Repo Config Reference
Per-repo configuration lives in .no-mistakes.yaml at the root of your repository.
agent: codex
commands: prepare: "go mod download" lint: "golangci-lint run ./..." # Targeted local validation only - not a full-repo CI-parity suite. test: "go test ./internal/cli -run '^TestDoctor' -count=1" format: "gofmt -w ."
ignore_patterns: - "*.generated.go" - "vendor/**"
# Optional documentation ownership policy, read only from the trusted default branch.document: instructions: | docs/ owns detailed product guidance; README.md owns the introduction.
# Optional review settings, read only from the trusted default branch:# whether the reviewer may ask you questions while it works (off by default),# and extra guidance scoped to the paths a change touches.review: conversation: true path_instructions: - path: "internal/scm/**" instructions: | Any URL or error string that can carry credentials must go through internal/safeurl. - path: "docs/**" instructions: | Prose changes only. Do not request test coverage.
# For orchestration repos whose project instructions would misidentify gate agents.# Read only from the trusted default branch. Defaults to false.disable_project_settings: true
# Positive declaration that this repository intentionally has no CI.# Read only from the trusted default branch. Defaults to false (CI expected).# no_ci: true
# Optional PR settings.# base_branch is read from the trusted default branch.# template, publish_intent, and appendix are trusted publication policy.# See pr.appendix below for presentation modes and inheritance.# title_format is a repository convention and is read from this branch.pr: base_branch: develop # template: .github/pull_request_template.md # publish_intent: false # appendix: collapsed # full | collapsed | minimal # title_format: "{{.Branch}}: {{.Title}}"
auto_fix: rebase: 3 review: 3 test: 3 document: 3 lint: 5 ci: 3
# Read only from the trusted default branch: each rerun is another workflow run,# and revalidation decides whether a CI repair may ship without review.ci: rerun_transient: 0 revalidate_repairs: false review_bot_comments: on_failure # or: always rebase_behind: false carry_review_on_replay: false required_reviews: [] # opt in with: [coderabbit]
# How a base branch that moved under your branch is integrated.# Read only from the trusted default branch.rebase: strategy: rebase # or: merge
commit: fix_message: "chore(no-mistakes-{{.Step}}): {{.Summary}}" # branch_pattern: '([A-Z]+-[0-9]+)' # To use the captured identifier in the subject: # fix_message: "{{.Branch}}: {{.Summary}}" # trailers: # - "Assisted-by: no-mistakes:{{.Agent}}:{{.Model}}"
intent: enabled: true threshold: 0.2 slack_days: 3 disabled_readers: []
test: # Product startup and live-validation runbook, read only from the trusted default branch. instructions: | Start the app with `make dev`, then drive the checkout flow in a browser. evidence: store_in_repo: true attach_media: true dir: .no-mistakes/evidence branch: no-mistakes/evidence commit_message: "no-mistakes: evidence for {{.Branch}} (run {{.RunID}})"
providers: github: draft_pull_requests: false gitlab: draft_pull_requests: false bitbucket: draft_pull_requests: false azuredevops: draft_pull_requests: false origin: draft_pull_requests: falseFields
agent
Override the default agent for this repo and its setup-wizard suggestions.
| Type | string or string[] |
| Values | Same as global agent |
| Default | Inherits from global config |
The global agent reference owns agent names, ACP alias defaults, auto resolution, availability, and fallback behavior.
You can also set an ordered fallback list:
agent: [codex, grok]This per-repo agent value, including every fallback entry, is still read from the trusted default-branch .no-mistakes.yaml unless allow_repo_commands is enabled there.
allow_repo_commands
Opt in to honoring the code-executing selection fields (commands.{prepare,test,lint,format} and agent) from a contributor’s pushed branch instead of the trusted default-branch copy.
| Type | bool |
| Default | false |
This field is itself read only from the trusted default-branch copy of .no-mistakes.yaml, never from the pushed SHA, so a contributor cannot self-enable it by setting it on a feature branch. By default the daemon reads commands and agent from your default branch (e.g. origin/main) so a pushed SHA cannot inject shell or pick the launched agent on the daemon host. The PR-target exception is documented under pr.base_branch; pr.template, pr.publish_intent, pr.appendix, and the other trusted-only fields listed above do not follow this opt-in. Leave this false for any repo that accepts contributions. Set it to true only for a single-developer environment where you trust every branch you push (for example, a personal repo gated by your own daemon).
disable_project_settings
Suppress project-level agent settings and instructions for every gate-agent start and resumed session.
| Type | bool |
| Default | false |
This opt-in is intended for agent-orchestration repositories whose AGENTS.md, CLAUDE.md, or harness-specific project settings would give a validation agent an operator identity and authority that it must not adopt.
When enabled, no-mistakes suppresses the target checkout’s project settings for every agent-driven gate step while preserving user-level agent configuration.
Codex, Claude, Pi, and the acp:omp target (Oh My Pi over ACP) are the currently verified agents: Codex receives project_doc_max_bytes=0 and --ignore-rules, Claude loads only its user setting source, and Pi runs with --no-context-files (preserving a pinned --no-context-files or -nc spelling).
acp:omp is launched as omp acp with a generated --config overlay that disables every omp context-file discovery provider (native, claude, codex, gemini, opencode, github, agents, agents-md, claude-md) and mnemopi memory, plus --no-rules, --no-skills, and --no-extensions. omp has no CLI flag to disable context files, and a CLI --config overlay is the highest settings layer, so the target repository’s own .omp/config.yml cannot re-enable a provider the overlay disabled. Memory is disabled because a gate turn that reads the repo’s AGENTS.md while reviewing could otherwise retain it and a later turn recall it around the provider suppression. Only the default acp:omp launch qualifies: an acp_registry_overrides entry for omp is an opaque custom command and fails closed. Other ACP targets (acp:<target>), including the cursor and devin aliases, remain unverified and are refused; Devin CLI loads the target repository’s AGENTS.md, CLAUDE.md, and editor rule files with no verified off-switch.
Grok 1.0.5 still discovers native project instructions and .grok project surfaces, so it is not a verified agent for this boundary. A configuration that resolves Grok while this option is enabled therefore fails closed before launch.
The setting applies to both new and resumed sessions.
The gate fails before launching an agent if any resolved agent or fallback lacks a verified suppression mechanism.
It also fails if agent_args_override defeats suppression, such as a nonzero Codex project_doc_max_bytes or Claude setting sources that include project or local.
When this option is false, missing, or null, all agents retain their existing project-setting behavior.
This field is honored only from the trusted default-branch copy of .no-mistakes.yaml, regardless of allow_repo_commands.
A pushed branch cannot enable it or disable a trusted opt-in.
If the trusted commit or its present config file cannot be read and parsed, the run aborts rather than guessing that the option is disabled.
no_ci
Declare that this repository intentionally has no CI.
| Type | bool |
| Default | false |
When true and the forge reports zero checks on the PR head, the CI monitor treats that empty result as all-checks-passed and axi run may return outcome: checks-passed. The monitor log names the declaration (no_ci: true) so the positive evidence stays inspectable rather than silently equating every empty forge response with green.
Absence of this field means CI is expected. A zero-length check result then stays not-ready for as long as the forge reports no checks - elapsed time, grace periods, workflow-file presence or absence, prior check history, and branch names are not evidence.
If checks still appear on a declared no-CI repository, their actual states are processed normally. The declaration never waives a registered pending or failing check.
This field is honored only from the trusted default-branch copy of .no-mistakes.yaml, regardless of allow_repo_commands.
A feature branch cannot self-declare no_ci: true to bypass checks, and cannot clear a trusted declaration either.
pr.base_branch
Select the branch that newly created pull requests target.
| Type | string |
| Default | The repository’s forge default branch |
| Trust | Trusted default branch, unless allow_repo_commands: true is explicitly enabled there |
Use this when the repository’s integration branch differs from its forge default branch, for example develop instead of main.
The configured branch is used for PR creation and pipeline integration and change scoping; the Pipeline Steps scope rules describe which steps use it and how the recorded per-run override takes precedence.
When unset and without a per-run override, no-mistakes targets the repository’s forge default branch.
PR lookup matches an existing PR by branch alone, never filtered by base, so a pr.base_branch change after a PR was opened updates that PR instead of opening a duplicate against the new base.
A per-run --base-branch override is different: if the run’s already-open PR targets another branch, the PR step retargets that PR (GitHub, GitLab, Gitea, Cursor Origin, and provider plugins that advertise set_pr_base_branch) so title, body, and CI follow the requested integration branch. A discovered PR that is not the run’s persisted identity, or a provider that cannot retarget, fails closed rather than moving another review object. See PR.
Once a PR exists, its actual forge base branch is authoritative over pr.base_branch for the CI step’s merge-conflict auto-fix and base-branch tip monitoring, protecting a resumed run from a configuration change made after the PR was created.
Because this setting controls where a PR lands, a pushed branch cannot redirect its own PR target by changing pr.base_branch.
It is read from the trusted default-branch copy regardless of allow_repo_commands by default.
The established explicit allow_repo_commands: true opt-in also applies to this setting for repositories that intentionally trust their pushed configuration, including a repository with no trusted default-branch copy of this file at all.
An empty value is valid and means “fall back to the forge default branch”; a non-empty value that Git would reject as a branch name fails config parsing closed, naming pr.base_branch in the error.
pr.template
Use a repository Markdown template for the public narrative, followed by no-mistakes’ protected evidence appendix. Supported on GitHub, GitLab, Gitea, Forgejo, Azure DevOps, Bitbucket Cloud, Cursor Origin, and provider plugins, using each backend’s authenticated raw-description transport (origin pr view --json for Cursor Origin; for a plugin, the raw body its pr view subcommand returns). Forgejo requires forgejo-axi with the raw api command (contract verified against 1.3.0); an older CLI without it fails rather than using a preview. Self-hosted instances use the existing provider routing.
| Type | string (literal repository-relative path) |
| Default | Empty (existing generated narrative) |
| Trust | Path from this trusted setting or a matching machine-local repository_overrides entry; bytes always from the pinned trusted default-branch commit, even under allow_repo_commands: true |
pr: template: .github/pull_request_template.md publish_intent: false # Optional; otherwise original Intent is still published. appendix: collapsed # Optional; see pr.appendix below.For example, commit this template and the configuration to the default branch:
## Overview
<!-- Explain the final change for a later reader. -->
## Rollout
<!-- Describe rollout and rollback considerations. -->
- [ ] Maintainer approves rolloutOn a new or empty PR, the agent makes a best effort to follow template instructions and fill applicable sections from the final branch delta. Only top-level ATX # headings outside fenced examples are structurally required, with their trimmed text and order retained. Lower-level headings (##–######) and task lines are editable: the model may remove inapplicable sections/options, select supported choices, and fill checkbox rationale placeholders. It is instructed not to invent behavior/tests or falsely claim human signoff; human approval boxes must not be marked complete. Subordinate completion and factual correctness are best effort, not mechanically guaranteed. No fixed What Changed heading is imposed. This is ordinary Markdown, not a variable/loop/plugin language, and there is no implicit template discovery. Template headings such as Testing remain author narrative; the generated appendix follows that narrative. pr.appendix chooses whether its recorded evidence is expanded, folded, or reduced to a risk line and the attestation. Extra evidence headings are intentional in the default full mode: this does not satisfy a policy requiring only the template’s headings or bytes. collapsed and minimal keep the template as the visible body.
The path is read as a literal Git tree entry, never through the pushed worktree filesystem. Absolute/Windows paths, traversal, ref expressions, symlinks, submodules, missing/unreadable files, empty/non-UTF-8/NUL-containing content, and files over 16 KiB fail rather than silently replacing the template with a generic summary. Raw no-mistakes ownership/attestation markers are reserved. Invalid agent output, missing/changed/reordered required H1 headings, and agent failure also fail template drafting rather than using the ordinary fallback. Templates without H1 headings have no structural heading requirements; they are not malformed for that reason. Matching retains the existing ordered-subsequence contract: extra headings are allowed. The structural guard is not a full Markdown parser, a visibility/uniqueness proof, or a template policy engine; it does not enforce subordinate sections, checkbox states, or placeholder completion.
Author-preserving regeneration
A templated PR contains one delimited, integrity-checked generated appendix. Later runs preserve live author text before and after it, including human checkbox choices and explicit issue-closing lines, and refresh only that appendix. They do not re-fill the narrative. An author’s title is also preserved unless pr.title_format is configured; that explicit repository convention redrafts the bare title and applies the format on every managed update. Changing or removing pr.template does not regenerate an already owned narrative; edit it on the PR when it needs updating. The full intent remains available to reviewers. Removing the generated Intent section is controlled separately below.
Ownership is never inferred from a heading’s name. An existing author-only body can be adopted without model rewriting. Legacy descriptions containing an unowned attestation require explicit author reconciliation before template mode can adopt them: separate/remove their obsolete generated evidence while retaining the desired author text and closing references, then retry. Do not manufacture ownership markers by hand. An edited appendix, missing/duplicate/malformed markers, or a competing attestation fails rather than risking discarded author content. Put author additions outside the generated appendix. The integrity guard detects accidental edits; it is not authentication or a cryptographic signature by no-mistakes.
Updates read the live raw body before deciding which publication path applies. Missing/null/malformed content is not treated as an empty description. Without pr.title_format, body-only updates omit title and draft flags rather than reading and resending a possibly stale author title. Template updates re-read immediately before writing and verify the body afterward; observed pre-write edits are retried from the latest body up to three times. Write/readback errors and body divergence fail visibly, without replaying a possibly applied write. This is not atomic compare-and-swap: an edit in the provider’s final read/write gap can still be lost. New template creations are read back too; a created PR identity may be recorded even if verification then fails, so it remains discoverable for recovery.
If the complete author text, closing references, and evidence selected by pr.appendix cannot fit the publication budget, the step fails instead of truncating them. Evidence rendering retains its existing artifact presentation limits; this adds no body-level eviction to make a template fit. Pre-push and CI-repair restamping update the appendix’s integrity guard together with its head-bound attestation, without changing author text.
Unconfigured, unowned descriptions retain ordinary narrative/fallback/size behavior; existing owned bodies retain author-safe updates even after the setting is removed. Providers without a raw content contract reject configured templates.
Provider caveats: Azure DevOps’ 4,000-character budget (and any non-zero max_pr_body_chars declared by a provider plugin) is checked conservatively in UTF-16 units before every owned write, including pre-push/CI-repair restamping. Oversize fails; ordinary truncation must never cut an ownership marker or author evidence. The 16 KiB source-template allowance does not imply a filled description will fit. Bitbucket keeps Markdown evidence (no HTML folds) and carries the exact existing attestation in a visible text code fence; ownership comments may also be visible. Ordinary, unowned Bitbucket descriptions still omit attestation. These are presentation differences, not a new attestation protocol. The bundled enforcement action remains GitHub-specific; no native enforcement workflow for other providers is installed.
Provider contract tests use fake CLI/API responses and local HTTP fixtures, not live server acceptance. Exact server byte roundtrips, rendering, consistency and instance-specific limits remain unverified; a differing body readback fails visibly rather than being normalized into success.
pr.publish_intent
Control publication of the generated Intent section, independently of intent extraction and review input.
| Type | bool |
| Default | true (missing or null also preserves the default) |
| Trust | Trusted default branch only, regardless of allow_repo_commands; the caller-side counterpart is the global intent.publish_intent default and the per-run axi run --no-publish-intent flag |
false suppresses that section in ordinary drafting, fallback output, and template appendices. It works without pr.template and does not otherwise enable template mode. It never removes full intent from review or PR-drafting context, changes evidence/attestation policy, or erases author-written sections named Intent. Unconfigured defaults remain unchanged.
A contributor can keep the section off for their own runs without touching this repository policy: axi run --no-publish-intent records a tighten-only omission on the run, and an operator can set the global intent.publish_intent: false default. Both compose with this field and can only reduce publication: the trusted repository policy is the ceiling, and a caller can never publish intent on a repository whose trusted config disabled it. Neither signal changes what review, test, document, lint, or CI auto-fix prompts receive. The caller-side omission goes one step further than this repository policy: the PR-drafting turns (ordinary narrative, title-only fallback, and repository-template narrative) receive no intent text at all and draft from the diff and commit messages only, so no paraphrase of the withheld intent can reach the public PR. The intent is withheld, never scanned for: there is no output filter.
This is not a privacy filter: generated narrative and other evidence can still contain sensitive information, and LLM drafting is not a confidentiality guarantee. No caller-written public-body override is introduced by this setting.
pr.appendix
Choose how much of the generated Risk, Testing, and Pipeline tail is visible after the narrative. Intent publication stays under pr.publish_intent.
| Type | string |
| Values | full, collapsed, minimal |
| Default | Missing or empty inherits machine-local defaults; see appendix precedence |
| Trust | Trusted default branch only, regardless of allow_repo_commands; the pushed branch cannot choose this mode |
full is today’s body: ## Risk Assessment, ## Testing, and ## Pipeline follow the narrative, in that order.
collapsed folds those three sections into one closed Validation details block. The narrative, and the Intent section when it is published, stay outside the block. Within the body limit, opening the block shows the same recorded evidence full would have published. If an ordinary body exceeds the limit, Testing is dropped before pipeline history is shortened; the attestation is retained. Bitbucket Cloud escapes raw HTML, so collapsed stays on the full appendix there instead of printing the details tags as text.
minimal keeps a single risk line (the recorded level and rationale, on one line) and the pipeline attestation. Testing logs, pipeline round history, and the Risk and Pipeline headings are omitted. The attestation marker stays in its host-specific form: an HTML comment on GitHub, GitLab, Gitea, Forgejo, Azure, Cursor Origin, and provider plugins, and a visible text fence on an owned Bitbucket description. Ordinary unowned Bitbucket descriptions still omit the comment.
An unrecognized value fails config parsing closed. Body size limits and truncation still apply in every mode. A templated body that cannot fit still fails instead of dropping author text. The marker remains the one require-no-mistakes binds to the PR head.
pr: appendix: minimalpr.title_format
Configure the title shape no-mistakes applies to newly created and updated pull requests.
| Type | string template |
| Default | Unset, which preserves conventional commit titles |
| Trust | Pushed branch, like other non-executing repository conventions |
The template supports literal text and {{.Branch}} and {{.Title}} placeholders.
{{.Branch}} is the normalized branch identifier resolved by commit.branch_pattern or a matching machine-local repository_overrides entry; its capture can be transformed by commit.branch_replacement from global config or that entry.
{{.Title}} is the bare concise title text returned by the PR agent, or update pull request when ordinary drafting uses its deterministic fallback.
For example, title_format: "{{.Branch}}: {{.Title}}" can render PROJ-123: add widget from a matching branch.
The format is applied deterministically after drafting; its literal text is not sent to the agent as an instruction.
The format is validated when configuration loads.
It must be valid UTF-8, contain only the two documented placeholders and literal text, and contain no control or unsafe Unicode format characters.
The template source is limited to 1,024 bytes and 16 placeholders, and the rendered title must be non-empty and no more than 4,096 bytes.
Providers can impose lower publication limits. GitLab titles are checked at its publication boundary and may contain at most 255 Unicode characters, including a preserved or requested draft marker.
If a format requires {{.Branch}} but the branch pattern finds no identifier, PR publication fails safely instead of publishing a malformed title.
When this setting is omitted, no-mistakes keeps its default conventional commit title behavior, including release type guidance and title tightening.
For a machine-local title convention that does not require repository configuration, see global repository_overrides.
commands.prepare
Optional dependency-preparation command for isolated run worktrees. Run via the platform shell - sh -c on POSIX, cmd.exe /c on Windows.
| Type | string |
| Default | Empty (no preparation command) |
When set, no-mistakes runs this command before the first configured Test, Lint, or Format command that the pipeline reaches, including machine-local additional Test or Lint checks.
By default, it is a lazy command hook rather than an additional pipeline step: when no configured command needs it and test.prepare is false, commands.prepare alone does nothing.
Trusted test.prepare: true instead triggers it eagerly before agent-only Test while leaving commands.test unset.
A successful result is shared by all later configured commands in that isolated worktree, including after daemon recovery.
The dependent step log records the preparation command, output, and elapsed preparation time.
A non-zero exit or launch failure fails that step before its command runs.
Use this for deterministic dependency materialization such as npm ci --prefer-offline. The run worktree starts with tracked files only, so ignored dependency directories such as node_modules are otherwise absent. no-mistakes keeps ignored files produced by preparation, and keeps any submodule it checks out at the commit the superproject records, while removing its tracked, ordinary untracked, and nested-repository mutations before continuing; a submodule commit the command moved to is reset to the recorded commit. Earlier pending tracked and ordinary untracked pipeline changes are restored exactly, so preparation can run before a later configured command without admitting setup artifacts into a fix commit.
Like every commands.* value, commands.prepare comes from the trusted default-branch configuration unless that trusted copy explicitly enables allow_repo_commands: true. no-mistakes never auto-detects an install command from the pushed branch.
commands.test
Explicit targeted local test command. Run via the platform shell - sh -c on POSIX, cmd.exe /c on Windows.
| Type | string |
| Default | Empty (agent derives and drives targeted end-user scenarios) |
commands.test is local targeted validation of the change and requested intent, not a CI-parity repository-wide regression command.
Broad regression belongs in remote CI and remains mandatory before a PR is ready; do not put a complete-suite walk here just to mirror CI.
no-mistakes does not guess whether an arbitrary shell string is “too broad” - the contract is documented and dogfooded, not enforced with language- or filename-specific heuristics.
When set, the test step runs this exact command first as the baseline and checks the exit code.
Machine-local repository_overrides.commands can add checks and lower its scheduling priority without replacing this command.
Whether the baseline passes, fails, or is absent, the agent then derives targeted end-user scenarios and drives the product itself under the same targeted-validation contract.
A non-zero exit parks the Test step. Approving that gate records an explicit override on the step and on the PR attestation; the require-no-mistakes check treats that as non-compliant unless test.allow_approve_over_failure is set.
commands.lint
Explicit lint command. Run via the platform shell - sh -c on POSIX, cmd.exe /c on Windows.
| Type | string |
| Default | Empty (agent auto-detects) |
When set, the lint step runs this exact command and checks the exit code. When empty, the agent-driven lint duty is folded into the document step’s combined housekeeping pass: one agent invocation covers both documentation and lint, and the lint step consumes that result, reporting lint-category findings with the same gate semantics (blocking findings park for a decision). Neither responsibility is skipped: when the document step has nothing to run against (or its structured output cannot be trusted), the lint step runs its own agent pass as before.
commands.format
Formatter command run before the push step commits agent fixes.
| Type | string |
| Default | Empty (no separate push-step formatter) |
This does not prevent empty commands.lint from detecting and running formatters during the combined housekeeping pass, or during the lint step when that pass cannot provide a result.
document.instructions
Repository-specific documentation ownership policy for the document step.
| Type | string (multiline) |
| Default | Empty (built-in placement policy only) |
The document step always applies a built-in placement policy: every fact has exactly one authoritative owner document, stale duplicates are removed or reduced to pointers instead of synchronized, no new documentation surfaces are created merely to close perceived gaps, and incident lessons live as invariants near their owner (with a pointer to the regression test), never as AGENTS.md postmortems. Its agent prompt treats AGENTS.md and CLAUDE.md as memory files: it may correct or remove factually wrong content, but must not add content because something is missing, create absent files, or restructure or expand them. This is prompt guidance, not a file guard.
document.instructions states this repository’s ownership map or extra placement rules (for example, which file owns which class of facts).
It augments or clarifies the built-in policy; it cannot disable documentation integrity, and it cannot turn the memory files into an automated documentation surface - instructions that encourage additions to AGENTS.md or CLAUDE.md do not take effect over the built-in correction-only rule.
Like commands.* and agent, this field steers gate behavior, so it is honored only from the trusted default-branch copy of .no-mistakes.yaml: a contributor’s pushed branch cannot weaken the documentation rules that gate its own review.
An operator can add their own policy for this repository through a machine-local repository_overrides entry; it is rendered as a separate, labeled section and never replaces this field.
review.conversation
Whether the reviewer may ask you questions while it reviews, instead of turning every undecidable point into a finding you answer with a verdict. The Review conversation concept page owns the protocol, the state machine, and what is persisted.
| Type | boolean |
| Default | false |
| Trust | Read only from the trusted default branch |
review: conversation: trueOpting in. Commit that block to your default branch (the same copy the daemon reads commands and agent from). It takes effect on the next run of every branch in the repository; a branch cannot opt itself in or out, in either direction. A contributor must not be able to make their own review park for a human answer, and once you have asked for the conversation a pushed branch must not be able to decline it.
On, the review step gains a question channel. The reviewer emits each larger question the moment it has one, keeps reviewing while it is open, and re-reads answers at its own checkpoints. A pass that ends with an unanswered question parks with one ask-user warning per question; you answer each with no-mistakes axi answer, and once none are open the reviewer finishes its pass with your answers - resuming that same session when session_reuse is on, cold otherwise. Answers are recorded per branch, reach every later cold reviewer as settled, and are published in the PR body.
Off (the default), the review step is the monologue it has always been: the reviewer is told nothing about a channel, no conversation files are written, no question findings are produced, and the PR body grows no conversation group. A repository that never opted in cannot have a conversation on disk, so for it every review turn also runs session-free and no-mistakes axi answer refuses and names this setting. A question asked while the setting was on stays answerable if you turn it off mid-run - see Turning the setting off does not strand a question already asked. Upgrading no-mistakes never starts a conversation under a repository that did not ask for one.
The trade-off is latency against precision. A question costs the run a park - tens of minutes to hours of wall clock, waiting on you - and buys a review that decided the point instead of handing you a finding to rule on. Repositories whose changes rarely turn on product intent will not get much for that wait; repositories where the reviewer regularly cannot tell deliberate from accidental will.
review.agent_timeout
A shorter stall budget for each Review-step agent invocation in this repository, so small, low-risk changes can be bounded more tightly than the machine-wide default.
| Type | string (Go duration, positive) |
| Default | unset (the global review_agent_timeout applies) |
| Trust | Read only from the trusted default branch |
review: agent_timeout: "10m"Precedence. The effective budget is the smaller of this value and the global review_agent_timeout. A repository can only tighten the machine policy: a longer value is accepted but has no effect, and the global limit stays in force. An unset key keeps the global limit, so the setting is opt-in.
Trust boundary. Commit it to your default branch, the same copy the daemon reads review.conversation and review.path_instructions from. A pushed branch cannot set, change, or remove it, because the timeout gates that branch’s own review. A value that is not a positive duration fails the config closed, on the pushed copy too, so an invalid block is caught before it merges.
What it does not change. It sets the same per-invocation budget as review_agent_timeout: the reviewer, the fixer, and each fresh rereviewer get it independently, and an expiry fails the Review step exactly as before. It never skips Review or counts a timeout as a pass. It does not change review_agent_working_timeout, which stays global and still bounds how long a still-working invocation may continue past the budget. Because a tightened budget is a configured timeout, a Review invocation cut by it is not retried by agent_crash_retries, as with a configured global value. Only Review is affected: Document, Lint, and Test keep the crash retry their own, unchanged budgets earn. It is not an aggregate limit on the whole Review step.
review.path_instructions
Extra review guidance, scoped to the paths a change actually touches.
| Type | object[] with path (string) and instructions (string, multiline) |
| Default | Empty (built-in review instructions only) |
Use this for house rules that only apply to part of the tree, for example a redaction rule for the code that builds remote URLs, or a note that a documentation directory needs no test coverage:
review: path_instructions: - path: "internal/scm/**" instructions: | Any URL or error string that can carry credentials must go through internal/safeurl. - path: "docs/**" instructions: | Prose changes only. Do not request test coverage.Each matched rule reaches the reviewer with the scope it was selected for, so a rule scoped to one directory can never read as a repository-wide instruction:
path: docs/**matched files: docs/notes.mdinstructions:Prose changes only. Do not request test coverage.Matching
path uses the same matcher and syntax as ignore_patterns, including the rule that * never crosses a /, so **/*.go covers a single directory level rather than every Go file.
The review step appends only the blocks whose path matches at least one changed file, in the order they appear in the file.
Two entries with the same path and the same instructions are injected once. The same instruction text under two different path values is injected once per path, because each block states its own scope. Two entries with the same path and different instructions are both injected.
Matching runs against the full changed-file list and is deliberately not filtered by ignore_patterns: that field is read from the pushed branch, so filtering here would let a contributor drop one of your rules from the review of their own branch.
Blocks augment the built-in review instructions; they cannot disable them, and a finding the reviewer raises from a block goes through the same severity and action model as any other finding.
With nothing configured, or nothing matching the change, the review prompt is exactly what it would be without this setting.
The step log names the rules it applied and the rules that matched nothing, so a rule that never fires is visible in no-mistakes axi logs --step review.
Limits and validation
instructions is prompt text, so merge-conflict markers (<<<<<<<, =======, >>>>>>>) are removed from it and runs of whitespace are collapsed, exactly as for document.instructions. Write rules without those tokens; a value that would be left empty once they are removed is rejected rather than silently dropped.
At most 32 entries are allowed, and the assembled prompt sections may not exceed 16,384 bytes, because the injected text shares the review prompt’s budget and an oversized prompt fails the agent invocation outright.
The size is measured on what is actually injected: each section’s heading, and for every entry its labels, its path, its instructions, and a 192-byte allowance for its matched-file list. A block whose matched-file list would exceed that allowance is truncated with a +N more suffix, so the measured limit holds for any diff.
A missing path or instructions value, an instructions value that renders empty, a path that is not a valid glob, or a config over either limit fails when the config is parsed, so the run aborts before an agent starts instead of silently dropping guidance.
These checks run on whichever copy of the file is parsed, including the pushed branch’s. A pushed branch’s blocks are ignored when the review prompt is built (see Trust below), but an invalid block on that branch still fails its own run, so a broken rule surfaces before it merges and becomes the trusted copy.
Trust
Like document.instructions, this field steers gate behavior, so it is honored only from the trusted default-branch copy of .no-mistakes.yaml, regardless of allow_repo_commands: a value present only on a pushed branch is ignored, so a contributor cannot inject instructions into the review that gates them.
Machine-local rules
The operator gating a repository can add rules from their own global config, globally with review.path_instructions or for this repository with a repository_overrides entry.
Those rules render in their own labeled sections before this field’s, never replace it, and count toward the limits above together with it.
gates
Extra repository-declared checks that run inside the pipeline, in addition to the core steps.
| Type | object[] with name (string), after (string), and command (string) |
| Default | Empty (core pipeline only) |
Use this for a validation pass that does not fit an existing step - a mutation-testing budget, a complexity ceiling, an architectural fitness function - so it runs before the branch is pushed rather than only in remote CI:
gates: - name: mutation-budget after: test command: "make mutation"A gate runs its command in the run worktree through the platform shell, sh -c on POSIX or cmd.exe /c on Windows. A command that ignores NO_MISTAKES_FINDINGS_FILE passes on exit code 0 and reports one error finding on a non-zero exit, as before. Agent gates are not supported. An entry with instructions fails config parsing so it cannot be mistaken for a command gate.
Structured findings
Before each command execution, including a re-check after a fix, no-mistakes creates an empty file in a private temporary directory outside the worktree and supplies its absolute path as NO_MISTAKES_FINDINGS_FILE. The command may write this JSON to that file:
{ "findings": [ { "id": "mutation-budget-low", "severity": "error", "file": "src/parser.go", "line": 42, "description": "Mutation score is below the configured budget", "action": "ask-user" } ]}This uses the existing pipeline finding shape. Each finding needs a non-empty id, unique within the file and stable across executions, a severity of error, warning, or info, and a non-empty description. IDs cannot contain commas or reuse IDs reserved by the pipeline. file and line are optional; a supplied line cannot be negative. action is optional and defaults to ask-user; accepted values are auto-fix, ask-user, and no-op. Enum values use these exact spellings. The report and each finding reject fields outside this schema.
| Command exit | File | Gate verdict |
|---|---|---|
| 0 | Empty | Pass, unchanged |
| Non-zero | Empty | Park with the existing exit-code error finding and command output |
| 0 | Valid report | Any error parks the gate; warnings and info attach without failing the command verdict |
| Non-zero | Valid report | Park with the reported findings and command output |
| Any | Invalid or over-cap report | Park with one error finding explaining the problem, action ask-user |
A report is limited to 1 MiB and 500 findings. The final encoded findings payload, including the command and log summary, must fit the portion of half the existing 1 MiB IPC frame left after the run’s persisted findings and the refusal space reserved for every configured gate. The other half remains available for the envelope and other run state. JSON escaping can make the effective file cap lower than 1 MiB. A payload that cannot fit parks with one error finding naming its encoded size and the remaining transport budget, action ask-user; findings are never truncated to make a report fit. This fixed-size transport refusal omits the command summary, whose complete output remains in the gate’s step log. Malformed JSON, a missing findings array, missing required fields, duplicate or unusable IDs, invalid severities or actions, unknown fields, and an unreadable or non-regular file also fail closed. An empty array is a valid report; an empty file opts out. The temporary directory is removed after the command is checked.
Findings remain available in axi status, axi logs, and the TUI, and their IDs can be selected with axi respond --action fix --findings <ids>. Executor approval policy is unchanged: a zero-exit report containing only warnings or info still goes through the same approval rules as other steps. Warnings park, and an omitted action defaults to ask-user. A gate never starts an automatic repair, even when a reported finding says auto-fix.
Placement
after names the core step the gate runs immediately after. Valid anchors are rebase, review, test, document, and lint.
The delivery tail (push, pr, ci) cannot be anchored: a gate that ran after push would be validating a branch the world can already see. intent cannot be anchored either, because it establishes the acceptance criteria the later gates check against.
Gates are inserted into the run’s step sequence and never replace, reorder, or remove a core step. Two gates sharing an anchor run in the order they appear in the file. A gate shares its anchor’s step order, so a restart that resets from the anchor resets the gate with it.
A run resolves this list once when it starts. Adding or removing a gate on the default branch therefore applies to later runs and never retargets a run already in flight. Daemon crash recovery owns how the recorded list is restored after a restart.
Failure
A failing gate parks by default. Trusted auto_fix.gates.<name> can authorize bounded repairs of auto-fix-eligible findings. Any ask-user finding still parks the whole gate. The current exit-code-only failure is ask-user, so the budget has no effect until the structured findings follow-up supplies auto-fix-eligible findings.
Answering that decision with fix is that authorization: the gate then runs a fix turn against the reported findings and the command that must exit 0 without reporting error findings, then re-runs its check. The next verdict describes the repaired worktree. Answering approve accepts the change as it stands.
Each gate keeps its own step log under the step name gate.<anchor>.<name>, so a gate declared as name: mutation-budget with after: test is read with no-mistakes axi logs --step gate.test.mutation-budget.
Because a gate can only add a verdict, a repository that configures gates makes a pass mean more than the core pipeline, never less. There is no way to switch a core step off here; to skip one for a single run, use the per-run --skip instead.
A gate also cannot be pre-skipped: neither --skip nor the no-mistakes.skip= push option accepts a gate step name, so a pushed branch cannot switch off the maintainer’s extra check before its own run starts. Answering a parked gate with skip stays available, like any other gate, as a decision made at the park.
Limits and validation
Leading and trailing whitespace is removed from name. The remaining name must be lowercase letters, digits, and inner hyphens, at most 40 characters, unique within the file, and not a core step name.
At most 16 gates are allowed. Each entry must provide a non-empty command. The parser rejects instructions with an error that states agent gates are not supported.
A malformed entry fails when the config is parsed, so the run aborts before any gate starts. These checks run on whichever copy of the file is parsed, including the pushed branch’s, so a broken gate surfaces before it merges and becomes the trusted copy.
Trust
A gate executes shell on the daemon host, so it is honored only from the trusted default-branch copy of .no-mistakes.yaml, regardless of allow_repo_commands.
That opt-in deliberately does not extend here. It covers a pushed branch re-running its own suite through commands.*; a gate instead defines what validating the branch means, so a contributor must not be able to declare, retarget, or delete the check that clears them.
What that boundary protects is the gate’s declaration, not the repository files its command invokes. The command runs in the run worktree, which is checked out at the pushed head, so a contributor who can edit the script or make target it calls can still change what it checks. commands.test and commands.lint have the same property. When a contributor must not be able to weaken a gate, point command at logic that does not live in the repository.
Command process lifetime
All configured commands.* entries and repository gate commands are scoped to their step.
After no-mistakes starts one of these commands, it terminates any remaining child processes from that command when the command exits, fails, or the step is cancelled.
On Windows, cancellation first sends CTRL_BREAK to the command’s isolated process group and allows up to three seconds for cleanup before forcibly terminating the job. A command that owns external resources should handle its runtime’s break signal and exit after cleanup; in Node.js, register a process.on('SIGBREAK', handler) listener. If the command does not exit before the window closes, expect forced termination.
Do not rely on a configured command to leave a background server or watcher running after it returns; keep that service inside the command lifetime or start it outside no-mistakes.
ignore_patterns
Paths to exclude from review and documentation checks.
| Type | string[] |
| Default | Empty (no ignores) |
Pattern matching rules. review.path_instructions uses the same matcher, so there is one path syntax to learn:
| Pattern | Rule |
|---|---|
*.generated.go | No slash - matches by basename, at any depth |
vendor/** | Ends with /** - matches that directory and everything under it |
some/path/file.go | Contains a slash - full path glob against the whole path |
**/*.go | Also a full path glob, so only one directory level - internal/main.go, not internal/scm/github/github.go |
* never crosses a /, on every platform, so **/*.go is not “every Go file”; it behaves as a single-segment wildcard. Use *.go to match by extension at any depth, or internal/** to cover a subtree.
protected_paths
Opt-in paths that automatic commits must leave for an operator to resolve.
| Type | string[] |
| Default | Empty (no protected paths) |
| Trust | Trusted default branch only, regardless of allow_repo_commands |
protected_paths: - "package-lock.json" - "*.lock" - ".github/**"Patterns use the same syntax as ignore_patterns. Empty or malformed rules fail config loading. Commit this setting to the default branch to enable it; a pushed branch cannot add, remove, or replace the trusted policy for its own run.
Before staging an automatic Review, Test, Document, Lint, or CI repair, an operator-authorized repository gate repair, or a Push leftover commit, the pipeline checks the index and worktree for dirty protected paths. This includes staged and unstaged modifications, deletions, both ends of renames, and individual untracked files inside new directories. A match refuses the entire commit and parks the step at an operator approval gate naming the path and rule. The index and all working files stay as they were; nothing is restored, unstaged, discarded, or partially committed. The Push check also covers formatter changes and residue from earlier steps. Daemon & Worktrees owns retention across terminal cleanup and crash recovery.
A protected-path refusal always requires an explicit response, including under AXI --yes and TUI yolo mode. CI does not retry its fixer, and automatic gate reconciliation cannot clear the refusal, even if the PR closes. Approval is rejected because it would skip unfinished work: inspect and resolve the reported edit, then use no-mistakes axi respond --action fix to retry the step, including its commit and publication. Deliberate skip and abort behavior is unchanged.
For CI, that explicit fix finishes the retained repair before normal monitoring can report checks-passed, even if forge checks turned green while parked or the response selects only an added finding. It uses the existing repair revalidation policy, including mandatory revalidation from Review for a rebased conflict repair, and the existing publication guards. If the retained repair cannot finish, the refusal remains available for another explicit fix response.
This is a staging guard, not an agent filesystem sandbox or a check on semantic intent. It does not inspect changes already committed by the author or an agent, and it does not infer whether an unprotected edit belongs to a finding. With an empty list, automatic staging keeps its existing behavior. ignore_patterns only filters checks and does not prevent staging.
auto_fix
Override auto-fix attempt limits for specific steps. Core-step fields not set here inherit from global config. Gate budgets are repository-only and default to 0.
| Type | object |
| Field | Type | Default |
|---|---|---|
auto_fix.rebase | int | Inherits from global (default 3) |
auto_fix.review | int | Inherits from global (default 0) |
auto_fix.test | int | Inherits from global (default 3) |
auto_fix.document | int | Inherits from global (default 3) |
auto_fix.lint | int | Inherits from global (default 3) |
auto_fix.ci | int | Inherits from global (default 3) |
auto_fix.gates.<name> | Non-negative int | 0, trusted default branch only |
Set to 0 to disable the follow-up auto-fix loop for a step (findings require manual approval).
The document step attempts documentation fixes during its initial pass, so unresolved documentation findings pause for approval instead of using an automatic follow-up loop.
For empty commands.lint, the document step’s combined housekeeping pass also attempts safe lint fixes, and the lint step consumes its result; unresolved blocking lint findings pause for approval instead of starting another automatic fix loop.
auto_fix.ci covers the CI step’s CI failure and merge-conflict auto-fix attempts.
The CI step reports each settled failure as an auto-fix finding and the shared auto-fix loop drives its fix rounds, exactly as for review; ask-user findings (a supported review bot’s red check, a provider-attributed check no rerun will replace) never consume an attempt.
For an extra gate, use its declared name, not its full step name:
auto_fix: gates: mutation-budget: 2This budget is honored only from the trusted default-branch config, even with allow_repo_commands: true. Global auto_fix.gates entries are rejected, including empty maps. Unknown gate names, negative budgets, and non-integer values are rejected.
With a positive budget, a gate with at least one auto-fix finding and no ask-user findings uses the shared fix loop. The fixer receives the findings and decision history, commits repairs like Test, and re-runs the gate. It parks when the budget is exhausted or a repair returns as many or more findings than the round it answered. Changing finding IDs without reducing the count is not progress. Manual fix, approve, and skip responses remain unchanged. This budget does not require non-waivable command success under unattended AXI.
Legacy alias: auto_fix.babysit.
ci.rerun_transient
How many times the CI step may re-run a single provider-attributed check before that check reaches an approval gate. This covers cancellations on supported providers and, when the value is positive, opts GitHub into detecting jobs that failed before any repository step ran.
| Type | int |
| Default | 0 |
| Range | 0 to 5; values outside it are clamped |
| Trust | Read only from the trusted default branch |
Every rerun this budget authorizes is another provider-side workflow run billed to the repository, so the value is read only from the trusted default-branch copy of this file, exactly like document.instructions and disable_project_settings.
A pushed branch cannot raise its own rerun budget.
The default is 0 because a cancelled conclusion does not identify its cause: the same value covers the provider aborting its own infrastructure, a maintainer stopping a runaway or unsafe job, and repository concurrency with cancel-in-progress.
Rerunning on that ambiguity can restart work someone deliberately stopped, so raise this only for a repository whose cancellations are known to be provider-side.
At 0, no-mistakes makes no extra provider call to classify a GitHub setup failure, so that failure keeps the earlier CI failure and auto-fix behavior.
With no trusted copy of this file, the operator’s own ci.rerun_transient applies, then the built-in default.
A value set here always wins over the global one, so the maintainer of the repository has the last word on how many workflow runs their project is billed for.
With a positive budget, a rerun is requested when the provider attributes the outcome to itself rather than to the job, which is true in two cases:
- The provider reported the outcome as
cancelled, the one terminal conclusion it attributes to itself rather than to the job. - On GitHub, the job failed before any repository step ran because its setup/action-resolution phase failed, for example during a “Failed to resolve action download info” / HTTP 503 outage while downloading the actions the job uses. This is read structurally from the job’s own setup-step conclusion, never from log text, so it cannot mask a real failure: a genuine test or lint failure cleared setup and failed a later step. When the detected setup failure persists past the budget, it reaches the same approval gate as an unresolved cancellation rather than the fix agent. An unreadable or unmatched job fails closed and remains an ordinary failure.
The remaining outcomes are the job’s own verdict on the commit and are never re-run:
failure,error,action_required, andstartup_failure(after any repository step ran) are the job’s verdict, so they escalate on the first failure with no added latency. One GitHub outcome is not a verdict at all: a workflow run that concludedaction_requiredwithout running a single job is the forge holding a first-time contributor’s workflows until a maintainer approves them. Nothing ran, so there is nothing to escalate and no rerun that could clear it; that run is reported as pending, and the monitor names the hold and keeps waiting for the maintainer instead of spending auto-fix rounds on work that never executed. A held run never defers another check’s genuine failure: that failure escalates as it would without the hold, and the hold itself still produces no finding. The distinction is read from the run’s own job list, so a run that concludedaction_requiredafter executing jobs keeps escalating as before. Only a job list the provider actually returned, and returned empty, is evidence of the hold: a read that fails, and a response carrying no job list at all, are unreadable job data and fail closed to the same unchanged behavior.timed_outmeans the job exceeded its owntimeout-minutes, which is usually the branch’s own code hanging. Re-running it burns another full timeout window reproducing the same failure, so it is treated as a genuine failure and is not opt-in.staleis already treated as skipped rather than failed, so it never reaches this decision.- An outcome no-mistakes recognizes as none of the above never earns a rerun either.
A single genuine job failure, or a merge conflict, suppresses the rerun for that poll: the fix agent is needed regardless, and no rerun can clear a merge conflict.
The budget is per check per run and is spent when the rerun is requested, so a provider that refuses the request cannot be retried in a loop. Check names are not unique on a pull request, so same-named checks share one budget.
A rerun request returns as soon as the provider accepts it, while the new attempt replaces the provider-attributed check in the status rollup a moment later.
A poll that still reads the exact completion the rerun was requested for has observed nothing new, so the monitor waits for a bounded couple of polls rather than escalating a check it never actually re-ran.
A provider that accepts a rerun and never publishes it cannot stall the run past that.
Once the provider publishes a conclusive replacement, no-mistakes durably stops treating that rerun as outstanding while preserving the spent budget; if the exact watched head is then green, the monitor reports checks-passed normally.
A provider-attributed check that no rerun is going to replace pauses the step for user approval when it is the only remaining issue, so the pull request never looks green.
That includes a check that came back cancelled after its rerun and a detected GitHub setup failure that persisted after its budget.
At the default budget of 0, once the budget is spent, or on a provider with no rerun API, cancellation itself reaches this gate because the provider has published its conclusion and will not publish another one on its own.
The check is reported as an ask-user finding, so it does not enter the auto_fix.ci loop and never consumes an auto-fix attempt: it is not a verdict on the code, so there is nothing for the fix agent to repair and no reason to let it edit code the provider never tested.
Answering that gate with fix is still honored: the fix round you asked for repairs the findings you selected, and a selected transient finding names its check to the agent alongside any other issue.
Reruns are skipped when:
- The provider has no rerun API (only GitHub implements one today; GitLab, Forgejo, Bitbucket Cloud, Azure DevOps, Gitea, Cursor Origin, and provider plugins reach the approval gate without a rerun).
- The check’s details link names nothing the provider can re-run, for example a third-party status pointing at an external dashboard, or a link under a workflow run that names no job the API accepts. A link naming one job re-runs that job; a cancelled check naming only the workflow run re-runs the whole workflow, while other run-only links re-run failed jobs; an unrecognized link is widened into neither.
- The published branch head no longer equals the commit the run delivered. That case terminates with the expected and observed commits instead: re-running checks against a different head would certify a revision this run never produced. See pipeline steps: CI.
ci.required_reviews
An optional list of external reviewers that must finish before the CI monitor reports checks-passed.
The default is []; the only supported reviewer profile is coderabbit on GitHub.com.
Enable it in the trusted default branch’s .no-mistakes.yaml:
ci: required_reviews: [coderabbit]The whole ci block is trusted-only, even with allow_repo_commands: true.
A pushed branch cannot disable the requirement or enable it for itself.
A repository value overrides the operator’s global list; an explicit [] disables the requirement, while omission inherits the global value.
Unknown or duplicate reviewer names fail configuration loading.
CodeRabbit must already be installed for the repository by its administrator.
no-mistakes uses the existing GitHub CLI authentication for read-only observation and adds no CodeRabbit credentials or installation flow.
When the list is empty, no additional completion checks are made.
Existing CI and Greptile behavior stays unchanged. CodeRabbit is recognized as a review bot only when this list names coderabbit: otherwise an installed CodeRabbit’s check is an ordinary CI check and its review-thread comments are never findings, exactly as if no-mistakes had no CodeRabbit support. Once opted in, failed CodeRabbit checks use the same review-bot findings path as Greptile.
Completion requires the latest CodeRabbit check run from GitHub.com app ID 347564, a nonempty immutable check-run ID, status: completed, conclusion: success, and a head_sha matching the exact current PR head.
The adapter pins the check query to that SHA and verifies the live PR head before and after discovery.
Names, slugs, formal approvals, and review/comment bodies cannot establish completion.
Unresolved CodeRabbit review-thread comments from the verified GitHub bot account become bounded ask-user findings in the existing review model, even when the required completion check succeeded.
Every page of review threads and of each unresolved thread’s comments is read; a response that cannot prove it is complete (missing comment nodes, an invalid page cursor, or an unreadable later page) leaves the review unverified rather than clean.
Their bodies are untrusted evidence and cannot instruct the fix agent; the CI step reference owns that shared handling.
GitHub’s check runs API owns the check fields; CodeRabbit documents its GitHub check.
Missing and in-progress reviews keep readiness false and wait under the existing ci_timeout policy.
Skipped, stale, neutral, failed, cancelled, timed-out, unknown terminal outcomes, and rate-limited reviews remain incomplete and produce ask-user findings without spending an automatic repair round.
Unreadable, malformed, partial, or mismatched evidence cannot make the monitor ready.
no_ci: true does not waive an external-review requirement.
Approval is refused while any required review is incomplete, has unresolved findings, or cannot be verified at the current PR head (including a transient provider or network error). The refusal names the reason and the CI gate stays parked, so the run is not lost; approve again once the review completes, or use fix, skip, or abort. Once required reviews are complete, approval of unrelated CI failures retains the existing explicit-override behavior.
CodeRabbit documents a passing check titled Review rate limited when no review ran.
That name or output title vetoes completion even alongside another successful check at the same head.
A separately named rate-limit check remains blocking while GitHub still returns it among the latest checks at that head; no-mistakes does not guess from comment text that the limit has cleared.
The monitor never posts review commands, requests a paid review, or retries a review on the provider’s behalf.
Strict gating on GitLab and other forges is unsupported and parks with an explicit unsupported finding when enabled. GitLab approvals and discussion activity are not a documented CodeRabbit completion signal. GitHub Enterprise Server is also unsupported because its separately installed app has a different immutable identity. Leave this setting empty on those platforms to retain normal CI behavior.
This gates no-mistakes readiness, not direct forge merges or merge-queue synthetic commits. The merge caller must recheck readiness for the current head and bind its merge request to that SHA. Configure forge protection separately if merges outside no-mistakes must be prevented.
ci.revalidate_repairs
Whether every CI repair must re-pass the pipeline before it is published, or only the ones whose continuity with the reviewed head cannot be proven.
| Type | bool |
| Default | false |
| Trust | Read only from the trusted default branch |
ci: revalidate_repairs: trueOne rule decides how every CI repair is delivered, on every CI-fix path - automatic and manual, CI failure and merge conflict alike:
A repair is published without revalidating only when its continuity with the reviewed, published head can be proven. When that continuity cannot be proven, the repair revalidates from Review.
Continuity is proven when the repaired head is the run’s durably review-approved commit or a descendant of it. That is the same fact the Push step’s publication guard enforces, so the decision to publish and the guard that permits the push can never disagree.
revalidate_repairs sets the intent, identically on every path:
false(default) asks to publish when it is safe to. A repair that builds on the reviewed head - the ordinary case, where the fix agent adds a commit - is committed and published immediately through the same guarded path the Push step uses (review-approved-head continuity, that step’s own remote-safety decision, remote verification, and the durable push binding all still apply), and the CI monitor keeps watching the same run for the new head. One repair costs one agent round.trueasks for revalidation outright: every repair is kept local, the run’s review approval is revoked, and validation restarts at Review so the repaired head re-passes Review, Test, Document, and Lint before Push republishes it.
CI repair publication uses the same settlement order as Push. The CI step reference owns the publication and retry behavior.
Merge-conflict repairs always revalidate, under either setting. They are not carved out - they simply always land in the cannot-be-proven half. A conflict repair rebases, so the repaired head is never a descendant of the reviewed head; resolving a conflict changes the commit’s patch-id; and no content-based guard can separate “rebased and resolved” from “dropped the work”. Revalidating is what keeps that safe: the rewritten head is not published until Review has approved it, so the reviewed commits stay on the remote in the meantime. The opt-in ci.carry_review_on_replay narrows only where that revalidation starts, and only for a rebase it can prove replayed the reviewed commits unchanged with no conflict: such a repair still revalidates, from Test.
Provenance is deliberately not accepted as a substitute for that proof. In the reproduction this rule exists for, the repair that deleted a reviewed commit was authored by no-mistakes’ own CI repair agent: it reset to the rebase base, left a clean tree, and the pipeline reported success while the remote lost the work. Who wrote a repair says nothing about what it did to the reviewed commits.
The tradeoff true buys is cost against an unreviewed repair:
false (default) | true | |
|---|---|---|
| Ordinary repair that builds on the reviewed head | published immediately, one agent round | revalidated: one agent round plus a full Review, Test, Document, Lint, Push, PR pass |
| Merge-conflict repair | revalidated | revalidated |
| Ordinary repair is reviewed before it reaches the PR | no | yes |
| Steps that re-run when a repair revalidates | Review onward; Intent and Rebase do not | same |
| Run identity | unchanged; a restart is a same-run rewind | same |
Turn it on where even an ordinary unreviewed CI repair is unacceptable.
Registered review-bot checks now park as ask-user findings instead of entering an automatic repair, but that classification does not make every red check’s proposed fix trustworthy: an unregistered external check or a repair the user explicitly requests can still ask the fix agent to change product behavior.
Before review-bot checks were classified structurally, firstmate#3250 demonstrated the risk: a CI repair responding to bot feedback made a --changed test run serial by default, contradicting the change’s stated intent; the restarted Review caught it and reversed it. Without revalidation that repair would have shipped.
That is the safety this option buys, and the reason it is offered rather than removed.
This value is read only from the trusted default-branch copy of this file, like ci.rerun_transient and disable_project_settings.
A pushed branch cannot turn a maintainer’s revalidation requirement off for its own repairs, and cannot turn it on either.
A value set here always wins over the operator’s own ci.revalidate_repairs, in both directions: true here enables revalidation even when the global value is false, and an explicit false here opts out even when the global value is true.
With no trusted copy of this file, the operator’s global value applies, then the built-in default of false.
ci.review_bot_comments
When the CI step reads a supported review bot’s unresolved review comments. See the CI step reference for supported bots and identity verification.
| Type | string (on_failure or always) |
| Default | on_failure |
| Trust | Read only from the trusted default branch |
ci: review_bot_comments: alwayson_failure(default) reads them only when the bot’s own check failed. A green bot check stays green unless a separateci.required_reviewsrequirement applies.alwaysalso reads them when the bot’s check completed green on the current head, or has not registered on it yet once every other check is green, since the bot’s threads from an earlier head can still be unresolved. Each unresolved comment becomes the sameask-userfinding a red bot check produces, anchored to the comment’s file and line, so the step parks for a decision instead of reportingchecks-passed. A green bot with nothing unresolved is still green.
A review bot can conclude its check success while leaving an unresolved comment. The comment most likely to be missed that way is the one on the pipeline’s own CI repair commit, which no human has reviewed yet.
The CI step reference owns provider-specific comment sources, bot identity verification, and prompt-safety handling.
Under always:
- Comments are read only once every check on the current head has completed green, the bot’s included when it has registered one, so a review still being posted is not raced. A bot that has not registered a check on the head yet has its comments read too, since its threads from an earlier head can still be unresolved. A head with no checks at all under trusted
no_ci: truehas them read the same way before it is reported ready. Only unresolved threads count, and the same per-gate bound applies as for a red check. A GitLab note counts only when it is resolvable, unresolved, not a system note, and authored by a registered bot, so an ordinary merge request comment is never a finding. - The findings never spend an
auto_fix.ciattempt. A human can select comments for a fix round or skip; approval is subject toci.required_reviews. - When approval is allowed, approving over comments records the CI step as passed with an override naming the comments, never as a clean pass.
- A comment list that cannot be read is not treated as empty:
checks-passedis withheld, and a read that keeps failing parks for a decision. - Each green poll costs one more provider read for the comments.
Forges that cannot supply review comments are unaffected by either value. Because only GitHub can attribute a check to a review bot, on_failure reads nothing on GitLab: a GitLab run needs always for the bot’s unresolved discussions to become findings.
This value is read only from the trusted default-branch copy of this file, like the rest of the ci block: a pushed branch cannot silence a green bot’s comments on itself, and cannot opt itself in either.
A value set here wins over the operator’s own ci.review_bot_comments.
ci.rebase_behind
Whether the CI monitor rebases a green GitHub PR that GitHub reports mergeStateStatus: BEHIND.
| Type | bool |
| Default | false |
| Trust | Read only from the trusted default branch |
ci: rebase_behind: trueGitHub reports BEHIND only when the base branch requires branches to be up to date before merging, so the merge button stays disabled even though every check is green and nothing conflicts.
A PR that is behind a base without that rule reads CLEAN, merges as it is, and is unaffected by this key.
false(default) keeps the monitor’s behavior from before the key existed: the PR reportschecks-passedand waits for a human to bring it up to date.truewithholdschecks-passedfrom such a PR. Once a second poll still sees it green andBEHINDat the same base tip, it takes the merge-conflict repair: rebase onto the PR base, revalidate from Review, and re-push through Push. A base that moves between those polls keeps the monitor waiting instead.
Off by default because every rebase rewrites the head, so it always revalidates from Review (see ci.revalidate_repairs) and costs another full Review, Test, Document, and Lint pass each time the base advances.
Each one also spends an auto_fix.ci attempt.
Other providers never report BEHIND, so the key only has an effect on GitHub.
This value is read only from the trusted default-branch copy of this file, like the rest of the ci block: a pushed branch cannot opt itself into the extra passes, or out of them.
A value set here wins over the operator’s own ci.rebase_behind in both directions.
ci.carry_review_on_replay
Whether a CI rebase repair that only replayed the reviewed commits keeps the run’s Review approval and restarts at Test instead of Review.
| Type | bool |
| Default | false |
| Trust | Read only from the trusted default branch |
ci: carry_review_on_replay: trueA merge-conflict repair, or a ci.rebase_behind rebase, rewrites every branch commit, so continuity with the reviewed head cannot be shown by ancestry and the repair revalidates from Review. Often the rebase changed nothing the reviewer looked at: the base moved, the branch’s own commits replayed on top of it unchanged, and the full Review pass only re-approves the same diff.
false(default) keeps that behavior exactly: every rebase repair revalidates from Review.truefirst checks whether the repaired head is a pure replay of the reviewed head onto the base tip the repair targeted. If it is, the run’s review approval moves to the replayed head and validation restarts at Test: Test, Document, Lint, Push, PR, and CI all run again against the new base, and only Review is not repeated. If it is not, the repair revalidates from Review as it would with the key off.
A rebase repair is a pure replay only when every part of this holds:
- The reviewed commits (from their merge base with the target up to the reviewed head) and the repaired commits (from the target up to the repaired head) are both single linear chains with no merge commits, of the same length, and the repaired chain sits directly on the target.
- Each reviewed commit, replayed with
git merge-treeonto the repaired commit’s parent, applies with no conflict and produces exactly the tree the repaired commit records. A conflict, even one an agent then resolved, and any edit, addition, or removal made during the repair fails this. - Each repaired commit is patch-identical to the reviewed commit it replaced, by
git patch-id --verbatimover the full binary diff, so whitespace, file-mode, and binary changes all count as changes.
Any git error while checking also counts as not a pure replay. The check is deliberately narrower than “the rebase did not stop”: a base change that lands within a few lines of a reviewed hunk changes that hunk’s context, so its patch-id changes and the repair revalidates from Review, even though Git applied it cleanly.
The carry applies only when the repaired head’s own commits are exactly the reviewed commits. If any commit was added after Review approved the head (a Test, Document, or Lint auto-fix commit, or an earlier published CI repair), the repair is not a pure replay of the reviewed commits and Review re-runs as it does with the key off.
The key has no effect when:
ci.revalidate_repairsistrue, which keeps meaning that every repair re-passes Review.- The run has a repository gate anchored
after: review. Restarting at Test would skip that gate for the new head, so the repair revalidates from Review instead. - The repair is not a rebase (an ordinary failing-check repair takes the
ci.revalidate_repairspath unchanged).
The approval is moved only from the approval the check was made against: an approval that was revoked or replaced in the meantime is never carried. Nothing is published early; the replayed head stays local until the Push step republishes it after Test.
The restart at Test is recorded with the carried approval, in the same write, and stays pending until the Push step publishes after Test onward has run. So it survives the CI step parking on findings that need your decision: approving them, even after a daemon restart, restarts at Test; a fix round that changes nothing or fails restarts at Test too; and a fix round that commits on top of the carried head revalidates from Review, even when its fixer then fails. None of these publishes the carried head directly.
This value is read only from the trusted default-branch copy of this file, like the rest of the ci block: a pushed branch cannot let its own rebases skip Review.
A value set here wins over the operator’s own ci.carry_review_on_replay in both directions.
ci.release_after_checks_pass
Whether the CI step finishes the run at its checks verdict instead of monitoring the pull request until it is merged or closed.
| Type | bool |
| Default | false |
| Trust | Read only from the trusted default branch |
ci: release_after_checks_pass: truefalse(default) is what the step has always done: once every check is green the run records readiness and keeps watching the PR until it is merged, closed, or declined, and a later base-branch advance or conflict is still repaired on its own.truefinishes the step at that point. The run completes with thechecks_passedstatus, releases its worktree, and reportsoutcome: checks-passed; whether and when the PR is merged is then the user’s decision, and nothing observes the merge afterwards, so the recorded CI duration stops at the checks verdict instead of including the wait for a merge.
This value is read only from the trusted default-branch copy of this file, like the rest of the ci block: a pushed branch cannot opt itself into the shorter run, or out of it.
A value set here wins over the operator’s own ci.release_after_checks_pass in both directions.
rebase.strategy
How the Rebase step integrates a base branch that moved under the gated branch.
| Type | string (rebase or merge) |
| Default | rebase |
| Trust | Read only from the trusted default branch |
rebase: strategy: mergeOpting in. Commit that block to your default branch (the same copy the daemon reads commands and agent from). It takes effect on the next run of every branch in the repository; a branch cannot opt itself in or out. The default stays rebase for every repository that does not ask, so upgrading no-mistakes never changes the shape of history under you.
rebase(default) replays the branch’s commits on top of the new base. This is the historical behavior and is unchanged.mergeintegrates the base with agit merge --no-ffcommit whose first parent is the head the pipeline reviewed.
The two differ in what survives the integration, which matters in three places:
rebase (default) | merge | |
|---|---|---|
| The reviewed head after integration | rewritten; no longer exists on the branch | still on the branch, as the first parent |
| Publication | force-push; an open PR’s head is rewritten | fast-forward; the PR’s head is appended to |
| Evidence of what a conflict resolution did | none; the result is just commits | the merge commit’s two parents and their merge base |
| Cost | none | one merge commit per integration |
Integration publishes as a fast-forward under merge. A CI merge-conflict repair is the exception: it rebases onto the base branch whichever strategy is set, so that repair still force-pushes and still revalidates in full.
Continuity. The CI step publishes a repair without a full revalidation cycle only when it can prove the repaired head continues the reviewed head (see ci.revalidate_repairs). Under merge that proof is plain ancestry, because the reviewed head is a parent. Under rebase there is nothing to prove it with.
Attestation. A review attestation that binds to an exact commit SHA survives a merge, because the attested commit stays in the branch’s history. A rebase rewrites every branch SHA, so the attested commit no longer exists on the branch.
Audit. Whether a conflict resolution deleted content one side introduced is decidable from a merge commit alone - its two parents and their merge base are all the inputs - by anything, afterwards, from outside no-mistakes. A rebase leaves no such record, so the same question is unanswerable once the run ends. To match, the conflict resolver’s prompt under merge requires an additive resolution: keep both sides’ introduced content, and never delete what one side introduced merely to make the merge apply. Only genuinely mutually exclusive changes may supersede one another, and the agent must say which and why.
The cost is a merge commit per integration. On a squash-merged default branch (one commit per PR) those commits collapse at landing and never reach it. On a merge-committed one they do, so the history is a graph rather than a line.
This value is read only from the trusted default-branch copy of this file, regardless of allow_repo_commands. It decides whether integrating a moved base leaves auditable evidence behind, so a pushed branch must not be able to change it in either direction. A value set here wins over the operator’s own rebase.strategy.
commit.fix_message
Override the auto-fix commit subject template for this repository.
| Type | string |
| Default | Inherits from global config, whose default is no-mistakes({{.Step}}): {{.Summary}} |
The value follows the global commit.fix_message template syntax and validation rules.
That includes the 1,024-byte template limit, 16-placeholder limit, 4,096-byte summary and rendered-subject limits, and rejection of bidi and invisible Unicode format characters.
The setting applies to the Review, Test, Document, Lint, and CI repair paths, plus operator-authorized repository gate repairs. When set to anything other than the default, it also renders the Push step’s catch-all commit ({{.Step}} is push, {{.Summary}} is apply agent fixes). It does not apply to commits created by the Rebase step or to evidence-branch commits.
This non-executing field is read from the pushed branch, so a branch can adopt its own commit-subject convention without enabling allow_repo_commands.
To apply a machine-local convention without adding it to the repository, see global repository_overrides.
commit.branch_pattern
Override the branch-identifier extraction pattern for this repository.
| Type | string regular expression |
| Default | Inherits from global config; when unset there, {{.Branch}} is the normalized full branch name |
The value follows the global commit.branch_pattern syntax and validation rules.
Its only capture group becomes {{.Branch}} in both commit.fix_message and pr.title_format.
For example, branch_pattern: '([A-Z]+-[0-9]+)' extracts PROJ-123 from feature/PROJ-123-add-widget.
When either template uses {{.Branch}} and the pattern does not find a non-empty identifier, rendering fails safely instead of producing an empty prefix.
This non-executing field is read from the pushed branch without enabling allow_repo_commands.
commit.trailers
Override the trailers appended to agent-produced commits for this repository.
| Type | list of string templates |
| Default | Inherits from global config, where it is unset |
The entries follow the global commit.trailers placeholders and validation rules.
A list here replaces the inherited one rather than extending it, and trailers: [] turns inherited trailers off for this repository.
This non-executing field is read from the pushed branch without enabling allow_repo_commands, like commit.fix_message: it shapes the messages of fix commits on that branch, whether the pipeline makes them or rewrites them onto a fix agent’s own git commit (see fix commits).
intent
Override transcript-based user-intent extraction settings for this repo. Fields not set here inherit from global config and then the built-in defaults.
| Field | Type | Default |
|---|---|---|
intent.enabled | bool | Inherits from global (default true) |
intent.threshold | float | Inherits from global (default 0.2) |
intent.slack_days | int | Inherits from global (default 3) |
intent.disabled_readers | string[] | Adds to globally disabled readers |
Valid disabled_readers values are claude, codex, opencode, rovodev, pi, and copilot.
test.prepare
Type: boolean. Default: false. Repository-only, trusted-default-branch-only, even with allow_repo_commands: true.
commands: prepare: "npm ci --prefer-offline"test: prepare: true# commands.test remains unset: Test is agent-driven.Opts agent-only Test into running commands.prepare before its first agent turn (including a repair turn). Uses the same successful-worktree receipt, cleanup/restoration, failure reporting, and recovery behavior as configured Test/Lint/Format; later configured commands do not install again. A new worktree prepares separately. Existing dependencies or an agent’s claim that installation succeeded do not count as managed preparation. An empty commands.prepare remains a no-op, and configured commands.test retains its existing preparation behavior.
This is eager, not on-demand: opted-in repositories pay setup cost even when the evidence agent subsequently reports no-surface. Leave it off to retain lazy command-only preparation. Preparation does not replace fresh Test evidence or change verdict/approval policy. Failures stop Test before the agent launches and never record successful preparation.
The trigger always comes from the trusted default branch; pushed-branch text cannot enable it. The executable commands.prepare value separately follows the existing allow_repo_commands policy.
test.base_attribution
Type: boolean. Default: false. Repository-only, trusted-default-branch-only, even with allow_repo_commands: true.
commands: test: "go test ./internal/... -count=1"test: base_attribution: trueWhen a configured commands.test exits non-zero, re-runs the same command on the run’s base commit (the merge base with the effective PR base branch) and diffs the two results, so failures that already exist on the base are not blamed on the change. The base run uses a disposable clone of that commit outside the run worktree, runs commands.prepare there first when one is configured (its output is logged as Prepare (base), and its tracked and ordinary untracked changes are reset before the base suite runs, exactly as on the head, so only ignored materialization survives), and logs its output to the Test step log as Test (base). Base preparation and the base command share one deadline, the Test budget test_agent_timeout (default 30 minutes); a base run that outlives it is stopped and reported as unavailable while the head’s failure still parks. Both base commands keep the machine-local nice settings for prepare and test. Only the repository command’s own output is attributed: machine-local additional test checks are never re-run on the base, and a failure in one of them alone triggers no base run.
The attribution leads the Test findings summary (the failure output the PR and repair turns see) and is passed to the evidence agent:
- the command passes on the base: every failure is introduced by the change;
- the command also fails on the base: recognized per-test failure lines are split into introduced by this change and pre-existing on the base commit. Per-test lines are recognized for common runners (
go test, pytest, jest/vitest, TAP, cargo); package- or file-level summary lines are ignored, except that ago testfailure is keyed by the package its block reports, and a pytest failure is keyed by itspath::testid without the failure reason. Only those two carry a package or file identity; any other line that also fails on the base (jest/vitest, TAP, cargo, orgo testoutput without a package line) may be a different test sharing the name, so it is listed as ambiguous, could not attribute instead of pre-existing. Ago testpackage that fails with no per-test line (a build failure, or aTestMainorinitpanic) and did not fail that way on the base is listed under failures without a per-test line (could not be attributed). When no per-test lines are recognized in the base output, or none are left to list from the change’s output, the summary says the two could not be separated; - the base checkout, preparation, or run cannot complete (including a base command that exits 126 or 127, meaning it could not be executed or found, such as an ignored dependency the fresh clone lacks, or a base run past its deadline): the summary says attribution is unavailable and every failure stays attributed to the change.
Attribution informs; it never changes the gate. The failing command still parks the Test step with the same error finding, an approval over it is still recorded as a configured-command override (see test.allow_approve_over_failure), and a passing command never triggers a base run. Each failing Test execution, including after an auto-fix round, pays one extra run of the command, which is why this is off by default.
test.instructions
Repository-specific runbook for standing the product up during live validation.
| Type | string (multiline) |
| Default | Empty |
The Test step injects these instructions into its repair and evidence prompts so each agent can start and drive the real product the way an end user would.
Like document.instructions, this field steers its own gate, so it is honored only from the trusted default-branch copy of .no-mistakes.yaml, regardless of allow_repo_commands. A contributor’s pushed branch cannot rewrite the runbook that validates that branch.
An operator can add their own runbook for this repository through a machine-local repository_overrides entry; it is rendered as a separate, labeled section before this field’s and never replaces it.
test.allow_approve_over_failure
Recorded reason that opts this repository into letting the PR must be raised via no-mistakes check accept a Test step that was approved over a failing configured commands.test.
| Type | string |
| Default | Empty (off) |
Off by default. When a Test step is approved while commands.test exited non-zero, no-mistakes records that as an override on the step and copies it onto the PR attestation as steps[].override_reason. The required check then refuses that attestation unless this field is a non-empty reason, which is copied into the attestation as allow_test_command_override.
Like no_ci, this field weakens a merge gate, so it is honored only from the trusted default-branch copy of .no-mistakes.yaml, regardless of allow_repo_commands. A contributor’s pushed branch cannot waive the configured-test check that certifies it. The string is the recorded reason; whitespace-only is treated as unset.
test.evidence
Configure repository publication of evidence artifacts from the test step. Fields not set here inherit from global config and then the built-in defaults.
| Field | Type | Default |
|---|---|---|
test.evidence.store_in_repo | bool | Inherits from global (default false) |
test.evidence.attach_media | bool | Inherits from global (default true) |
test.evidence.dir | string | Inherits from global (default .no-mistakes/evidence) |
test.evidence.branch | string | Inherits from global (default no-mistakes/evidence) |
test.evidence.commit_message | string | Inherits from global (default no-mistakes: evidence for {{.Branch}} (run {{.RunID}})) |
By default, test evidence is written to <NM_HOME>/evidence/<run-id>. Where it is stored locally and how long it is kept are global-only settings; see test.evidence.
For GitHub repositories, set store_in_repo: true to also publish it to an orphan evidence branch in the code branch’s push-target repository and link the artifacts from the PR body; evidence is never committed to the pushed branch, so it never reaches the default branch.
test.evidence.branch is read ONLY from the trusted default-branch copy of this file, because it names a git ref the daemon pushes to; a pushed branch cannot redirect evidence commits.
The other publication fields, including test.evidence.commit_message, are read from the pushed branch. The commit-message template shapes only the evidence commit subject and cannot select its target branch.
See global config for attachment behavior, credential-vault opt-out guidance, provider support, limits, validation, and fail-closed behavior.
providers.github.draft_pull_requests
Override the global GitHub draft setting for this repo.
| Type | bool |
| Default | Inherits from global (default false) |
providers.gitlab.draft_pull_requests
Override the global GitLab draft setting for this repo.
| Type | bool |
| Default | Inherits from global (default false) |
providers.bitbucket.draft_pull_requests
Override the global Bitbucket draft setting for this repo.
| Type | bool |
| Default | Inherits from global (default false) |
providers.azuredevops.draft_pull_requests
Override the global Azure DevOps draft setting for this repo.
| Type | bool |
| Default | Inherits from global (default false) |
providers.origin.draft_pull_requests
Override the global Cursor Origin draft setting for this repo.
| Type | bool |
| Default | Inherits from global (default false) |