Give your AI agents and automations their own GitHub (App) identity.
Authenticate using GitHub Apps so every commit, PR, and action is attributed to the bot — not your personal account.
Run ghapp setup once and existing git and gh commands just work — business as usual
# Homebrew (macOS/Linux)
brew tap operator-kit/tap
brew install ghapp
# One-liner (Linux/macOS)
curl -sSL https://raw.githubusercontent.com/operator-kit/ghapp-cli/main/install.sh | bash
# PowerShell (Windows)
irm https://raw.githubusercontent.com/operator-kit/ghapp-cli/main/install.ps1 | iex
# Specific version
curl -sSL https://raw.githubusercontent.com/operator-kit/ghapp-cli/main/install.sh | GHAPP_VERSION=v0.1.0 bash
# From source (requires Go)
go install github.com/operator-kit/ghapp-cli/cmd/ghapp@latest
# Build from cloned repo
go build -o build/ ./cmd/ghapp/
go build -o build/ ./cmd/gh-wrapper/ # optional: gh wrapper binary
# Cross-compile
GOOS=linux GOARCH=arm64 go build -o build/ ./cmd/ghapp/You need three values for ghapp setup: App ID, Installation ID, and a private key (.pem file).
- Go to Settings → Developer settings → GitHub Apps → New GitHub App (docs)
- For org-owned apps: Org settings → Developer settings → GitHub Apps
- Name: anything unique (e.g.,
Mr Fox) - this will be used everywhere your App interacts. - Homepage URL: can be any URL (e.g., your org's GitHub page)
- Webhooks: uncheck Active (not needed) The other settings are not needed.
Select Repository permissions based on what you need:
| Use case | Required permissions |
|---|---|
git clone/push/pull |
Contents: Read & write |
gh PRs, issues, etc. |
Contents: Read & write, Pull requests: Read & write, Issues: Read & write, Metadata: Read |
Add more as needed.
gh pr listsilently returns empty without Issues read permission.
- Click Create GitHub App
- App ID is shown at the top of the app's settings page
- On the app settings page, scroll to Private keys → Generate a private key
- A
.pemfile downloads — store it securely (GitHub won't show it again)
- On the app settings page, click Install App in the left sidebar
- Select your account/org and choose which repos to grant access to
- After installing, the URL will be
github.com/settings/installations/12345678— the number at the end is your Installation ID
ghapp setup # prompts for App ID, Installation ID, key path
gh pr list # use `gh` as usual
git commit -m "Test" # sign commits using your AppIf you skipped auth configuration during setup, run
ghapp auth configureseparately.
ghapp config set --app-id 123 --installation-id 456 --private-key-path /path/to/key.pem
ghapp auth configure --gh-auth shell-function| Command | Description |
|---|---|
ghapp setup [--import-key] |
Interactive setup — App ID, Installation ID, PEM key |
ghapp config set [flags] |
Set config values non-interactively (see below) |
ghapp config get [key] |
Print config values (all or single key) |
ghapp config path |
Print config file location |
ghapp token [--no-cache] |
Print an installation token (cached; --no-cache forces fresh) |
ghapp auth configure [--gh-auth MODE] |
Configure git credential helper, gh CLI, and git identity |
ghapp auth status |
Show current auth configuration and diagnostics |
ghapp auth reset [--remove-key] |
Remove all auth config and restore previous git identity |
ghapp update |
Self-update to the latest release |
ghapp version |
Print version info |
| Flag | Description |
|---|---|
--app-id |
GitHub App ID |
--installation-id |
GitHub App installation ID |
--private-key-path |
Path to private key PEM file |
--import-key |
Import private key into OS keyring from PEM file (mutually exclusive with --private-key-path) |
Only flags that are explicitly provided are written — omitted fields are preserved from the existing config.
During auth configure, you're prompted to choose how gh CLI gets authenticated. You can also pass it non-interactively:
| Mode | Flag value | Description |
|---|---|---|
| Shell function | --gh-auth shell-function |
Wraps gh with a shell function that injects a fresh token per invocation |
| PATH binary | --gh-auth path-shim |
Installs ghapp-gh wrapper binary as gh earlier in PATH |
| None | --gh-auth none |
Only writes hosts.yml (token expires in ~1hr) |
ghapp registers itself as a git credential helper. On every git network operation, git calls ghapp credential-helper get, which returns a fresh installation token. Tokens are cached locally so repeated operations within the same session are fast.
auth configure also sets url."https://github.com/".insteadOf "git@github.com:" so that SSH-style URLs (git@github.com:org/repo.git) are transparently rewritten to HTTPS. This means copy-pasted SSH clone URLs and submodules that reference git@github.com:... will work automatically.
auth configure sets user.name and user.email to the app's bot account (e.g., myapp[bot]), so commits are attributed to the app with its icon on GitHub. If you already have a git identity, it will ask before overwriting and backs up your previous identity for auth reset.
auth configure injects a managed block into your shell's rc file that wraps gh with a function. Every gh invocation automatically gets a fresh token via GH_TOKEN:
# What gets added to your .bashrc / .zshrc (managed automatically):
eval "$(ghapp auth shell-init)"Under the hood, this defines a gh() function that calls ghapp token, sets GH_TOKEN, and delegates to the real gh. Tokens are cached so the overhead is negligible after the first call.
Supported shells: bash, zsh, fish, PowerShell
For environments without shell rc files (CI, containers, cron), the ghapp-gh wrapper binary can be placed on PATH as gh. It resolves the real gh, generates/caches a token, and execs with GH_TOKEN set. Falls through to plain gh if config is missing.
All token paths (credential helper, ghapp token, shell function, wrapper binary) share a local cache file. Tokens are reused until they're within 5 minutes of expiry, then automatically refreshed. This means:
ghapp tokenreturns in <10ms on cache hit- Back-to-back
gitoperations don't re-generate tokens - The shell function adds negligible latency to
ghcommands
Stored at ~/.config/ghapp/config.yaml:
app_id: 123456
installation_id: 789012
private_key_path: /path/to/key.pem
key_in_keyring: false
app_slug: myapp # cached after first auth configure
bot_user_id: 149130343 # cached after first auth configureEnvironment overrides: GHAPP_APP_ID, GHAPP_INSTALLATION_ID, GHAPP_PRIVATE_KEY_PATH, GHAPP_NO_UPDATE_CHECK=1 (disable daily update notice)
- File (default): path stored in config, key stays on disk
- OS Keyring (
--import-key): key imported into Windows Credential Manager / macOS Keychain / Linux Secret Service