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.
Postil reads an existing .coderabbit.yaml automatically, with no setup step: a repo migrating from CodeRabbit gets a sensible translation of the overlapping settings on the first run, before anyone writes a line of Postil-specific config. This compatibility read covers CodeRabbit's config today only; see exactly what translates below.
Precedence
In the hosted GitHub App, each configuration artifact resolves separately: the target repository, the owner account's installed .github repository, organization form fallback, then built-in defaults. Shared owner configuration reads only .postil.yaml, .postil/guardrails.md, and .postil/content-policy.md from one default-branch commit. The App never reads an uninstalled public repository without authentication. Authorization or identity failures remove the shared snapshot and return no shared policy. A transient refresh may use the last successful snapshot only after the current call validates installation access and immutable repository identity.
Add or create <owner>/.github in the same GitHub App installation to use shared configuration. Public source files are public. Private and internal source files follow GitHub repository access, but policy text is not a secret: review output can reveal its effect.
Anyone who can merge to the owner .github repository can change review policy for every inheriting repository. Protect its default branch with CODEOWNERS, a ruleset, and required review.
From strongest to weakest:
- CLI flags
- Environment variables
.postil.{yaml,yml,json}.coderabbit.yaml(compatibility read)- Built-in defaults
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.
What translates from .coderabbit.yaml
Three settings, mapped directly:
| CodeRabbit key | Maps to |
|---|---|
| Path filters | ignore |
Review profile | minConfidence |
enabled | enabled |
Everything else in a .coderabbit.yaml (custom instructions, tool integrations, path-specific instructions beyond simple filters, and any CodeRabbit-only knob not listed above) is not read. Configs from Qodo, Macroscope, or other review tools are not translated at all; only .coderabbit.yaml gets a compatibility read today. This translation surface is small by design and expected to grow; it is not a claim of broad config compatibility across the category.
Full reference
Hosted inference ignores the entire model block and uses Postil's operator-managed roster. Repository model, fallback, and API settings apply only to BYOK organizations, the CLI, and self-hosted deployments.
# .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
findingPresentation: reviewComments # reviewComments (default) | checkAnnotations (GitHub only)
contentPolicy:
enabled: true # built-in prose/content baseline; false opts out
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: z-ai/glm-5.2
cascade: # fallbacks, tried in order on provider errors
- moonshotai/kimi-k2.7-code
- deepseek/deepseek-v4-flash
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; the gate never marks an unreviewed head as passing. 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/.Content policy
On by default, content policy reviews the human-readable prose in a diff (comments, docstrings, Markdown, and the PR title/description) against the built-in baseline. A .postil/content-policy.md file appends repo-specific rules to that baseline. Set contentPolicy.enabled: false to opt out entirely. Violations surface as contentPolicy findings. See content policy for the baseline, extensions, and opt-out behavior.
Environment variables
| Variable | Meaning |
|---|---|
MODEL_API_KEY | LLM API key; falls back to POSTIL_API_KEY, then OPENROUTER_API_KEY |
POSTIL_API_BASE | OpenAI-compatible or Anthropic API base URL (default https://openrouter.ai/api/v1) |
POSTIL_API_FORMAT | openai-compatible (default) or anthropic |
POSTIL_ENDPOINT_AUTH_HEADER | Optional private-gateway authentication header; set with its value |
POSTIL_ENDPOINT_AUTH_VALUE | Secret value paired with the private-gateway authentication header |
REVIEW_MODEL | Model id for BYOK, CLI, and self-hosted use |
REVIEW_MODEL_CASCADE | Comma-separated fallback models for BYOK, CLI, and self-hosted use |
GITHUB_TOKEN | Token for GitHub API access (--forge github; required for remote reviews) |
GITHUB_API_URL | GitHub API base URL for GitHub Enterprise Server (default https://api.github.com) |
GITLAB_TOKEN | Token for GitLab API access (--forge gitlab) |
GITLAB_API_URL | GitLab API base URL for self-managed instances (default https://gitlab.com/api/v4) |
BITBUCKET_TOKEN | Token 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_USER | Username for Bitbucket app-password (basic) auth; when set, BITBUCKET_TOKEN is used as the password |
BITBUCKET_API_URL | Bitbucket API base URL (default https://api.bitbucket.org/2.0) |
AZURE_DEVOPS_TOKEN | Personal access token for Azure DevOps (--forge azure) |
AZURE_DEVOPS_API_URL | Azure 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.