Skip to content

Global Config Reference

Global configuration lives at ~/.no-mistakes/config.yaml. Set NM_HOME to relocate the config directory.

~/.no-mistakes/config.yaml
agent: auto
acpx_path: acpx
forgejo_axi_path: forgejo-axi
acp_registry_overrides:
local-gemini: node /opt/mock-acp-agent.mjs
agent_path_override:
claude: /Users/you/bin/claude
codex: /opt/homebrew/bin/codex
grok: /Users/you/.grok/bin/grok
rovodev: /usr/local/bin/acli
opencode: /usr/local/bin/opencode
pi: /usr/local/bin/pi
copilot: /usr/local/bin/copilot
agent_config:
codex:
model: gpt-5.4
effort: low
agent_args_override:
codex:
- -c
- service_tier="priority"
ci_timeout: "168h"
step_quiet_warning: "10m"
agent_timeout: "30m"
review_agent_timeout: "30m"
test_agent_timeout: "30m"
daemon_connect_timeout: "3s"
branch_sync_remote_timeout: "60s"
gate_reconcile_interval: "2m"
gate_reconcile_timeout: "30s"
log_level: info
session_reuse: true
worktree_roots:
/Users/you/src/my-repo: /Users/you/work/my-repo-runs
forge_profiles:
github-personal:
gh_config_dir: ~/.config/gh-personal
github-work:
gh_config_dir: ~/.config/gh-work
gitlab-work:
glab_config_dir: ~/.config/glab-work
provider_plugins:
ssm:
command: ~/bin/nm-ssm-plugin
hosts: ["*.sourcemanager.dev"]
auto_fix:
rebase: 3
review: 0
test: 3
document: 3
lint: 3
ci: 3
ci:
rerun_transient: 0
revalidate_repairs: false
review_bot_comments: on_failure # or: always
rebase_behind: false
carry_review_on_replay: false
release_after_checks_pass: false
required_reviews: []
rebase:
strategy: rebase # or: merge
review:
path_instructions: []
commit:
fix_message: "chore(no-mistakes-{{.Step}}): {{.Summary}}"
# branch_pattern: '^PROJ/([0-9]+)$'
# branch_replacement: 'PROJ-${1}'
# 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: []
# publish_intent: false # Keep the generated Intent section out of PR bodies by default
test:
evidence:
store_in_repo: false
attach_media: true
dir: .no-mistakes/evidence
branch: no-mistakes/evidence
commit_message: "no-mistakes: evidence for {{.Branch}} (run {{.RunID}})"
retention: 336h
max_runs: 200
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: false

Fields

agent

Default agent for all repos and setup-wizard suggestions. Can be overridden per-repo.

Typestring or string[]
Valuesauto, claude, codex, grok, rovodev, opencode, pi, copilot, antigravity, cursor, devin, acp:<target>
Defaultauto

auto resolves to the first supported native agent or ACP alias in this order: claude, codex, grok, opencode, acli with rovodev support, pi, copilot, antigravity, cursor, then devin. cursor is an ACP alias for the cursor target with default command cursor-agent acp, and devin is an ACP alias for the devin target with default command devin acp. With default paths, auto only selects an alias when both its command binary (cursor-agent or devin) and acpx resolve; acp_registry_overrides.<target> and acpx_path replace those respective defaults during availability checks. acp:<target> uses the user-installed acpx binary to run an ACP target, for example acp:gemini; acp:cursor and acp:devin use the same default commands as cursor and devin. Arbitrary acp:<target> agents are opt-in and are not considered by agent: auto. The effective agent configuration must resolve to a runnable runner before a new validation gate starts. If an explicit agent is unavailable, auto finds no native agent or ACP alias, or no fallback-list entry is available, the gate fails before its first pipeline step rather than reporting a partial command-only validation as passed. no-mistakes doctor checks the global configuration, while every run repeats resolution after applying any trusted repository-level agent override.

You can also set an ordered fallback list:

agent: [codex, grok]

The list is filtered to entries available to the daemon at run startup. By default, the first available entry becomes the primary agent; opt-in quota-aware routing can reorder that resolved list. After resolving auto, entries that resolve to the same ACP target are deduplicated in list order, so cursor and acp:cursor (or devin and acp:devin) provide one fallback and preserve whichever spelling appears first. If no entry is available, the gate fails before its first pipeline step. If a pipeline invocation fails because that agent process cannot start or exits with an error, no-mistakes retries that invocation with the next available fallback. Fallback candidates share the invocation’s existing bounded context and use only its remaining time; once that context expires or is cancelled, no further candidate is announced or started. Structured findings and validation failures in an agent’s returned output do not trigger fallback. A recognized Codex provider rejection of the requested structured-output schema does trigger fallback.

acpx_path

Path to the user-installed acpx binary used for agent: acp:<target> and ACP aliases such as agent: cursor and agent: devin.

Typestring
Defaultacpx

forgejo_axi_path

Executable used for Forgejo PR and CI operations.

Typestring
Defaultforgejo-axi

A bare name is resolved from the daemon’s effective PATH; an explicit path is executed directly. See Provider Integration for setup and the environment reference for host and token configuration.

acp_registry_overrides

Map an ACP target name to a raw ACP agent command. When agent: acp:<target> matches an override key, no-mistakes runs acpx --agent <command> instead of acpx <target>. ACP aliases use the same target keys. For example, agent: cursor and agent: acp:cursor resolve to the cursor target, so set cursor to override the default cursor-agent acp command; devin likewise overrides the default devin acp command. Values are trimmed; a blank or whitespace-only value behaves as no override, so an alias keeps its default command. Availability checks always resolve acpx_path. They also probe the executable named first in the effective non-blank raw command when it is a bare command name or clean absolute path. Relative, quoted, or escaped raw commands are not pre-probed; acpx executes them from the worktree. These checks do not invoke the ACP target or test its credentials.

Typemap[string]string
DefaultEmpty

Example:

agent: acp:local-gemini
acp_registry_overrides:
local-gemini: node /opt/mock-acp-agent.mjs

For devin, an override is also the way to select a model slug from devin models list that Devin does not advertise over ACP, since agent_config.devin.model accepts only ACP-advertised ids:

agent: devin
acp_registry_overrides:
devin: devin acp --model <slug>

agent_path_override

Custom binary paths for native agents. When set, no-mistakes uses this path instead of looking up the binary on PATH. ACP agents and aliases use acpx_path for the bridge; use acp_registry_overrides to replace a raw target command such as cursor-agent acp.

Typemap[string]string
DefaultEmpty (uses default binary names)

Default native binary names when no override is set:

AgentBinary
claudeclaude
codexcodex
grokgrok
rovodevacli
opencodeopencode
pipi
copilotcopilot
antigravityagy

agent_config

Model and reasoning effort per agent, in one common spelling. no-mistakes maps each field down to whatever mechanism that harness actually uses, so you no longer have to know each CLI’s own flag.

Typemap[string]{model, effort, quota_provider}
Keysclaude, codex, grok, rovodev, opencode, pi, copilot, antigravity, cursor, devin, acp:<target>
DefaultEmpty (every harness keeps its own defaults)
agent_config:
codex:
model: gpt-5.4
effort: low
claude:
model: sonnet
effort: high
opencode:
model: openai/gpt-5
cursor:
model: gpt-5

effort is one of minimal, low, medium, high, xhigh, max. The value is passed to the harness as written, so a level that harness does not implement is rejected by the harness itself rather than silently downgraded.

How each field maps:

AgentmodeleffortAccepted effort levels
claude--model--effortlow, medium, high, xhigh, max
codex-m-c model_reasoning_effort="…"minimal, low, medium, high
grok--model--reasoning-effortwhatever the selected reasoning model accepts
copilot--model--effortminimal, low, medium, high, xhigh, max
pi--model--thinkingminimal, low, medium, high, xhigh, max
opencodesession model (needs provider/model)session model variantprovider-specific
cursor, devin, acp:*acpx --modelnot expressible-
rovodevnot expressiblenot expressible-
antigravitynot expressiblenot expressible-

opencode needs the provider/model form (for example openai/gpt-5) because its session API takes the provider and the model as separate fields; a bare model name is refused at config load rather than dropped. OpenCode 2 receives both knobs in the model reference when the session is created; an effort-only profile resolves the location’s default model first. OpenCode 1 receives them in the session message. Neither version receives model flags in the launch command, because opencode serve rejects them.

An entry may also declare quota_provider, the quota-axi provider ID used as routing input when quota_routing.enabled is on. It does not set a harness option. See quota-aware routing for provider defaults, Pi’s explicit-provider requirement, and account selection.

rovodev and antigravity have no mechanism no-mistakes can set - acli rovodev serve plus its REST session API take no model parameter, and the agy CLI parses flags strictly - so setting model or effort for them is a config error. An entry containing only quota_provider is valid. Reach for agent_args_override there if your build of the CLI accepts a flag. Reasoning effort is likewise unavailable for ACP targets: no-mistakes drives them through acpx, which exposes --model but no effort surface. acpx also accepts only the model ids a target advertises over ACP; for devin that is a subset of devin models list, and acp_registry_overrides is the escape hatch for the rest.

agent_config is global-only. Like agent_args_override, it decides which model runs with your credentials, so an agent_config block in a repository’s .no-mistakes.yaml is ignored. For first-class ACP aliases, cursor and acp:cursor share a profile, as do devin and acp:devin: the selected spelling’s entry wins when both are configured; otherwise the other spelling’s entry applies. This also applies to review-agent profiles.

Precedence for unpinned runs. agent_args_override wins. Opt-in per-run Pi profiles have a separate, immutable selection contract. If a raw flag already pins a knob natively - for example, -m, --model, or a -c/--config assignment whose exact key is model or model_reasoning_effort for Codex, plus the other harnesses’ --effort, --reasoning-effort, or --thinking forms - then agent_config does not emit its value for that knob. Text such as model= nested inside an unrelated option’s value is not a pin. Any knob the raw flags leave alone still comes from agent_config, so adding agent_config to an existing configuration never changes the arguments that configuration already supplied:

agent_config:
codex:
model: gpt-5.4 # ignored: the raw -m below pins it
effort: low # applied: nothing raw pins reasoning depth
agent_args_override:
codex:
- -m
- o3

Per-run Pi profiles

