Skip to content

Self-hosting the App

The App exists so that no issue text has to reach anyone else's infrastructure — including mine. The whole deployment is one container and a Postgres.

Create a GitHub App

Use apps/app/app-manifest.yml. The permissions it requests are the minimum Dispatch uses:

  • contents: read — to read .github/dispatch.yml, template overrides, and CODEOWNERS
  • issues: write, pull_requests: write
  • metadata: read

Notably not requested: contents: write (Dispatch never commits and never checks out pull request code), administration, or members.

Run it

bash
cp .env.example .env
openssl rand -base64 48   # DISPATCH_MASTER_KEY
docker compose -f apps/app/docker-compose.yml up -d
VariableNotes
DISPATCH_APP_IDFrom the App settings page
DISPATCH_PRIVATE_KEYThe generated .pem, contents inline
DISPATCH_WEBHOOK_SECRETMust match what you configured on the App
DISPATCH_MASTER_KEYEncrypts installation keys. Never commit it.
DATABASE_URLPostgres 16

Point the App's webhook URL at https://your-host/webhook.

How it handles load

The webhook path is: verify the signature over the raw bytes, enqueue, return 200. No model work happens inside the acknowledgement — GitHub's delivery timeout is ten seconds and the measured provider p99 is 2.1 s for a single request, before any file reads or label writes.

Two behaviours are deliberate:

  • 500 when the queue is down, so GitHub retries. A 200 would lose the event.
  • 200 for events we ignore, so GitHub stops retrying something we never want.

Installation keys

Each installation supplies its own provider key, so the database holds credentials that bill other people. They are encrypted with AES-256-GCM under DISPATCH_MASTER_KEY, which lives in the environment and never in Postgres — a database dump alone is not enough to spend a maintainer's budget.

GCM specifically for the authentication tag: tampered ciphertext would otherwise decrypt to garbage and then be sent to the provider as an API key.

Health

EndpointMeaning
GET /healthThe process is up
GET /readyDependencies are reachable; 503 when not

Publishing these docs

.github/workflows/docs.yml builds and publishes the site to GitHub Pages on any push to master that touches docs/, the workflow itself, or packages/config/src — the configuration reference is generated from the schema, so a schema change alters the published docs without anything under docs/ being edited.

Enable it once under Settings → Pages → Source → GitHub Actions, then run the workflow manually the first time (workflow_dispatch).

A project site is served from /<repo>/ rather than the root, so the workflow sets DOCS_BASE. Locally it defaults to /, which is why pnpm run docs:dev is unaffected.

MIT licensed.