Self-hosted
The same stack we run hosted: Postgres, the web app, and the worker. Free forever, no seat limit. Budget under 15 minutes from clone to a reviewed test PR.
Quickstart
git clone https://github.com/postil-dev/postil
cd postil
cp .env.example .env
# fill in: GitHub App credentials, webhook secret, a sealing key,
# a session secret, and your LLM key. Each line in
# .env.example explains its variable.
docker compose up -d
docker compose exec web bun run db:migrateBoth web and worker validate their configuration at boot. A missing or malformed variable stops the process with the variable name, what it is for, and an example value — not a stack trace from the first request that happened to need it.
Pointing it at a model
OpenRouter (default)
POSTIL_API_BASE=https://openrouter.ai/api/v1
POSTIL_API_KEY=sk-or-v1-...
REVIEW_MODEL=deepseek/deepseek-v4-pro
REVIEW_MODEL_CASCADE=qwen/qwen3-coderAzure OpenAI
POSTIL_API_BASE=https://<resource>.openai.azure.com/openai/v1
POSTIL_API_KEY=<azure-api-key>
REVIEW_MODEL=<deployment-name>Ollama (local, no API key)
POSTIL_API_BASE=http://ollama:11434/v1
POSTIL_API_KEY=ollama # any non-empty value
REVIEW_MODEL=qwen3-coder:30bYes, Ollama actually works. The worker talks plain OpenAI-compatible chat completions, so anything that serves that API — vLLM, LiteLLM, TGI — works the same way.
postil doctor
Before opening a test PR, run the doctor inside the worker container. It checks the API base is reachable, the key is accepted, and the configured model responds:
docker compose exec worker postil doctor
endpoint http://ollama:11434/v1 ... ok (142ms)
auth key accepted ............ ok
model qwen3-coder:30b ......... ok (1.2s first token)Every failure mode prints the failing layer and a suggested fix. The documented anti-goal: a reviewer that silently falls back to a provider you did not configure.
GitHub App setup
- Create a GitHub App on your org with permissions
contents: read,pull_requests: write,checks: write,metadata: read, and thepull_request,installation, andinstallation_repositoriesevents. - Set the webhook URL to
https://your-host/api/webhooks/githuband generate a webhook secret (GITHUB_WEBHOOK_SECRET). - Download the App private key and set
GITHUB_APP_IDandGITHUB_APP_PRIVATE_KEY(PEM, base64 accepted). - Install the App on a test repository and open a PR.
Operations
/api/health— database ping, suitable for liveness probes./api/metrics— Prometheus text (queue depth, reviews by status, silence rate, watchdog kills), bearer-protected byMETRICS_TOKEN.- The worker's watchdog fails any review running longer than 10 minutes and completes its check-runs as failed, so a stuck review can never hold a PR hostage as eternally in-progress.
- The CLI binary is baked into the worker image at a pinned commit; upgrading the reviewer is an image upgrade, not a runtime download.