Select a profile when creating a validation run, without editing global config:

Terminal window
no-mistakes axi run --intent "the user's goal" \
--model openai-codex/gpt-5.4 --effort high

--model and/or --effort opt in. Each explicit field overrides agent_config.pi; an omitted field inherits that global default. Both must resolve to nonempty values before a run starts. Use a provider-qualified model ID from Pi’s catalog, not a bare name, URL, glob, or :thinking suffix. Supported effort spellings are minimal, low, medium, high, xhigh, max. Availability, authentication, and model-specific reasoning support remain Pi’s responsibility. For optional quota evidence at run start, see quota-aware routing.

A pin applies to every pipeline duty, including reviewer and fixer roles. The effective agent selection must be Pi-only (no auto, non-Pi fallbacks, or non-Pi review_agents). Under the default trust policy, a nonempty agent in the freshly fetched, trusted default-branch .no-mistakes.yaml replaces the global scalar or fallback list for this check, just as it does for an ordinary run. This lets one project opt into Pi profiles with trusted agent: pi while other projects keep a global agent: auto or another global selection. When the trusted project config does not select an agent, the global selection must itself be Pi-only. If the trusted default branch enables allow_repo_commands: true, the submitted branch instead becomes the source of any repository agent override. Without that opt-in, an agent: pi that exists only on the submitted feature branch cannot authorize the profile. Unreadable or malformed submitted/trusted config refuses the profile. These checks run before any active validation is cancelled. Pi role-specific model/effort values are superseded by the run pin. Native --model, --provider, --models, --thinking (including --flag=value), or -- in agent_args_override.pi conflict at launch: move defaults to agent_config.pi rather than combining two selection mechanisms.

The daemon resolves the values once and stores runs.pi_profile atomically with run creation. That field cannot be changed or cleared. Each invocation, retry, fresh review, resumed fixer, and daemon recovery uses that pin; later global model, effort, agent-chain, role, or raw selection-flag changes cannot replace it. Recovery still enforces trusted repository policies and refuses unusable configuration or a missing Pi binary rather than switching harnesses. The pin fixes selection parameters, not provider credentials, model-catalog contents, or other agent settings; credentials are never stored in it.

Reattaching with omitted flags preserves the existing pin. Explicit fields must match it; a different profile requires a new run. The same rule binds nonce replays and receipt claims. rerun --model ... --effort ... selects a profile for a new run; without those flags a rerun uses current global configuration, not its predecessor’s pin. Existing runs and all callers omitting both flags remain unpinned and keep the previous global-config behavior. Concurrent runs hold independent pins without modifying shared configuration.

Structured AXI status and daemon run/receipt responses expose pi_profile: {model, effort} only for pinned runs. no-mistakes stats --run <id> shows that requested profile alongside per-invocation served-model and usage evidence; a pin is not a claim that a provider reported usage. These values stay local, not in remote analytics. The CLI checks daemon support before a fresh pinned submission, so an older daemon cannot silently launch it without a pin.

review_agents

Optional, global-only harness and model/effort overrides for the review loop. Repository .no-mistakes.yaml cannot set these profiles. Omitted roles keep the normal agent selection and fallback chain; other pipeline steps are unchanged.

review_agents:
reviewer:
agent: pi
model: anthropic-vertex/claude-opus-4-8
effort: max
fixer:
agent: pi
model: google-vertex/gemini-3.8-flash
effort: max

The role keys are reviewer, fixer, and their optional later-round overlays reviewer_after_round and fixer_after_round. Each configured role requires one explicit agent (the same harness names as agent_config; no auto or lists). Model and effort are optional and inherit agent_config for that harness when empty. Nonempty role values override that profile, but native agent_args_override flags still win. Model availability, credentials, and supported effort levels remain the harness/provider’s responsibility.

Later-round role overrides

reviewer_after_round and fixer_after_round are opt-in overlays for long review loops, where the first pass is worth a stronger tier and later rounds are mostly re-checking a fix the stronger model already prescribed. Each takes the same agent / model / effort fields plus after_round: the number of leading rounds that stay on the base role. after_round defaults to 1, so the overlay takes over from round 2.

review_agents:
fixer:
agent: pi
model: anthropic-vertex/claude-opus-4-8
fixer_after_round:
agent: pi
model: google-vertex/gemini-3.8-flash
after_round: 2

Rounds 1 and 2 above run on the fixer profile; round 3 and every later round run on fixer_after_round. The direction is yours: point the overlay at a cheaper tier to stop long loops from spending at the top tier, or at a stronger one to escalate a loop that is not converging.

Without these keys nothing changes - every round runs on the role it runs on today. They only select the harness for a round; they never change how many rounds happen, and auto_fix plus the gate remain the only things that bound the loop. The overlay applies to a round the pipeline numbered; an invocation outside a numbered round keeps the base role. Only the base roles accept plain agent / model / effort - setting after_round on reviewer or fixer, or a value below 1, is a configuration error. Because a later-round fixer may be a harness that cannot resume sessions, fixer session reuse is reported for every fixer a run can use: configuring a non-resumable fixer_after_round turns fix turns cold for the whole run rather than handing round 3 a session it cannot resume. no-mistakes stats --run <id> shows the agent and served model per invocation alongside its round, so which tier served which round is visible after the fact.

Both roles can use the same harness with different models. Reviews and rereviews always run fresh; only review fixes reuse the fixer’s session when session_reuse is enabled and the fixer supports it. These settings do not select the agents repairing tests, documentation, or CI. An opt-in per-run Pi profile supersedes these role values for that run. Eval capture strips these profiles so replay candidates remain authoritative.

agent_args_override

Extra CLI flags to pass to each native agent. Use this for anything agent_config does not cover - service tier, permission mode, profiles, or any other flag the underlying agent supports - and as the escape hatch for a harness whose model or effort flag no-mistakes cannot map. For model and reasoning effort on a mapped harness, prefer agent_config: one spelling instead of seven.

Typemap[string][]string
Keysclaude, codex, grok, rovodev, opencode, pi, copilot, antigravity
DefaultEmpty (no extra flags)

User-supplied flags are normally inserted ahead of no-mistakes’ managed flags, so your choices usually take precedence. Security suppression selected by trusted disable_project_settings may be placed first while preserving a compatible operator pin. A few flags are reserved because no-mistakes depends on them to communicate with the agent - setting any of these returns a config error on load:

AgentReserved flags
claude-p, --print, --verbose, --output-format, --json-schema, -r, --resume, --session-id, -c, --continue, --fork-session
codexexec, resume, --resume, --session, --session-id, --thread, --thread-id, --last, --json, --color
grok-p, --single, --prompt-file, --prompt-json, --output-format, --json-schema, -r, --resume, -c, --continue, --fork-session, --session-id, --system-prompt-override, --system-prompt, --rules, --append-system-prompt, --agent, --agents, --verbatim, --no-subagents, --no-auto-update, --cwd, --restore-code, --worktree, --worktree-ref
rovodevrovodev, serve, --disable-session-token
opencodeserve, --hostname, --port, --print-logs
pi--mode, --no-session, -c, --continue, -r, --resume, --session, --session-id, --fork
copilot-p, --prompt, --output-format, --no-color
antigravity--dangerously-skip-permissions, --print, --json-schema, --output-format, --conversation, -c, --continue

For structured codex runs, no-mistakes also appends its own --output-schema <tempfile> after your overrides. Treat that flag as managed even though config validation does not currently reject it.

The selected Codex profile/model’s provider must accept that schema. A recognized provider schema rejection lets the next eligible configured fallback agent take over. Without one, the run stops with codex structured-output incompatibility and preserves the provider diagnostic. The Codex schema incompatibility is not retried by the adapter or by automatic crash retries. A Review or Test analyzer rerun restarts the agent chain, so Codex may be called again and fail fast before the fallback runs. Review is neither skipped nor retried without the schema. Select a compatible Codex profile/model or configure a different agent route, then rerun the pipeline so review can complete. A profile that works for plain prompts, such as Rebase, can still reject structured review requests.

The Claude, Codex, Grok, Pi, and Antigravity session-control forms are reserved so no-mistakes can keep review-loop conversations deterministic: review turns stay session-free while the fixer keeps its own isolated durable session.

Smart defaults:

  • For claude, supplying --permission-mode (or --dangerously-skip-permissions) suppresses the default --dangerously-skip-permissions.
  • For codex, supplying --ask-for-approval, --sandbox, or --dangerously-bypass-approvals-and-sandbox suppresses the default --dangerously-bypass-approvals-and-sandbox.
  • For grok, supplying --permission-mode or --always-approve suppresses the default --permission-mode bypassPermissions. No model flag is added: Grok uses its current configured default unless you explicitly set -m or --model.
  • For antigravity, supplying -t or --print-timeout suppresses the default --print-timeout 24h.

Permission and sandbox flags affect the underlying agent, but they do not disable no-mistakes’ pipeline prompt steering. Pipeline agents are still told to keep intentional writes inside the worktree and avoid mutating system state outside it.

Example:

agent_args_override:
claude:
- --model
- sonnet
- --permission-mode
- acceptEdits
codex:
- -m
- gpt-5.4
- -c
- service_tier="priority"
- -c
- model_reasoning_effort="low"
grok:
- --reasoning-effort
- high
rovodev:
- --profile
- work
pi:
- --provider
- google

Do not put a model flag under opencode here: these flags go to opencode serve, which exits with usage on an unknown option. Use agent_config.opencode.model instead.

For Codex, service_tier and reasoning effort tune different things: service_tier selects the speed or priority lane, while reasoning depth is what agent_config’s effort sets (as -c model_reasoning_effort). no-mistakes reloads global config while setting up each run, so edits made before no-mistakes axi run apply to that run. An opt-in per-run Pi profile still keeps its pinned model and effort for that run’s lifetime. For repeatable profiles, use separately initialized NM_HOME directories; each has its own config.yaml and no-mistakes state.

forge_profiles

Optional machine-local routing for repositories that use different GitHub or GitLab identities. Keys are the raw host tokens recorded in the repository remote, including SSH aliases such as github-personal. Each entry must set exactly one provider config directory:

forge_profiles:
github-personal:
gh_config_dir: ~/.config/gh-personal
github-work:
gh_config_dir: /Users/you/.config/gh-work
gitlab-work:
glab_config_dir: ~/.config/glab-work
expected_login: team-bot

