GitHub App Setup
This is the recommended GitHub auth mode for teams sharing one Archon instance. It replaces the shared GITHUB_TOKEN PAT with a registered GitHub App so that:
- Bot comments appear as
archon[bot]with the App badge, not under an operator’s personal account. - Installation access tokens rotate automatically every ~1h (smaller blast radius if leaked).
- Webhooks centralise — one URL per App covers every installation.
- A team’s repos can span multiple GitHub orgs (or a mix of orgs and personal accounts) — Archon routes per-(owner, repo) to the right installation transparently.
Solo installs that only need the PAT model can ignore this page; see GitHub for the legacy setup.
When to use App mode vs. PAT mode
Section titled “When to use App mode vs. PAT mode”| Situation | Recommended mode |
|---|---|
| Solo developer, single GitHub account | PAT |
| Team of 2+ sharing one Archon instance | App |
| Repos across multiple orgs | App |
You want bot comments to attribute as <slug>[bot] with App badge | App |
| You want short-lived (1h) tokens instead of long-lived PAT | App |
Archon refuses to start with both modes configured. Pick one set of env vars.
Step 1: Register the GitHub App
Section titled “Step 1: Register the GitHub App”- Go to https://github.com/settings/apps/new (or
https://github.com/organizations/<org>/settings/apps/newfor an org-owned App). - Fill in:
- GitHub App name — e.g.
Archon Bot. The slug derived from this (visible in the App URL) is what you’ll later set asGITHUB_APP_SLUG. Self-filter compares against<slug>[bot]. - Homepage URL — your team’s Archon URL, e.g.
https://archon.example.com/. - Webhook URL —
https://archon.example.com/webhooks/github. - Webhook secret — same value as your
WEBHOOK_SECRETenv var.
- GitHub App name — e.g.
- Uncheck Active on the user authorisation callback URL — Archon doesn’t use OAuth in PR-B.
Step 2: Permissions (fine-grained)
Section titled “Step 2: Permissions (fine-grained)”Repository permissions:
| Permission | Access | Used for |
|---|---|---|
| Contents | Read | Cloning + reading repo metadata |
| Issues | Read & Write | createComment + listComments |
| Pull requests | Read & Write | pulls.get + comment posting |
| Metadata | Read | Mandatory (auto-included) |
Account permissions: none.
Step 3: Subscribe to webhook events
Section titled “Step 3: Subscribe to webhook events”Subscribe to:
- Issue comments
- Pull request review comments
- Pull request
- Issues (used for
closedcleanup)
Step 4: Generate a private key
Section titled “Step 4: Generate a private key”- After saving the App, scroll to Private keys and click Generate a private key.
- Save the downloaded
.pemfile in a location only readable by the Archon process — e.g./etc/archon/github-app.pem.
Step 5: Install the App
Section titled “Step 5: Install the App”Install the App on every org or personal account that holds repos your team operates on:
- From the App settings page, click Install App.
- Pick the org → grant access to all repos (or selected repos).
- Repeat for every org/account.
Multi-installation: Archon resolves
owner/repo → installation_idviaGET /repos/{owner}/{repo}/installationautomatically. No per-install config needed unless you’re a single-install team — seeGITHUB_APP_INSTALLATION_IDbelow.
Step 6: Configure Archon
Section titled “Step 6: Configure Archon”Add the following to your .env (or ~/.archon/.env):
GITHUB_APP_ID=123456 # numeric App ID, visible on the App settings pageGITHUB_APP_PRIVATE_KEY_PATH=/etc/archon/github-app.pemWEBHOOK_SECRET=<same value as on the GitHub side>
# Optional:# GITHUB_APP_SLUG=archon-bot # defaults to 'archon'; set this if you named your App# # differently. The bot's posted-comment login is `<slug>[bot]`.# GITHUB_APP_INSTALLATION_ID=98765 # skip the per-(owner, repo) installation lookup when you only# # have one installation. Saves one HTTP round trip per new# # repo after a restart.Inline private key (alternative)
Section titled “Inline private key (alternative)”If you can’t write a file (e.g. a managed PaaS), set the PEM contents inline:
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"Archon normalises the literal \n sequence in .env-quoted values into real newlines.
Unset the PAT
Section titled “Unset the PAT”Archon refuses to start if both modes are configured. Remove GITHUB_TOKEN from your env when switching to App mode.
Step 7: Restart Archon and verify
Section titled “Step 7: Restart Archon and verify”- Restart the server.
- Confirm the startup log shows
github.adapter_mode_appwith your slug. - Trigger a webhook from a repo where the App is installed (e.g. comment
@archon pingon an issue). - Confirm the bot’s reply appears as
<slug>[bot]with the App badge in the GitHub UI.
Operational notes
Section titled “Operational notes”Token rotation is invisible
Section titled “Token rotation is invisible”Installation tokens are valid for 1h. Archon caches each installation_id → token pair and refreshes ~5 minutes before expiry on the next access. No background timer; no leaked handles.
event.installation.id short-circuits the lookup
Section titled “event.installation.id short-circuits the lookup”Every webhook delivery from a GitHub App carries installation.id. Archon primes its owner/repo → installation_id cache from the payload, so the next outbound call to that repo skips the GET /repos/{owner}/{repo}/installation round trip.
401 forces a single retry
Section titled “401 forces a single retry”A 401 from any installation Octokit evicts the cached token and the call is retried once with a fresh token. Persistent 401s propagate as the original error.
Long-running workflow git push
Section titled “Long-running workflow git push”Workflows that span >1h need a fresh token to push from the cloned worktree. Archon installs a git credential helper at clone time (App mode only): the worktree’s .git/config points at ~/.archon/bin/git-credential-archon, which talks back to Archon’s internal endpoint for a fresh installation token on each operation.
Compiled binary builds: the credential helper is installed from
scripts/git-credential-archon.shin the source tree. Compiled binaries that don’t shipscripts/on disk silently skip the install — workflows up to 1h still succeed via the URL-embedded installation token and theGH_TOKENenv injection, but longer workflows will seegit pushfail with “Authentication failed” past the 1h mark. Track this when running App mode in a binary deployment.
Internal endpoint security — REQUIRED
Section titled “Internal endpoint security — REQUIRED”The credential-helper backend is exposed at POST /internal/git-credential and hands out live installation access tokens. It MUST NOT be reachable from outside the Archon host.
Archon enforces this at startup: with App mode active and the server bound to a non-loopback interface (e.g. 0.0.0.0), the process refuses to start and exits with github_app.internal_endpoint_public_bind_rejected. Two correct configurations:
- Recommended — bind Archon to
127.0.0.1(HOST=127.0.0.1) and put a reverse proxy in front. Configure the proxy to drop/internal/*paths. Operators who use systemd / docker for upstream routing also fall into this category. - Opt-in escape hatch —
ARCHON_ALLOW_INTERNAL_ON_PUBLIC_BIND=1combined withHOST=0.0.0.0(or unset). Use ONLY when your reverse proxy already drops/internal/*AND your deployment topology genuinely requires the upstream to bind non-loopback (e.g. a container network where loopback isn’t reachable from the proxy). Startup logsgithub_app.internal_endpoint_exposed_acknowledgedso the choice is auditable.
Example Caddy snippet that drops /internal/*:
example.com { @internal path /internal/* respond @internal 404 reverse_proxy 127.0.0.1:3090}Migration from PAT mode
Section titled “Migration from PAT mode”- Register the App and install on your orgs (Steps 1–5 above).
- Add
GITHUB_APP_*env vars (Step 6). - Remove
GITHUB_TOKENfrom your env (or comment it out). Archon refuses to start if both are set. - Restart Archon.
- Webhook URLs configured per-repo against the PAT-mode setup can stay or be removed — the App’s single webhook URL covers everything once it’s installed. New repos auto-join via App installation.
Troubleshooting
Section titled “Troubleshooting”AppPrivateKeyError: Provided value is not a valid PEM-encoded private key
Section titled “AppPrivateKeyError: Provided value is not a valid PEM-encoded private key”- Check the file content includes
-----BEGIN ... PRIVATE KEY-----and-----END ... PRIVATE KEY-----. - For inline keys, ensure the
.envvalue preserves newlines (either literal newlines in a multi-line value or the\nescape inside double quotes).
AppNotInstalledError: The Archon GitHub App is not installed on "<owner>"
Section titled “AppNotInstalledError: The Archon GitHub App is not installed on "<owner>"”- The App is not installed on that owner’s org/account. Use the install link in the error message to add it.
401 loop on GitHub API calls
Section titled “401 loop on GitHub API calls”Repeated 401s on outbound API calls (createComment, listComments, repos.get, pulls.get) point at installation / token issues, not webhook config. Walk through:
- Verify the App is installed on the target
ownerand has not been suspended or uninstalled. Visithttps://github.com/settings/installations(or the org equivalent) to confirm. - Verify the App’s permissions still include the scopes the operation needs (Contents:Read for clone; Issues:RW + Pull requests:RW for comments and reactions). Permission scope changes require operators to review and accept the new permissions on every installation; Archon will 401 until that’s done.
- Verify the private key in your env (
GITHUB_APP_PRIVATE_KEYor_PATH) matches the same App thatGITHUB_APP_IDpoints at. Mismatched key+ID is a common cause of “401 from JWT” errors at token-issuance time. - Verify
GITHUB_APP_INSTALLATION_ID(if set) still corresponds to a live installation — uninstall + reinstall assigns a new ID.
Webhook deliveries fail signature verification
Section titled “Webhook deliveries fail signature verification”A webhook-secret mismatch causes github.signature_mismatch / github.signature_length_mismatch errors at the POST /webhooks/github endpoint — distinct from outbound API 401s. If GitHub’s webhook delivery page shows red ❌ next to the delivery (rather than your bot just silently not responding), check:
WEBHOOK_SECRETin Archon’s env matches the value entered in the GitHub App’s webhook configuration page exactly.
Bot comments still appear under your personal account
Section titled “Bot comments still appear under your personal account”- You’re still in PAT mode. Check
process.env.GITHUB_TOKENis unset andGITHUB_APP_IDis set; restart.
Server refused to start: github_app.internal_endpoint_public_bind_rejected
Section titled “Server refused to start: github_app.internal_endpoint_public_bind_rejected”- App mode is active but the server is bound to a non-loopback interface. This is a fail-fast guard — the
/internal/git-credentialendpoint hands out live installation access tokens and would leak credentials to the network. Either setHOST=127.0.0.1(recommended), or, if your reverse proxy already drops/internal/*and you genuinely need a non-loopback bind, setARCHON_ALLOW_INTERNAL_ON_PUBLIC_BIND=1.
Server log shows github_app.internal_endpoint_exposed_acknowledged
Section titled “Server log shows github_app.internal_endpoint_exposed_acknowledged”- You set
ARCHON_ALLOW_INTERNAL_ON_PUBLIC_BIND=1. Double-check that your reverse proxy actually drops/internal/*— acurl https://your-archon/internal/git-credential -d '{"host":"github.com","path":"any/repo"}'from outside the host must return 404 or 403 from the proxy (NOT a token from Archon).