Setup

GitHub App setup

Octopus uses a GitHub App (not OAuth, not the gh CLI) to receive PR webhooks and post review comments as a bot identity. This page walks you through creating one. Estimated time: 5 minutes.

Why a GitHub App and not the gh CLI

Three things only the App model gives you, and they matter for a continuous-review tool:

  • Webhooks. GitHub pushes pull_request events to your server when PRs open or get new commits. The ghCLI has no webhook registration; you'd have to poll, which is slow and rate-limited.
  • Bot identity. Review comments appear as your-app[bot], distinct from any human reviewer. User-OAuth comments show up under whoever's token you used.
  • Per-repo scoped permissions. An org admin picks exactly which repos Octopus can see. Survives users leaving the org and key rotations.

For one-off octp review --pr <PR> from the CLI, a personal token works fine. The web app + auto-review-every-PR flow needs the App.

Step-by-step

Org owner / admin permission required on the GitHub side
  1. Open github.com/settings/apps/new (or for an org: Settings → Developer settings → GitHub Apps → New GitHub App).
  2. GitHub App name — pick anything; this is what shows up as the comment author. Examples: octopus-review for production, octopus-staging for staging. Names must be globally unique on GitHub.
  3. Homepage URL — your deployment URL, eg. https://octopus.example.com.
  4. Callback URL — leave blank.
  5. Setup URL (under Post installation) — set to https://your-domain/api/github/callback, and check Redirect on update. GitHub redirects users here after install, carrying the installation_id and signed state the callback needs to link the installation back to the org. Without it the install completes on github.com, the callback never fires, and reviews never start.
  6. Webhook — check Active. URL:
    https://your-domain/api/github/webhook
    Generate a random webhook secret (any high-entropy string, eg. openssl rand -hex 32) and paste it. Keep a copy — you'll need it for GITHUB_WEBHOOK_SECRET.
  7. Permissions — repository permissions:
    • Contents: Read-only (Octopus clones to index)
    • Pull requests: Read & write (post review comments)
    • Checks: Read & write (set the review status check)
    • Metadata: Read-only (automatic — leave default)
  8. Subscribe to events:
    • Pull request — main trigger
    • Pull request review — to react to human reviewer actions
  9. Where can this App be installed? — pick Any account if you want other orgs to install it; pick Only on this account for a private/self-hosted setup.
  10. Click Create GitHub App. You'll land on the App's settings page.
  11. Note the App ID at the top — this is your GITHUB_APP_ID.
  12. Note the slug from the URL bar (github.com/settings/apps/this-part) — this is your NEXT_PUBLIC_GITHUB_APP_SLUG.
  13. Scroll to Private keys → Generate a private key. A .pem file downloads. Open it; the contents are your GITHUB_APP_PRIVATE_KEY (paste with newlines preserved).

Env vars

Drop these into your .env:

GITHUB_APP_ID=123456
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
...lines from the .pem file...
-----END RSA PRIVATE KEY-----"
GITHUB_WEBHOOK_SECRET=<the secret you generated above>
NEXT_PUBLIC_GITHUB_APP_SLUG=<the slug from the App's URL>

Restart the server. The "Install GitHub App" button on /settings/integrations should now appear and link to https://github.com/apps/<slug>/installations/new.

Installing the App into your repos

From /settings/integrations click Install GitHub App. GitHub asks the user (must be a repo or org admin) to pick:

  • All repositories — every repo the org has, now and in the future. Simplest; fine when Octopus runs reviews for the whole org.
  • Only select repositories — explicit allowlist. Recommended for shared orgs where you only want Octopus on a subset.

After approval GitHub redirects back to /api/github/callback, Octopus stores the installation_id on your Organization row, and reviews start flowing on the next PR push.

Staging vs production — use separate Apps

Don't share one App across environments.Webhook URLs are fixed per-App, and you don't want production traffic hitting your staging server (or vice versa). Create one App per environment with a distinct webhook URL:

  • Production: octopus-review https://octopus.example.com/api/github/webhook
  • Staging: octopus-staging https://staging.example.com/api/github/webhook
  • Local dev: octopus-dev https://your-ngrok-tunnel.app/api/github/webhook

Each App has its own App ID, private key, slug, and webhook secret — set them as distinct env values per environment. Test orgs install the staging App; real orgs install production. Local development installs the dev App into a sandbox org (eg. a personal account with one test repo).

Troubleshooting

Webhook deliveries failing

Open your App's Advanced tab on GitHub → Recent deliveries. Failed deliveries show the response status. Common causes:

  • 401 invalid signature — webhook secret mismatch. The secret you set on the App must equal the env var GITHUB_WEBHOOK_SECRET.
  • 404— wrong webhook URL on the App, or your server isn't reachable from GitHub's IPs.
  • 500 — check your server logs. Often a database not being reachable.

Reviews aren't posting

Webhooks are arriving but no review comment shows up. Check:

  • App has Pull requests: Read & write — not just read.
  • App is actually installed on the repo (it's possible for an org to install for "selected repos" that excludes the one you're testing).
  • The review worker is running — if jobs are never picked up, set ENABLE_REVIEW_WORKERS=true on the review-engine process.

"GitHub App not configured" on /settings/integrations

NEXT_PUBLIC_GITHUB_APP_SLUGisn't set. Restart the server after editing .env — Next.js inlines NEXT_PUBLIC_*vars at build time, so a hot reload isn't enough.