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.

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:

  1. CLI flags
  2. Environment variables
  3. .postil.{yaml,yml,json}
  4. .coderabbit.yaml (compatibility read)
  5. 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 keyMaps to
Path filtersignore
Review profileminConfidence
enabledenabled

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

VariableMeaning
MODEL_API_KEYLLM API key; falls back to POSTIL_API_KEY, then OPENROUTER_API_KEY
POSTIL_API_BASEOpenAI-compatible or Anthropic API base URL (default https://openrouter.ai/api/v1)
POSTIL_API_FORMATopenai-compatible (default) or anthropic
POSTIL_ENDPOINT_AUTH_HEADEROptional private-gateway authentication header; set with its value
POSTIL_ENDPOINT_AUTH_VALUESecret value paired with the private-gateway authentication header
REVIEW_MODELModel id for BYOK, CLI, and self-hosted use
REVIEW_MODEL_CASCADEComma-separated fallback models for BYOK, CLI, and self-hosted use
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.