Paths must be absolute or begin with ~/; environment variables and other shell expansion are not supported. Host keys are case-insensitive.

When a repository matches a profile, no-mistakes validates it before starting the pipeline and applies an immutable environment to every subprocess in that run: built-in provider commands, custom shell commands, agents, managed agent servers, and the run’s Git commands together with any hooks or credential helpers they spawn. A GitHub profile sets GH_CONFIG_DIR and removes higher-precedence GitHub token, host, and repository variables; a GitLab profile does the equivalent for GLAB_CONFIG_DIR and GitLab variables. The daemon process environment is never changed.

Each selected GitHub config must contain the target host and exactly one account for it, with that account active. A selected GitLab config must contain the target host. An optional expected_login pins the account name the profile must be signed in as; resolution fails closed when the config’s active login differs or is missing, so a swapped or re-authenticated config directory can never route a run through the wrong account. It carries an account name only, never credentials. no-mistakes doctor validates every configured profile and its online authentication.

Profile activation is provider-specific and fail-closed: after at least one GitHub profile is configured, a GitHub repository must match a GitHub profile; GitLab remains ambient unless a GitLab profile is also configured, and vice versa. With no forge_profiles, provider detection and ambient CLI authentication behave exactly as before.

For a GitHub fork, no-mistakes considers both the parent and fork host tokens. A match on either side is sufficient. If both match, they must select the same account: the same effective provider config directory and the same expected_login pin. Otherwise startup fails as ambiguous, so two host tokens sharing a config directory while pinning different logins can never silently resolve to one of them. Fork PR topology itself is unchanged.

Deliberate scope boundaries, so profiles never duplicate what other layers own:

  • Commit identity stays with Git. Author and committer for pipeline fix commits come from the effective Git configuration (for example remote-keyed includeIf sections), which resolves naturally inside run worktrees. Profiles carry no name/email fields.
  • Two accounts on the same host are distinguished by remote host tokens. Give each account its own SSH alias (github-personal, github-work) and key a profile per alias; a profile cannot disambiguate two accounts behind one identical remote URL.
  • Executable selection stays with the machine. Which gh, glab, or git runs is owned by PATH and the existing command resolution, not by profile configuration.
  • Credential-helper context stays with Git configuration. Profiles point at provider CLI config directories and never model or store credential material; credentials remain in the CLI’s own store.

provider_plugins

Optional machine-local PR and CI support for hosts no-mistakes does not ship a provider for, such as a company-internal forge or Google Cloud Secure Source Manager. Each entry names an AXI-shaped CLI that implements the provider plugin protocol and the hosts it serves:

provider_plugins:
ssm:
command: ~/bin/nm-ssm-plugin
args: ["--location", "us-central1"]
hosts: ["*.sourcemanager.dev"]
timeout: 2m
draft_pull_requests: false
KeyRequiredMeaning
commandyesExecutable to run. A bare name is resolved from the run’s PATH; a path must be absolute or begin with ~/. Relative paths are refused because plugins run with the run worktree as their working directory.
argsnoArguments passed verbatim on every invocation, before the subcommand words (<command> <args...> pr view 7 ... --json). PR bodies travel in a private --body-file, never in argv, so they never appear in a process listing.
hostsyesHost patterns the plugin claims: an exact host name or SSH alias as it appears in the remote, or *.<domain> for any subdomain (not the apex). No scheme, port, path, or user.
timeoutnoBound for one plugin invocation (Go duration). Defaults to 2m.
draft_pull_requestsnoPasses --draft to pr create. Defaults to false.

Names are 1-63 lowercase letters, digits, -, or _ and must not reuse a built-in provider name. A run’s provider shows up as plugin:<name>.

Selection happens per run, before built-in detection and forge profiles: the remote’s literal host token is matched first, then its SSH HostName resolution. An exact pattern beats a wildcard, and a longer wildcard beats a shorter one. Two plugins (or one plugin twice) may not list the same pattern, and a host that a forge_profiles entry claims may not also be claimed by a plugin; both are configuration errors. Because a forge profile matches the remote’s literal host while a plugin also matches its SSH HostName, an overlap that only appears after alias resolution (a profile keyed by an SSH alias whose HostName a plugin claims) is refused when the run starts, with an error naming both.

provider_plugins is global-only. A plugin runs with your credentials for every repository on its hosts, so a repository .no-mistakes.yaml can never add, change, or redirect one; a provider_plugins block there is ignored.

Plugins run through the same environment as built-in provider CLIs (the daemon’s login-shell environment plus any forge-profile overlay) with the run worktree as the working directory. A plugin whose status exits non-zero (for example, not authenticated) makes the PR and CI steps skip with its message, reported under run.automatic_skips; a plugin that breaks the protocol (unreadable output, wrong protocol version, timeout) fails the step instead, in its status handshake or in any later call (a timeout during the CI step’s repeated polls or log retrieval is handled like any failed read instead). no-mistakes doctor lists configured plugins and checks that each command resolves; it does not run the plugin, because the handshake is per repository.

ci_timeout

How long the CI step waits for provider CI status to settle before giving up, and how long it keeps monitoring an open PR after every check is green.

Typestring (Go duration, or an unlimited keyword)
Default168h (7 days)

Accepts any Go time.ParseDuration string: 30m, 2h, 4h30m, etc.

This is an idle timeout, not an absolute deadline: every time the base branch advances, the monitor re-arms it. So an actively-updated green PR keeps its monitor no matter how long it stays open; under ci.release_after_checks_pass that watch ends at the checks verdict instead. If it later develops an actual merge conflict (on GitHub, GitLab, Forgejo, Azure DevOps, Cursor Origin, or a provider plugin declaring mergeable_state), the CI auto-fix path rebases it, revalidates from Review because rebasing cannot prove continuity with the reviewed head, and publishes it through Push. A clean behind PR needs no command, except on GitHub when the base requires up-to-date branches (mergeStateStatus: BEHIND): that PR waits for a human to bring it up to date, unless ci.rebase_behind is on. A genuinely idle/abandoned PR still parks at an approval gate after the timeout elapses. While that CI gate is parked, the daemon continues bounded read-only PR-state checks. If the PR is merged or closed externally, the stale gate completes automatically; an open, unknown, or temporarily unreachable PR remains parked for a user decision.

Set it to unlimited (none, off, and never are accepted aliases), 0, or any non-positive duration to disable this timeout. A run still ends when the PR is merged or closed, or at readiness under ci.release_after_checks_pass. You can cancel it with no-mistakes axi abort --run <id>.

Legacy alias: babysit_timeout.

step_quiet_warning

How long a running or fixing step can go without recorded step-log or native-agent lifecycle activity before AXI status marks the step as quiet.

Typestring (Go duration)
Default10m

Accepts any positive Go time.ParseDuration string: 30s, 5m, 1h, etc. Non-positive values are ignored and keep the default.

This is observability only. It does not cancel the step, change auto-fix behavior, or mark the run failed. AXI renders the quiet signal in the active_steps table as part of last_activity, for example quiet 12m3s ago: codex started pid=4242. For older active runs that do not yet have activity rows, AXI falls back to the step log file’s modification time.

agent_crash_retries

Opt-in automatic retries of an agent-crashed Review, Test, Document or Lint step in the same live run. Completed steps stay completed. Set agent_crash_retries: 1 to allow one additional attempt; the default 0 preserves the existing failure behavior.

Typeinteger
Range0–3
Default0 (disabled)

Agent process exits and agent invocation timeout cuts qualify, never a real finding, test verdict, configured-command failure, Git error, or cancellation. Typed terminal provider signals, including authentication/access-denial errors and quota exhaustion, stay terminal. Adapters that give no typed terminal signal (Pi, Grok) can have an auth or quota failure retried up to agent_crash_retries times before failing with the original diagnostic. Existing adapter and analyzer formatting retries run first; exhausted adapter-transient failures and Claude’s native structured-output retry exhaustion stay terminal. Each additional attempt must still produce a valid result; a crash is never a pass.

Eligible validation steps also pin their freshly resolved diff base across the live run: a later fetch that changes that base fails before invoking another agent, even if the run’s recorded previous-push SHA did not change. A full restart at Review establishes a new base pin.

Before retrying, the executor proves that the run and worktree head SHA, recorded base SHA, effective configuration, completed-step records/rounds and evidence-file hashes still match their pre-attempt snapshot. The worktree must be clean before and after the attempt, including untracked and ignored files. Missing or changed proof refuses the retry and fails normally: no in-run restart is attempted; start a fresh run for full validation from step 1. Partial edits, commits or evidence from a crashed attempt are never silently discarded or certified. The log records the agent_invocation retry or proof refusal; an exhausted retry still fails with its agent diagnostic.

A hang cut by the default invocation budget can qualify. A non-default agent timeout, or any still-working cap, disables timeout-based crash retries; the shipped timeout values count as unconfigured even when the generated config writes them explicitly. Process exits can still qualify. Test budget cuts that already park for an operator decision remain parked, not automatically retried.

Fix rounds, review-answer/coverage continuations, conflict resolution, custom gates, Intent and Push/PR/CI delivery are not replayed or retried. This budget is separate from auto_fix, is not replenished by approval rounds, and is disabled for the remainder of a run resumed after daemon recovery; a later agent crash fails that step normally. It does not continue a terminal run: axi retry is the separate manual continuation, using the shared agent_invocation cause and its own checkpoint proofs. Timeout cuts do not acquire that cause, and parser rejections remain terminal. It is global-only: repository config and environment variables cannot enable it.

max_concurrent_runs

Opt-in cap on how many pipeline runs execute at once on this machine. When the cap is reached, newly submitted runs wait in the queue in submission order with their run row pending, and start as running runs finish, fail, or are cancelled, instead of all starting at once and competing for host memory and CPU.

Typeinteger
Range0 or greater
Default0 (unlimited)

0 or unset means unlimited. An admitted run holds its slot until its executor finishes, fails, or is cancelled, including while parked at an approval gate. Recovered parked runs use the same cap and wait for a slot before resuming. Cancelling a queued run removes it from the queue without starting or resuming it.

