Postil

Configuration

Per-repo configuration lives in .postil.yaml (also .postil.yml or .postil.json). Every knob has a working default; an empty file is a valid file.

Precedence

From strongest to weakest:

  1. CLI flags
  2. Environment variables
  3. .postil.{yaml,yml,json}
  4. .coderabbit.yaml (compatibility read)
  5. Built-in defaults

Migrating from CodeRabbit costs nothing: leave the existing.coderabbit.yaml in place and Postil maps the overlapping settings (ignore patterns, severity thresholds, review toggles). Add a .postil.yaml later to use Postil-specific features; it wins wherever both define a value. Use postil config to print the resolved configuration with the provenance of every value.

Full reference

# .postil.yaml — every key, with defaults
enabled: true            # disable reviews for this repo entirely

ignore:                  # globs excluded from review
  - "vendor/**"
  - "**/*.lock"
  - "dist/**"

severityThreshold: info  # drop findings below: info | warn | error
minConfidence: 0.6       # drop findings below this confidence
maxFindings: 20          # hard cap per review; excess counted as suppressed

reviewer:
  tone: "direct, specific, no praise, no filler"  # free-form, passed to the model
  focus:                 # steer attention; free-form, passed to the model
    - correctness
    - security

review:
  onClean: skip          # skip = stay silent on clean PRs (default) | comment

gate:
  failOn: error          # the gate fails at/above this severity
  onError: block         # block (fail closed, default) | advisory
                         # advisory fails open on provider outages only

model:
  name: deepseek/deepseek-v4-pro
  cascade:               # fallbacks, tried in order on provider errors
    - qwen/qwen3-coder
  apiBase: https://openrouter.ai/api/v1
  consensus: 1           # run the first N of [name + cascade], keep only
                         # findings they agree on (must be >= 1)

Gate behavior on operational errors

gate.onError controls what happens when a review cannot complete — a provider outage, an exhausted key, model output that fails validation. The default, block, fails the gate: an unreviewed head is not a passing head. Setting it to advisory lets the gate pass on provider outages only, for repos that prefer fail-open over a blocked merge queue when the model endpoint is down. Findings the model did produce still gate normally.

Repo guardrails

Drop repo-specific merge rules in .postil/guardrails.md (plain Markdown, one rule per bullet or heading) and Postil injects them into the review prompt. A change that violates one is reported as a guardrail finding that quotes the rule it breaks — see the envelope schema.

# .postil/guardrails.md
- Every new API route must enforce org-scoped authorization.
- Database migrations must be reversible.
- No direct writes to the billing tables outside src/billing/.

Environment variables

VariableMeaning
POSTIL_API_KEYLLM API key; falls back to OPENROUTER_API_KEY
POSTIL_API_BASEOpenAI-compatible base URL (default https://openrouter.ai/api/v1)
REVIEW_MODELModel id (default deepseek/deepseek-v4-pro)
REVIEW_MODEL_CASCADEComma-separated fallback models
GITHUB_TOKENToken for GitHub API access (--forge github; required for remote reviews)
GITHUB_API_URLGitHub API base URL for GitHub Enterprise Server (default https://api.github.com)
GITLAB_TOKENToken for GitLab API access (--forge gitlab)
GITLAB_API_URLGitLab API base URL for self-managed instances (default https://gitlab.com/api/v4)
BITBUCKET_TOKENToken for Bitbucket API access (--forge bitbucket); sent as a bearer token, or as the password for basic auth when BITBUCKET_USER is also set
BITBUCKET_USERUsername for Bitbucket app-password (basic) auth; when set, BITBUCKET_TOKEN is used as the password
BITBUCKET_API_URLBitbucket API base URL (default https://api.bitbucket.org/2.0)
AZURE_DEVOPS_TOKENPersonal access token for Azure DevOps (--forge azure)
AZURE_DEVOPS_API_URLAzure DevOps API base URL (default https://dev.azure.com)

Each remote forge reads its own token plus an optional base-URL override for self-managed or enterprise instances. Only the variables for the forge you target are required. Unlike some self-hosted reviewers, Postil never silently substitutes a different provider: if the configured model cannot be reached with the configured credentials, the review fails with exit code 2 and a precise error. postil doctor runs the same checks standalone.

Trying changes safely

Do not tune thresholds against live PRs. Run postil plan with the candidate file to see what it would have changed on your recent reviews.