Fresh queued runs do not survive a daemon restart and must be resubmitted. Recovered parked runs waiting for a slot remain recoverable across a clean shutdown. If the global configuration cannot be read, the daemon keeps the last successfully loaded cap. It is global-only: repository config cannot set it.

agent_timeout

Stall budget for one pipeline agent invocation that does not already have a more specific deadline. This is the default-by-construction budget: Document, Lint, Rebase conflict repair, PR drafting, CI auto-fix, and any future agent-spawning step are bounded even if they forget to install their own timer. Review still uses review_agent_timeout for each review or fix invocation, Test still uses test_agent_timeout per invocation, and Intent keeps its five-minute extraction cap; any existing deadline is honored rather than capped. A silent invocation is cancelled when this budget expires. An invocation that is still producing output at expiry, or whose agent subprocess is still running a child process it started after its last output, such as a test suite a tool call launched, continues only when agent_working_timeout is set. It may then continue until it goes quiet with no live child process for 10 minutes (the shipped step_quiet_warning default, fixed regardless of that setting; this budget itself when it is shorter) or until that cap, whichever comes first. With the cap unset, the turn stops at this budget. There is no hidden multiple of this budget. When the invocation is cancelled, it returns a timeout diagnostic instead of remaining active indefinitely. Most agent-driven mutation steps fail the run, CI auto-fix parks for a user decision, and PR drafting follows its existing agent-error fallback and continues with deterministic content. The CI step reference owns the approval behavior. A late successful return after cancellation is rejected, so post-agent commits and PR content cannot use work from a timed-out turn.

The diagnostic names which bound cut the invocation and how long it ran, and separately reports what activity was actually measured. With no still-working cap set it reads after 30m0s (silent budget; no still-working cap is set; ran 30m0s), which claims nothing about output or child processes because nothing checked them. With a cap set it reads after 30m0s (stall budget, then no recent output or live child process; ran 42m0s) for a turn that went idle, or at its 1h0m0s still-working cap (silent budget 30m0s; ran 1h0m0s) for a turn that reached the cap. Evidence resets whenever a retry or fallback starts a replacement attempt, including provider fallback, failed session resume, and OpenCode’s prompt-only structured-output fallback, so the diagnostic describes only the attempt that reached the deadline:

  • agent produced no output at all in 30m0s after its subprocess started (pid=1234) - the current attempt launched and then emitted nothing. Check that the agent CLI is authenticated and responsive.
  • agent last produced output 4s ago (312 observed) - the current attempt was working right up to cancellation. Set the still-working cap, raise it if it is already set, or split a request that is too large for one turn.
  • agent produced no output at all in 30m0s and never reported a subprocess start - the current attempt never reached a running agent process.

Output means anything observable: streamed assistant text, or raw bytes on the agent subprocess’s stdout or stderr. Subprocess bytes matter because an agent spends most of a long turn running tools rather than writing prose, so prose alone cannot tell a working agent from a wedged one. A live child process of the agent subprocess extends the budget too, because a long tool call writes nothing until it returns, but it is liveness rather than output and is never reported as the agent having produced anything. The agent’s child processes are sampled about once a second, and each output freezes a sample taken before it as the baseline; only a child missing from that baseline counts. A tool the agent launches right after announcing it, even in its very first output, therefore still extends the budget. Helpers it keeps alive for the whole turn, such as the ACP agent under acpx or stdio MCP servers, are in the baseline once a sample taken after they started precedes an output, so they cannot keep a hung turn alive past the stall budget. A helper started less than about a second before the agent’s first output, with no output after it, cannot be told apart from a tool that output announced, so it counts as work and can hold a hung turn open until the still-working cap. Agents that report no subprocess, and hosts where the process table cannot be read, get no such extension. step_quiet_warning remains a separate status-only signal; configuring it does not change the 10-minute quiet window that cancels a previously-working turn after the stall budget. Any substantive report from the agent adapter - for a native agent, its exit status and captured stderr - is appended to the diagnostic as agent reported: ...; credential-bearing URLs are redacted and the report is length-bounded before it can reach logs or findings. A bare context cancellation is omitted because it adds no evidence.

Typestring (Go duration)
Default30m

Accepts any positive Go time.ParseDuration string: 5m, 30m, 1h, etc. Non-positive values are rejected when loading the global config. Raise it when those turns routinely stay quiet longer than this budget. With agent_working_timeout unset, this budget also stops a turn that is still working, so set that cap when busy turns are cut here. It is global-only: repository config and environment variables cannot override it.

agent_working_timeout

Optional cap for one invocation that is still producing output, or waiting on a live child, after agent_timeout expires. Unset means no extension: the turn stops at agent_timeout, including when it is still working. Set, it is the absolute deadline for that still-working turn, not a multiple of the silent budget. The 10-minute quiet stop still cancels a turn that goes idle before the cap. The value must be at least agent_timeout. review_agent_working_timeout and test_agent_working_timeout are the same cap for Review and Test.

Typestring (Go duration)
Defaultunset

Accepts any positive Go time.ParseDuration string. Non-positive values are rejected when loading the global config. It is global-only.

review_agent_timeout

Stall budget for one Review-step agent invocation. The optional fixer gets the full configured budget, and its fresh, session-free independent rereviewer gets a new full budget of its own. Every later fixer and rereviewer does the same; no invocation inherits time spent by an earlier turn. A silent invocation is cancelled when this budget expires. A still-working invocation continues only when review_agent_working_timeout is set, under the same idle rule as agent_working_timeout. When the invocation is cancelled, the review agent fails the run with a diagnostic naming the bound that cut it instead of remaining active indefinitely. That diagnostic carries the same measured evidence and adapter report described under agent_timeout. A repository can tighten this value for itself with the trusted review.agent_timeout key; the smaller of the two applies, and a repository can never raise it.

Typestring (Go duration)
Default30m

Accepts any positive Go time.ParseDuration string: 5m, 30m, 1h, etc. Non-positive values are rejected when loading the global config. Raise it when reviews routinely stay quiet longer than this budget. With review_agent_working_timeout unset, this budget also stops a review that is still working, so set that cap when busy reviews are cut here. It bounds only the Review step, and no other step or environment variable overrides it.

review_agent_working_timeout

Optional still-working cap for one Review invocation. Unset means the turn stops at review_agent_timeout. Set, it is that turn’s absolute deadline, and it must be at least review_agent_timeout. The 10-minute quiet stop still applies.

Typestring (Go duration)
Defaultunset

It is global-only.

test_agent_timeout

Stall budget for one Test-step agent invocation. The budget covers the post-test evidence-gathering turn, and a Test-repair turn gets its own budget of the same length. A silent invocation is cancelled when this budget expires. A still-working invocation continues only when test_agent_working_timeout is set, so a targeted run that already needs most of this budget is not failed solely because the provider was slow. When the invocation is cancelled, the test agent parks for a decision with an ask-user finding rather than failing the run as a code defect. That finding carries the same measured evidence and adapter report described under agent_timeout. A late structured result from the expired turn is still not used as a successful Test pass. The park keeps the configured commands.test result from the same execution, so approving over a failing command is still recorded as a configured-command override. A cut fix round also keeps the findings of the gate it was answering, selected or not, and the last completed evidence turn’s verdict, so approving it is recorded against that verdict. A commit the timed-out agent already made is recorded locally for custody and is not pushed, unless an unfinished rebase or merge leaves only a partial HEAD. While the run worktree holds uncommitted changes or commits past the head the last completed evidence turn saw (before one completes, past the head the first cut measured from, which each later park carries forward and measures again), the park names them with the commands to inspect them and approval is refused, because the steps after Test would commit and publish them. Otherwise approving the park is a Test exception (passed-with-override), not a silent green pass. A fix response spends another budget: a repair turn runs only for selected findings other than the budget cut itself, then validation re-runs over whatever the cut left. Guidance you attach to the budget-cut finding itself (axi respond --instructions, or e in the TUI) is given to that re-run validation. You can also abort, raise this value, and retry.

Typestring (Go duration)
Default30m

Accepts any positive Go time.ParseDuration string: 5m, 30m, 1h, etc. Non-positive values are rejected when loading the global config. Raise it when targeted tests or evidence gathering routinely stay quiet longer than this budget. With test_agent_working_timeout unset, this budget also stops a Test turn that is still working, so set that cap when busy turns are cut here. The shipped default stays a silent bound and is not raised automatically. It bounds only the Test step, and no other step or environment variable overrides it.

test_agent_working_timeout

Optional still-working cap for one Test invocation. Unset means the turn stops at test_agent_timeout. Set, it is that turn’s absolute deadline, and it must be at least test_agent_timeout. The 10-minute quiet stop still applies.

Typestring (Go duration)
Defaultunset

It is global-only.

daemon_connect_timeout

Maximum time a CLI client waits for an existing daemon socket to accept a connection before failing instead of hanging. Guards against a daemon process that is alive but stuck or unresponsive.

Typestring (Go duration)
Default3s

Accepts any positive Go time.ParseDuration string. Overridable per-invocation with the NM_DAEMON_CONNECT_TIMEOUT environment variable; see Environment Variables.

branch_sync_remote_timeout

Maximum time guarded branch synchronization (sync, axi sync, and the TUI’s sync action) waits for each remote Git operation - ls-remote or fetch - before remote verification fails closed and synchronization is refused.

Typestring (Go duration)
Default60s

Accepts any positive Go time.ParseDuration string.

Raise this if your environment’s Git credential helper (for example gh auth git-credential, invoked by Git as a child process against a private remote) legitimately takes longer than the default - this is a real, non-outage latency characteristic that has been observed taking 19-22s in some environments, not a hang. It is a machine/environment setting, not a per-repository one: it is read only from global config and has no matching field in a repository’s .no-mistakes.yaml, so a pushed branch cannot widen or narrow how long the local service waits before failing closed. It never changes the fail-closed guarantee itself - a timeout or unknown remote state still always refuses synchronization without changing files or refs, whatever this value is set to.

gate_reconcile_interval

How often the daemon rechecks a parked approval gate while waiting for user approval. Today this applies to the CI step’s parked gate, which re-probes provider availability (including gh auth status) and clears the gate when the PR was merged or closed, and to a review gate parked on its reviewer’s own questions, which resumes the reviewer once none are open.

Typestring (Go duration)
Default2m

Accepts any positive Go time.ParseDuration string. Global-only: there is no matching field in a repository’s .no-mistakes.yaml.

gate_reconcile_timeout

Maximum wall time one parked approval-gate reconcile attempt may spend before the attempt stops, the gate stays parked, and the next interval wait begins. Covers host probes such as gh auth status that can hang without returning. The same bound applies to the live verification an approve response runs at a parked CI gate; a verification that times out counts as unverifiable, so it is refused while a ci.required_reviews requirement applies and otherwise recorded as an explicit override.

Typestring (Go duration)
Default30s

Accepts any positive Go time.ParseDuration string. Global-only: there is no matching field in a repository’s .no-mistakes.yaml. Raise this if a legitimate credential helper or network path routinely needs longer than the default for auth probes during reconcile. Timeout and interruption are reported distinctly from authentication failure; that distinction does not require raising this value.

log_level

Daemon log verbosity.

Typestring
Valuesdebug, info, warn, error
Defaultinfo

session_reuse

Per-run agent session reuse for the review loop’s fixer role.

Typebool
Defaulttrue

When enabled and every fixer that can serve the run supports native session resume (Claude or Grok via --resume, Codex via exec resume, Pi via --session <UUID>, Antigravity via --conversation <id>), each run keeps one durable fixer session across its review-fix turns. A configured later-round fixer that cannot resume therefore makes all fixer turns cold for that run; see later-round role overrides. Review turns - the initial full review and every full rereview - always run as fresh invocations regardless of this setting. They are also session-free, unless the run has a review conversation AND this setting is on, in which case one reviewer session spans exactly one review pass - the asking turn and the finalize turn that receives its answers - and never a code change; with session_reuse: false that finalize turn runs cold, which costs a re-read rather than the answers, because the finalize prompt is the complete review prompt plus the answers. Either way a rereview certifies fixes that implement the previous review turn’s findings, so it must never resume the session that prescribed them; cross-round review context travels only in the explicit sanitized round history. The fixer session is never lent to review turns, other pipeline steps stay session-isolated in their own cold invocations, and different runs never reuse identities. When resume is unavailable or fails, the fix turn falls back to a cold run or a fresh fixer session and the fallback is recorded in the local agent_invocations performance record. Pi emits per-invocation usage after a resume, unlike Codex’s cumulative session counters. Session identities are persisted only as minimum local resume metadata, never as prompts or transcripts; Pi’s own session directory retains its native transcript. Keep Pi’s session directory private, and keep any --session-dir or PI_CODING_AGENT_SESSION_DIR setting stable while a run is active so a daemon restart can find the fixer session. The daemon crash-recovery reference owns which parked gates can resume or reconcile after a restart. Set false to force every agent invocation cold.

quota_routing

Opt-in, quota-aware agent ordering at run start.

Typemap[string]{enabled, expected_run_length, read_timeout, quota_axi_path}
Defaultenabled: false (the feature is opt-in)

When enabled: true, no-mistakes reads one snapshot with the locally installed quota-axi --full --json at the start of each run and reorders the resolved agent list by quota evidence before the run picks its head agent. Explicit review_agents overrides do not use quota routing. Ordering follows these rules:

  • An agent with concrete proof of exhaustion - runway exhausted_now, or a known 0% remaining - is moved to the back of the list (it stays in the list, so the existing launch-failure fallback still has somewhere to go).
  • An agent whose runway is projected_exhaustion must have a reported usable runway greater than expected_run_length; otherwise it is treated like an exhausted one.
  • Runway through_reset passes.
  • Surviving agents with known applicable scopes and a spendPriority for each scope rank by the minimum of those priorities, highest first; ties keep your configured order.
  • An agent without proof of exhaustion whose applicable quota or spendPriority is unknown stays eligible but ranks below every ranked agent. Unknown candidates keep their configured order relative to each other.

Native claude and codex retain account, profile, and model-scope matching. All other agents, including Pi, use only provider-level all_models or all_products scopes for their declared provider. Vendor-specific and named-model scopes do not affect their routing. Without provider-wide evidence, quota is unknown: the agent stays eligible and retains its configured order among unknown candidates.

Each agent keeps its own agent_config model and effort: only the order changes. A missing, slow, or unreadable quota-axi keeps your configured order, logs the reason, and never blocks a run. The mid-run quota switch remains enabled in this case. Inspect the recorded outcome with no-mistakes axi status or no-mistakes stats. See local telemetry for storage and privacy.

Mid-run, a recognised quota-exhaustion error advances to the next agent in the chosen order with a fresh session, dropping any resumed session. This can happen once per agent, and later invocations do not return to earlier agents. If no successor remains, the error is returned. The existing agent-unavailable fallback is unchanged. Daemon recovery reuses the recorded order and last recorded switch without reading another snapshot, even if the global opt-in setting has since changed.

Subkeys:

  • enabled (bool, default false): the opt-in switch.
  • expected_run_length (positive duration, default 90m): the runway floor. A projected exhaustion that outlasts this window does not demote the agent; the value is an expectation for ordering, never a run cancel.
  • read_timeout (positive duration, default 15s): bound on the single quota-axi read at run start. Quota-axi may delegate an expired session’s renewal to the vendor CLI that owns it, so a slow read waits up to this long before the run proceeds on the configured order.
  • quota_axi_path (string, default quota-axi on PATH): the executable to run.

quota_routing is global-only: it decides which of this machine’s credential-bearing agents a run spends, so a quota_routing block in a repository’s .no-mistakes.yaml is a config error rather than an ignored key.

Provider mapping: claude and codex map to their same-named quota-axi providers by default. Any agent can declare quota_provider under agent_config to select a provider explicitly. An unmapped non-Pi agent ranks as unknown quota. A pi without an explicit provider disables reordering for the whole run with one warning: the configured order stands, the mid-run switch stays off, and the run record says why. Model names never infer a provider. For Pi with quota_provider: codex, the model prefix selects the published credential key (codex-native/… reads codex-home; openai-codex-work/… reads that Pi credential). For quota_provider: claude, explicit profile:… and claude-swap:… prefixes select that published profile. Other providers use their default account; a Pi provider prefix such as kimi-coding is not an account key. Routing checks published accountKeys membership in both quota schemas. A named credential missing from the report stays unknown rather than borrowing another account’s evidence.

worktree_roots

Where a repository’s pipeline run worktrees are created.

Typemap[string]string
KeysAbsolute registered checkout paths (what you ran no-mistakes init in)
ValuesAbsolute directory paths
DefaultEmpty (<NM_HOME>/worktrees/<repo id>/<run id>)

By default a run worktree is created under NM_HOME, outside every checkout, so directory-scoped toolchain configuration (mise, direnv) never reaches it: those tools resolve their settings by path ancestry. Point a checkout at a directory of your own and its runs are created at <value>/<run id> instead, inheriting whatever that directory configures. A relative value is rejected at load time, because the daemon that reads it has an unrelated working directory.

The directory stays yours. no-mistakes never enumerates it: the only directories it touches there are the exact ones its own run records name, which is what startup cleanup, orphan-process reaping, and no-mistakes eject all go by. Anything else in it - your files, your scratch checkouts, and a directory that merely looks like a run worktree but no run created - is never read, never swept, never signalled, and never removed.

Each checkout needs its own root: two entries pointing at the same directory, two spellings of one checkout, or a root equal to its checkout are rejected at load time, and init --worktree-root refuses a directory another checkout already claims.

Two more values are refused at daemon startup, because they cannot work:

  • Inside NM_HOME. It collides with no-mistakes’ own state - under worktrees a run worktree is indistinguishable from the per-repository directories the default placement owns, and under logs a run’s worktree is its log directory, so removing the worktree at run end would take the run’s logs with it.
  • Inside any checkout. The run worktree is then an untracked directory in that checkout while the run executes, so the checkout is dirty and branch synchronization refuses to move it until the run finishes. That holds whether the victim is the checkout whose own runs land there or an unrelated gated one, so the daemon refuses a root inside any repository it has registered. Registering a repository around an already configured root is refused by no-mistakes init itself, so you can still place that checkout elsewhere or repoint the entry; anything that reaches the configuration another way is caught at the next daemon start.

Changing an entry affects new runs only. Each run records the directory it was created in, so editing, adding, or removing an entry never retargets a run that already exists - resuming it after a restart, reading its diff, cleaning it up, reaping processes left standing in it, and ejecting its repository all keep using the directory that run actually has, including after you point the checkout somewhere else.

The key is matched against the checkout path recorded at init. After moving a checkout, re-run no-mistakes init from the new path and update the key; a key that matches no registered repository is reported in the daemon log at startup and otherwise does nothing.

no-mistakes init --worktree-root <dir> prints the exact entry to add for the checkout you are initializing. The global config is hand-maintained, so init never rewrites it for you.

worktree

Retention for leftover run-worktree directories under the default <NM_HOME>/worktrees/<repo id>/<run id> tree.

Typeobject
FieldTypeDefaultDescription
worktree.retentionstring24hHow long a leftover run worktree survives; unlimited/none/off/never or a non-positive duration disables the bound
worktree.max_runsint20How many leftover worktree directories survive regardless of age; 0 disables the bound

A run’s own worktree is already removed the instant its pipeline finishes, so this budget is a safety net rather than the normal path: it only ever governs the directory left behind by a git worktree remove failure (for example a vendored .git nested somewhere under a large node_modules tree) or a protected-path refusal that later became removable. Without it, a leftover like that survived indefinitely on a long-running daemon that never restarts, since the crash-recovery sweep that also reclaims it (see the daemon’s worktree cleanup) runs only at startup.

This reap runs after every finished run and again at daemon startup, the same cadence test.evidence.retention uses. Only the default <NM_HOME>/worktrees tree is bounded; a checkout you placed with worktree_roots is your own directory, and only the directories no-mistakes’ own run records name there are ever touched, per that section’s rules.

Global-only, for the same reason test.evidence’s local storage fields are: it governs this machine’s local disk, so a repository does not get to set the retention budget for a directory every repository on the machine shares.

auto_fix

Maximum follow-up auto-fix attempts per step. Set a step to 0 to disable the follow-up auto-fix loop, so 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 then pause for approval instead of starting another automatic fix loop.

Typeobject
FieldTypeDefaultDescription
auto_fix.rebaseint3Rebase conflict auto-fix attempts
auto_fix.reviewint0Review finding auto-fix attempts
auto_fix.testint3Test failure auto-fix attempts
auto_fix.documentint3Not used by the automatic document pass
auto_fix.lintint3Lint issue auto-fix attempts
auto_fix.ciint3CI auto-fix attempts for CI failures, plus merge conflicts on GitHub, GitLab, Forgejo, Azure DevOps, Cursor Origin, and provider plugins declaring mergeable_state

Legacy alias: auto_fix.babysit.

These are global defaults. Per-repo config can override individual steps.

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.

Typeint
Default0
Range0 to 5; values outside it are clamped
ci:
rerun_transient: 0

Each rerun is another provider-side workflow run billed to the repository being contributed to. Set 0 here to never spend someone else’s CI minutes; this is the only place to make that choice for a repository whose default branch you do not control.

The per-repo ci.rerun_transient overrides this value and owns the classification, the trust boundary, and every case that skips the rerun.

ci.required_reviews

The operator-level fallback for ci.required_reviews. That reference owns supported reviewer profiles, completion evidence, and the trust boundary. Defaults to []; the trusted repository list overrides it, including an explicit empty list.

ci.revalidate_repairs

The operator-level fallback for ci.revalidate_repairs, whose per-repository reference owns the repair-delivery semantics, safety rationale, and trust boundary.

Typebool
Defaultfalse
ci:
revalidate_repairs: false

A value in the trusted repository config overrides this global value in both directions: an explicit repository true enables revalidation when this is false, and an explicit repository false disables opt-in revalidation when this is true. When the trusted repository config omits the key, this global value applies.

ci.review_bot_comments

The operator-level fallback for ci.review_bot_comments, whose per-repository reference owns the semantics and the trust boundary.

Typestring (on_failure or always)
Defaulton_failure
ci:
review_bot_comments: always

A value in the trusted repository config overrides this global value. An unrecognized value fails the config rather than falling back to the default.

ci.rebase_behind

The operator-level fallback for ci.rebase_behind, whose per-repository reference owns the semantics, the cost, and the trust boundary.

Typebool
Defaultfalse
ci:
rebase_behind: true

A value in the trusted repository config overrides this global value in both directions. When the trusted repository config omits the key, this global value applies.

ci.carry_review_on_replay

The operator-level fallback for ci.carry_review_on_replay, whose per-repository reference owns the pure-replay proof, its limits, and the trust boundary.

Typebool
Defaultfalse
ci:
carry_review_on_replay: true

A value in the trusted repository config overrides this global value in both directions. When the trusted repository config omits the key, this global value applies.

ci.release_after_checks_pass

The operator-level fallback for ci.release_after_checks_pass, whose per-repository reference owns the semantics, the cost, and the trust boundary.

Typebool
Defaultfalse
ci:
release_after_checks_pass: true

A value in the trusted repository config overrides this global value in both directions. When the trusted repository config omits the key, this global value applies.

rebase.strategy

The operator-level default for rebase.strategy, whose per-repository reference owns the semantics, the trade-off, and the trust boundary.

Typestring (rebase or merge)
Defaultrebase
rebase:
strategy: merge

A value in the trusted repository config overrides this global value in both directions. When the trusted repository config omits the key, this global value applies. An unrecognized value fails the config closed rather than falling back to the default, so a typo cannot quietly keep rewriting history a maintainer asked to stop rewriting.

review.path_instructions

Machine-local review guidance that applies to every repository this machine gates. Use it for house rules you hold in every repository, including ones you do not control and so cannot commit a review.path_instructions to. For a rule that holds in one repository only, use a matching repository_overrides entry instead.

Typeobject[] with path (string) and instructions (string, multiline)
DefaultEmpty
review:
path_instructions:
- path: "**/*.vue"
instructions: |
Repeated instances of a component are driven from a computed, not stacked v-ifs.

Entries match, render, and validate exactly like the repository field, whose reference owns those rules. They only add guidance: the repository’s own trusted rules always apply alongside them, and nothing here can remove or replace one. The reviewer receives each source as its own section, in this order: this global list, then the matching repository_overrides entry’s list, then the repository’s trusted list. The two machine-local headings say the rules come from the operator’s global config and not from the repository, so a machine-local rule never reads as the repository’s own. The step log names the source of every rule it applied or skipped.

The entry and byte limits apply to the combined set from all three sources, because they share one review prompt. This global list together with each repository_overrides list is checked when the config loads. The repository’s trusted list changes independently, so the combined set is checked again when each run starts and when a run is recovered after a daemon restart: a run whose combined rules exceed a limit fails before any step runs or resumes, with an error naming each source’s entry count, rather than silently dropping a rule. Shorten or remove your machine-local entries to fix it.

Only path_instructions is accepted under this block. review.conversation stays a repository decision, because an open question parks the gate. Changes apply to the next run, and to a run recovered after a daemon restart, which re-reads this file.

commit.fix_message

Template for the subject of commits created by 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 for remaining uncommitted changes, with {{.Step}} as push and {{.Summary}} as apply agent fixes; at the default, that commit keeps its no-mistakes: apply agent fixes subject.

Typestring
Defaultno-mistakes({{.Step}}): {{.Summary}}

The template supports literal text and three Go-style placeholders:

VariableValue
{{.Step}}Pipeline step name, such as review, test, document, lint, ci, push, or gate.test.mutation-budget
{{.Summary}}Sanitized one-line summary returned by the fix agent, or the step’s deterministic fallback summary
{{.Branch}}Normalized branch name, or the identifier captured and optionally transformed by commit.branch_pattern and commit.branch_replacement

The value must be a valid UTF-8 template that renders to a non-empty, single-line commit subject. The template source is limited to 1,024 bytes and 16 placeholders. The fix-agent summary and final rendered subject are each limited to 4,096 bytes. Before rendering, no-mistakes predicts the subject size from the validated literal text and placeholders, then rejects oversized output without allocating the expanded message. Template functions, control actions, named templates, unknown placeholders, malformed syntax, control characters, unsafe Unicode format characters, and Unicode line or paragraph separators cause configuration loading to fail. The blocked format set includes every Unicode Bidi_Control code point plus U+00AD, U+180E, U+200B, U+2060 through U+2064, the deprecated bidi controls U+206A through U+206F, U+FEFF, U+FFF9 through U+FFFB, and Unicode tag characters in U+E0000 through U+E007F. Legitimate U+200C zero-width non-joiner and U+200D zero-width joiner text shaping remains allowed. The final rendered subject is validated again, so unsafe characters in an agent-provided summary are also rejected. Each fix prompt tells the agent how many characters the summary may use so the subject stays within 72: 72 minus the rendered text around the summary, divided by the number of times the template uses {{.Summary}}, with a floor of 20. The limit is guidance only; no-mistakes does not truncate or reject a longer subject. The setting does not change commit subjects created by the Rebase step or the evidence-branch commit; see test.evidence for the latter. A per-repo commit.fix_message value overrides this global setting.

commit.branch_pattern

Optional regular expression for extracting the value exposed as {{.Branch}} to commit and PR title templates.

Typestring regular expression
DefaultUnset, so {{.Branch}} is the normalized full branch name

The expression is limited to 1,024 bytes, must be valid UTF-8, must exclude the same control and unsafe Unicode format characters as commit.fix_message, and must compile with exactly one capture group. Without commit.branch_replacement, that capture group becomes {{.Branch}}, so ([A-Z]+-[0-9]+) extracts PROJ-123 from feature/PROJ-123-add-widget. For example, this global configuration renders PROJ-123: preserve legacy drafts from branch PROJ/123:

commit:
branch_pattern: '^PROJ/([0-9]+)$'
branch_replacement: 'PROJ-${1}'
fix_message: "{{.Branch}}: {{.Summary}}"

When a template uses {{.Branch}} and the pattern does not find a non-empty identifier, rendering fails safely instead of producing an empty prefix. A per-repo commit.branch_pattern value overrides this global setting.

commit.branch_replacement

Optional expression that adds literal text around the branch pattern’s capture group before exposing it as {{.Branch}}. Set it under global commit for the machine-wide default, or under a matching repository_overrides entry for one remote. It is not available in a repository’s .no-mistakes.yaml.

Typestring replacement expression
DefaultUnset, so the capture group is used unchanged

Use exactly one ${1} reference to insert the capture group; other dollar syntax is rejected. Under global commit, the replacement must be configured with commit.branch_pattern in that block. Under repository_overrides, pair it with commit.branch_pattern in the same remote entry. It is limited to 1,024 bytes, must be valid UTF-8, and must exclude the same control and unsafe Unicode format characters as commit.fix_message. Malformed replacement syntax fails configuration loading with an actionable error. The expanded identifier is subject to the existing UTF-8, control-character, unsafe-Unicode, and rendered-subject validation. A commit.branch_pattern in .no-mistakes.yaml takes precedence and clears any inherited machine-wide replacement, including one from a matching repository override, so a replacement cannot be applied to a different pattern.

commit.trailers

Git trailers appended to each commit made from a single agent invocation’s changes, naming the agent and model that produced them.

Typelist of string templates
DefaultUnset, so commits carry no trailers

Each entry renders to one trailer line. It supports literal text and two Go-style placeholders:

VariableValue
{{.Agent}}The agent that actually ran the invocation; with an agent fallback list, the one that answered, not the first configured
{{.Model}}The model the agent reported serving the invocation, or unknown when it reports none

For example, this renders Assisted-by: no-mistakes:codex:gpt-5.5 on a fix made by Codex after a fallback from Claude:

commit:
trailers:
- "Co-Authored-By: no-mistakes {{.Agent}} <noreply@example.com>"
- "Assisted-by: no-mistakes:{{.Agent}}:{{.Model}}"

{{.Agent}} and {{.Model}} come from agent output, so each is cut to its first whitespace-separated token, reduced to letters, digits, and -_.:/, and limited to 64 bytes; a value with nothing left renders as unknown. Claude, Codex, Grok, and Pi report the model they served; other agents render unknown. Every entry must render to a Key: value line that git recognizes as a trailer. The key must be literal: an entry starts with its full Key: prefix as plain text, and placeholders are allowed only in the value after it, so {{.Agent}}-assisted: yes is rejected. Entries are limited to 1,024 bytes and 16 placeholders, the list to 16 entries, and the same template restrictions and unsafe-character rules as commit.fix_message apply. The 1,024-byte limit also applies to the rendered line, checked when configuration loads with every placeholder at its 64-byte maximum, so an entry that loads cannot overflow at commit time. An invalid entry fails configuration loading, and a render failure at commit time leaves the changes unstaged.

Trailers are added to Review, Test, Document, and Lint fix commits, operator-authorized repository gate repairs, and CI repair commits. Commits that no single invocation produced get none rather than a guessed agent: the Push step’s catch-all commit, a CI repair retried after a protected-path refusal, and rebase or merge commits that an agent writes itself. A per-repo commit.trailers list or a matching repository_overrides entry replaces this list rather than extending it; an empty list clears it.

pr.appendix

Machine-wide default for the generated PR evidence appendix:

pr:
appendix: collapsed # full | collapsed | minimal

Precedence: a non-empty trusted repository pr.appendix, then a matching repository_overrides value, then this global value, then built-in full. An unset or empty value inherits the next layer. The pushed branch cannot choose the appendix mode, even with allow_repo_commands: true.

All modes retain the pipeline attestation. See the repository pr.appendix reference for rendering behavior and provider caveats. Invalid modes fail config loading. pr.template and pr.publish_intent are not machine-wide settings.

repository_overrides

Machine-local settings scoped to one repository by remote host and full repository path. This lets one machine add checks, lower command scheduling priority, add review, documentation, and live-validation guidance, or apply ticket conventions without adding settings to that repository. Remote hosts are matched case-insensitively. HTTP, HTTPS, SSH, and Git-protocol URLs, plus scp-style remotes, are accepted; the transport scheme is not part of the match. A URL’s scheme-default port (80, 443, 22, or 9418 for HTTP, HTTPS, SSH, or Git) matches an omitted port; non-default ports remain distinct. IPv6 addresses are canonicalized, with bracket boundaries preserved so a port cannot be confused with address text. For github.com, gitlab.com, and bitbucket.org, repository paths are also matched case-insensitively and without a trailing .git, across equivalent HTTPS, SSH URL, and scp-style remotes. On every other host, repository path case and a trailing .git are significant. GitLab subgroup paths are preserved. On other SSH hosts, rooted paths (host:/... or ssh://host/...) remain distinct from home-relative scp paths (host:...).

repository_overrides:
https://github.com/acme/widget.git:
commit:
branch_pattern: '([A-Z]+-[0-9]+)'
fix_message: '{{.Branch}}: {{.Summary}}'
pr:
title_format: '{{.Branch}}: {{.Title}}'

Formatting fields are commit.branch_pattern, commit.branch_replacement, commit.fix_message, commit.trailers, and pr.title_format; each retains the same fail-closed validation as its global or repository-config equivalent. A commit.branch_replacement must be paired with commit.branch_pattern in the same override. Precedence for these formatting fields is explicit: .no-mistakes.yaml wins for every field it sets, then a matching machine-local override, then the plain global value, then the built-in default. As with the global replacement, a repository commit.branch_pattern replaces the matching machine-local pattern and clears its replacement. Repositories matching no block keep existing global and built-in behavior.

Machine-local PR publication defaults

A matching entry can select a repository’s existing PR template without committing .no-mistakes.yaml:

repository_overrides:
https://github.com/acme/widget.git:
pr:
template: .github/pull_request_template.md
appendix: collapsed

pr.template selects a repository-relative file, never local template contents. It uses the same path and file validation as the repository setting, and its bytes are read only from the pinned trusted default-branch tree, never from the pushed branch or worktree. pr.appendix accepts full, collapsed, or minimal and can be set with or without pr.template; it uses the same appendix and attestation behavior as the repository setting. When template mode is active, author-edited narrative is preserved on later updates. For pr.template, a non-empty trusted repository value wins over the matching machine-local value. For appendix inheritance, see pr.appendix precedence. pr.template is available only under repository_overrides, not as a machine-wide PR setting. pr.publish_intent remains trusted-repository-only.

Machine-local review, documentation, and test guidance

A matching entry can add review rules, documentation policy, and a live-validation runbook for that one repository, without committing anything to it:

repository_overrides:
https://gitlab.example.com/group/app-one.git:
review:
path_instructions:
- path: "**/*.cs"
instructions: |
Sync wording is always "sync from <upstream>": it is a one-way overwrite, never a merge.
document:
instructions: |
Configuration keys are owned by docs/reference/config.md.
test:
instructions: |
Never install, launch, or test on a physical device; drive the emulator only.

review.path_instructions behaves like the global list: its rules render in their own labeled section after the global rules and before the repository’s trusted rules, and they count toward the same combined limits. document.instructions is added to the document step’s prompt in a labeled section before the repository’s trusted document.instructions, and like that field it augments the built-in placement policy and cannot weaken it. test.instructions is added to the Test step’s repair and evidence prompts in a labeled section before the repository’s trusted test.instructions runbook. All three are additive only: the repository’s trusted values still apply in full, and a pushed branch can supply none of them. Under review only path_instructions is accepted, under document only instructions, and under test only instructions; settings that could weaken a gate, such as no_ci, allow_repo_commands, or pr.base_branch, are not accepted here. Changes apply to the next run, and to a run recovered after a daemon restart, which re-reads this file.

Eval replay cases store no remote URL, so a replay does not apply a matching entry’s review, documentation, or test guidance.

Machine-local commands

A matching commands block supplements the repository’s trusted commands; it never changes their strings or removes them. Repository command selection still comes from the trusted default branch, or the pushed branch only with trusted allow_repo_commands: true. Only the operator’s global config can supply these local settings, never a repository’s .no-mistakes.yaml. With no matching command override, execution remains unchanged.

repository_overrides:
https://github.com/acme/widget.git:
commands:
test:
additional:
- /opt/local-checks/widget-smoke
nice: 10
lint:
additional:
- /opt/local-checks/widget-policy
prepare:
nice: 10
FieldSupported commandsMeaning
additionaltest, lintOrdered list of separate shell checks added after the repository check; every check must succeed
niceprepare, test, lint, formatPOSIX niceness adjustment from 0 to 19; 0 leaves scheduling unchanged

Test runs the committed command first, then each added command in a separate shell, retaining a failure from either source even when another check succeeds. Test still performs its unconditional agent-driven end-user scenarios afterwards. Lint runs additional checks after the existing lint duty, including agent-driven lint when commands.lint is empty. An added check’s failure parks the step rather than silently passing; existing explicit approval rules still apply. Its finding names that machine-local check and its exit code, and never attributes the failure to the committed command, including when the committed command is empty. additional is refused for preparation and formatting, because those commands are not independent check gates. Replacement command strings, command, replace, skip, per-command env, unknown command names, empty additional checks, and niceness outside 0 through 19 are configuration errors.

Overrides are always declared, never silent: whenever a command runs under any of these settings, its step log states machine-local overrides applied to commands.<name>: followed by the niceness and the added checks, once per step rather than per check, and Test passes the same declaration to its agent for the testing summary. These settings are scoped to configured shell commands and their local checks, not agents, built-in Git operations, forge commands, or repository-declared extra gates.

There is no per-command environment override. Toolchain paths (such as PATH) and parallelism settings (such as GOMAXPROCS) come from the operator’s own environment, which the daemon captures at startup and passes to every configured command; Environment the daemon sees owns where to set them.

nice: 10 invokes the POSIX nice -n 10 utility around the command shell, adding ten to its inherited niceness, not setting an absolute priority. Positive niceness is refused on Windows; set resource limits in the operator’s own environment there. A missing nice utility fails the command rather than silently ignoring the request.

Before executing an opted-in run, no-mistakes records the full resolved configuration in <NM_HOME>/logs/<run-id>/command-config.ndjson, including the unchanged team command strings, added checks, niceness, trusted-config SHA, and tool build. It also records the values configured commands inherit from the daemon’s environment for PATH, GOMAXPROCS, MAKEFLAGS, CARGO_BUILD_JOBS, and CMAKE_BUILD_PARALLEL_LEVEL, omitting any that are unset; these values appear only in this file, never in step logs, agent prompts, findings, or the PR. This record is independent of optional eval capture. Recovery appends a new snapshot of the configuration it resolves, including removal of a previously active local override. A snapshot write failure stops execution before checks run. The file is private local evidence, restricted to owner-only permissions on POSIX on every write (including a file left from an earlier snapshot) and excluded from PR and test-evidence publication.

intent

Transcript-based user-intent extraction settings. When enabled and no intent was supplied directly for the run, no-mistakes can read recent local agent transcripts, match the session that produced the change, summarize the author’s intent, and pass that summary to rebase, review, test, document, lint, CI auto-fix, repository gate repair, and PR prompts. For publication of the generated Intent section, see pr.publish_intent.

Typeobject
FieldTypeDefaultDescription
intent.enabledbooltrueEnable transcript-based intent extraction
intent.thresholdfloat0.2Minimum raw match score for selecting a transcript session
intent.slack_daysint3Extra days to look back before the change window
intent.disabled_readersstring[]EmptyTranscript readers to disable
intent.publish_intentbooltruePublish the generated Intent section on PR bodies by default

Valid disabled_readers values are claude, codex, opencode, rovodev, pi, and copilot.

intent.publish_intent: false is a global, operator-side default that keeps the generated ## Intent section out of the PR body for runs started without an explicit override. It is the caller-side counterpart of the repository’s trusted pr.publish_intent: both are tighten-only, the repository’s trusted policy remains the ceiling a caller can never exceed, and review, test, document, lint, and CI auto-fix prompts keep the full intent. Under the caller-side omission the PR-drafting turns receive no intent text at all and draft from the diff and commit messages only; the intent is withheld from them, never scanned out of their output. A run records the folded decision (the axi run --no-publish-intent flag OR this global default) at start; reruns inherit it, and a mid-run config change never re-publishes. This field is global-only: a pushed branch’s .no-mistakes.yaml cannot express it.

The match score is the share of matching files mentioned in a transcript session; deleted files are ignored when the diff also contains non-deleted changes. All-deletion diffs still match against the deleted changed files. Mentioning extra files does not reduce the score. For multi-file diffs, no-mistakes still requires at least two overlapping files and an effective minimum score of 0.5. Partial matches older than 24 hours are rejected unless their raw score is at least 0.8. If exactly one accepted candidate has a raw score of at least 0.85, that decisive candidate wins before recency ranking. Otherwise, accepted candidates are ranked by confidence, which combines the raw score with a small recency boost, with ties going to the most recent matching session, and ambiguous accepted candidates may be disambiguated by the configured pipeline agent.

test.evidence

Test-step evidence storage settings. By default, evidence artifacts are written to <NM_HOME>/evidence/<run-id>. On GitHub.com/GHEC, supported image and video artifacts are also uploaded when the PR is rendered; see attach_media below.

Typeobject
FieldTypeDefaultDescription
test.evidence.store_in_repoboolfalsePublish test evidence artifacts to the repository’s orphan evidence branch
test.evidence.attach_mediabooltrueUpload image and video evidence to GitHub user-attachments when the PR is rendered
test.evidence.dirstring.no-mistakes/evidenceDirectory prefix inside the evidence branch
test.evidence.branchstringno-mistakes/evidenceName of the orphan evidence branch
test.evidence.commit_messagestringno-mistakes: evidence for {{.Branch}} (run {{.RunID}})Subject template for evidence-branch commits
test.evidence.local_rootstring<NM_HOME>/evidenceAbsolute directory where run evidence is written on local disk
test.evidence.retentionstring336h (14 days)How long a run’s evidence survives; unlimited/none/off/never or a non-positive duration disables the bound
test.evidence.max_runsint200How many run directories survive regardless of age; 0 disables the bound

The test step always collects evidence outside the worktree, so artifacts never enter the branch under validation. On GitHub.com and GitHub Enterprise Cloud, image and video artifacts that pass GitHub’s attach rules (png, jpg, jpeg, gif, webp, svg, mp4, mov, webm; images at most 10 MiB and videos at most 100 MiB) are uploaded to GitHub user-attachments when the PR body is rendered, unless attach_media is false. Setting attach_media: false disables uploads even when store_in_repo: true; evidence-branch publication and its commit-pinned links remain enabled. Uploads need the raw GitHub token, which the PR step reads once per PR render with gh auth token; when that read fails, the step logs one line and skips every remaining upload in that render instead of asking again per file. If your gh sits behind a credential vault or disclosure gate that prompts before it releases the token, set attach_media: false so the PR step never asks for it. The testing section embeds the returned image markdown or bare video URL so remote reviewers can open the media. Upload is fail-closed: any error, unsupported type, oversize file, GitHub Enterprise Server, non-GitHub forge, or GitHub App/Actions token keeps today’s rendering (a commit-pinned evidence-branch link if store_in_repo published, otherwise a local path) rather than a dead attachment URL. Text artifacts stay inlined as they are today. When store_in_repo is true for a GitHub repository, the PR step copies that directory onto branch under <dir>/<branch-slug> in the code branch’s push-target repository (the fork when fork routing is configured), pushes it, and links the artifacts from the pull request body. Published text files get the same home-directory redaction as the PR title and body, so a path under the operator’s home is committed with that part rewritten to ~. Before that, the run’s worktree root, and any path into another run worktree under <NM_HOME>/worktrees/<repo-id>/<run-id>, is rewritten to {run-worktree} (a bare <NM_HOME>/worktrees or <NM_HOME>/worktrees/<repo-id> to {worktrees}), because the repo id is a hash of the local checkout path and NM_HOME may sit outside the home directory. Binary and visual artifacts are published as written, and the local evidence files are never changed. When both attach_media and store_in_repo apply, the testing section carries the user-attachments embed in addition to the commit-pinned git link. The branch is an orphan: it shares no history with your code branches, so evidence never reaches the default branch. Links use the evidence commit rather than the branch, so they keep resolving after later runs. Branch slashes become nested directories, unsafe branch characters are replaced, and an empty branch slug falls back to the run ID. branch must be a valid Git branch name; an invalid value fails the config with the offending key and value. commit_message supports literal text and two placeholders: {{.Branch}} (the code branch name) and {{.RunID}} (the run ID). It follows the same template restrictions, size limits, and unsafe-character rules as commit.fix_message; an invalid template fails configuration loading, and a subject that fails validation at publish time leaves the evidence unpublished. The publisher never force-pushes. It appends to the fetched evidence-branch tip with a fast-forward push, retries one lost race, and refuses to use the run branch, default branch, or an existing branch whose tip lacks the .no-mistakes-evidence marker. Publication is also refused when the remote cannot be read or pushed, an artifact exceeds 64 MiB, a run exceeds 500 files or 256 MiB, or another writer wins the retry. The PR body then keeps its local rendering instead of adding links that would not resolve. Evidence-branch publication currently supports GitHub links only. On other providers, no evidence branch is pushed and the PR body keeps its local rendering. Enabling this pushes a branch to your remote, so pick a branch name your CI workflows do not build.

Local storage and cleanup

Evidence lives under the app root rather than the system temp directory. On Linux the daemon runs from a service unit that does not export TMPDIR, so the old temp-directory default resolved to the shared /tmp, which current Ubuntu mounts as a RAM-backed tmpfs. The app root is disk backed on macOS, Linux, and Windows alike.

no-mistakes reaps its recorded run directories itself rather than relying on an operating-system temp cleaner. Unrecognized directories under a custom local_root are left untouched.

  • A finished run that produced no artifacts leaves nothing behind.
  • Recorded run directories older than retention are removed.
  • Whatever recorded run evidence survives is trimmed to max_runs, oldest first.
  • A run that is still pending or running is never touched.

Reaping runs after each finished run and again at daemon startup. An upgraded daemon also drains the pre-relocation directory in the system temp directory under the same rules; nothing is migrated, because absolute paths recorded in older pull request bodies name the old location.

local_root must be an absolute path outside <NM_HOME>/worktrees; a relative or managed-worktree path fails daemon startup and prevents new or recovered runs from starting. Because retention bounds how long a PR body’s local artifact links keep resolving, raise it rather than lowering it if your reviews run long.

The publication fields are global defaults. Repo config can override store_in_repo, attach_media, dir, and commit_message; it can override branch only through the trusted default-branch copy. local_root, retention, and max_runs are global-only: a repository does not get to name a filesystem path this machine’s daemon writes to, or set the retention budget for a directory every repository on the machine shares.

test.evidence.retention and test.evidence.max_runs also bound <NM_HOME>/logs/<run-id> (per-run step logs), reaped on the same cadence rather than through a second config surface for the same kind of per-run diagnostic artifact.

eval

Local review-evaluation corpus settings for no-mistakes eval.

Typeobject
FieldTypeDefaultDescription
eval.capture_provenancebooltrueRecord the exact commit and configuration inputs a replay needs
eval.auto_capturebooltrueCollect eligible review cases and fixed CI false negatives automatically
eval.max_casesint200Retention target for automatic collection; 0 keeps every case
eval.diversified_sizeint32Cap on the official gold-only diversified set; 0 is one gold case per stratum

capture_provenance is what makes a review pass replayable at all. It is recorded when the round is written and cannot be added afterwards, because the pinned configuration is a point-in-time snapshot, so a run reviewed with it off can never be captured later.

auto_capture collects without any command: when an eligible run finishes, its decided review rounds become cases and fixed ci-check and ci-review-bot findings become Review false negatives. It does nothing while capture_provenance is off. Collection runs after the pipeline has already reported its outcome and can never change it; a failure is logged and nothing else. The Evaluation toolkit owns eligibility and labeling details.

max_cases sets the retention target enforced after automatic collection. When it is exceeded the oldest unprotected cases are dropped first. A case with a replay in progress or recorded candidate replays is protected, so the corpus can remain above the target rather than invalidate a comparison you have spent tokens on. Cases from the same repository share one local object pool, so a case costs its own records plus the objects its commits introduced rather than a copy of the repository.

diversified_size caps the official gold-only eval set used by eval run --cases diversified. Selection is stratified and pinned; unlabeled cases never fill it. 0 keeps one gold case per stratum with no Hamilton bound. Corpus retention (max_cases) and this official-set cap are different knobs.

These are operator settings for this machine’s local disk, so they are global-only: an eval block in a repository’s .no-mistakes.yaml is ignored. Corpus storage stays under <NM_HOME>/eval and no-mistakes never uploads it; replay still sends code to the selected agent’s configured model provider as described in the Evaluation toolkit.

providers.github.draft_pull_requests

Open pull requests created on GitHub as drafts (gh pr create --draft).

Typebool
Defaultfalse

Only affects PR creation; existing PRs are not toggled between draft and ready. GitHub only — ignored for other providers. This is a global default. Per-repo config can override it via providers.github.draft_pull_requests.

providers.gitlab.draft_pull_requests

Open merge requests created on GitLab as drafts (glab mr create --draft).

Typebool
Defaultfalse

Only affects MR creation; existing MRs are not toggled between draft and ready. GitLab only — ignored for other providers. This is a global default. Per-repo config can override it via providers.gitlab.draft_pull_requests.

providers.bitbucket.draft_pull_requests

Open pull requests created on Bitbucket Cloud as drafts ("draft": true in the create-PR API request).

Typebool
Defaultfalse

Only affects PR creation; existing PRs are not toggled between draft and ready. Bitbucket only — ignored for other providers. This is a global default. Per-repo config can override it via providers.bitbucket.draft_pull_requests.

providers.azuredevops.draft_pull_requests

Open pull requests created on Azure DevOps as drafts (az repos pr create --draft true).

Typebool
Defaultfalse

Only affects PR creation; existing PRs are not toggled between draft and ready. Azure DevOps only — ignored for other providers. This is a global default. Per-repo config can override it via providers.azuredevops.draft_pull_requests.

providers.origin.draft_pull_requests

Open pull requests created on Cursor Origin as drafts (origin pr create --status draft). When false (the default), no-mistakes passes --status open because the Origin CLI otherwise defaults to draft.

Typebool
Defaultfalse

Only affects PR creation; existing PRs are not toggled between draft and ready. Cursor Origin only — ignored for other providers. This is a global default. Per-repo config can override it via providers.origin.draft_pull_requests.

Environment variables

See Environment Variables for NM_HOME, NM_DAEMON_CONNECT_TIMEOUT, Forgejo host and token settings, Bitbucket Cloud credentials, and update-check suppression.