Src/Content/Docs/Guides/Agents
---
title: Choosing an Agent
description: Supported AI agents, how to pick one, and how they integrate.
---
no-mistakes is pipeline-agent-agnostic by design: the gate should mean the same thing regardless of which supported agent backend you prefer.
It is not runner-free.
Every validation run requires a supported native agent binary, the agent: cursor ACP alias, or an explicit acp:<target> through acpx.
The default agent: auto setting picks the first supported native agent or ACP alias available on your system.
The coding agent that calls no-mistakes axi drives approval gates, but it does not automatically become the pipeline agent that performs review, evidence testing, documentation, combined documentation-and-lint housekeeping, or fixes.
Those jobs run in the daemon's disposable worktree through the configured pipeline agent.
A validation-step agent inspects, fixes, and returns only its assigned phase; delivery requirements in user intent remain acceptance context, but the outer executor alone performs the other validation, push, PR, and CI phases.
If that step attempts pipeline control, no-mistakes returns error.code: nested_gate_context; the agent must return control to the outer executor, while read-only no-mistakes axi status, no-mistakes axi logs, help, and no-mistakes doctor remain available.
The agent is responsible for the parts of the gate that benefit from judgment:
code review, evidence-oriented test validation, test or lint detection when you
have not configured explicit commands, auto-fixing, and setup-wizard suggestions
when you leave prompts blank.
Pipeline agent prompts also include a workspace-boundary preamble.
It tells agents to keep intentional source, project, user-data, and system file writes inside the disposable worktree, avoid mutating system state such as Homebrew packages, /Applications, or global tool config, and treat that boundary as prompt steering rather than true enforcement.
The only intentional out-of-worktree write it allows is test evidence under the run's managed evidence directory when a testing prompt asks for it.
Incidental temp or cache writes from normal development tools are still allowed.
Testing prompts also ask agents to remove transient working-tree artifacts they created, such as downloaded models, caches, build outputs, large binaries, or generated data directories, before reporting completion.
How to choose quickly
- Leave agent: auto if one good agent is already installed and you do not need repo-specific behavior.
- Set a repo-level agent override when one codebase clearly works better with a different tool.
- Use an ordered fallback list when you prefer one agent but want no-mistakes to try another if the first process is unavailable.
- Set explicit commands.lint and a targeted commands.test if you want deterministic local baseline command execution regardless of agent choice; leave commands.test empty for agent-selected smallest relevant checks. Do not configure a complete-suite walk as local Test - remote CI owns broad regression.
That last point matters: the agent helps fill in gaps, but explicit repo
commands are still the strongest way to make the baseline gate predictable.
When user intent is available, the test step may still invoke the configured agent after commands.test succeeds to gather evidence that demonstrates the change.
That testing invocation is expected to leave only intentional source or test-file changes in the worktree, while preserving requested evidence files under the dedicated evidence directory.
That directory is always outside the worktree and is reaped by no-mistakes on a bounded retention schedule; GitHub repos can opt into publishing it to an orphan evidence branch with test.evidence.store_in_repo. See test.evidence for its location and cleanup.
Supported agents
| Agent | Binary | Protocol |
| --- | --- | --- |
| Claude | claude | Subprocess per invocation, JSONL streaming |
| Codex | codex | Subprocess per invocation, JSONL events |
| Rovo Dev | acli | Persistent HTTP server, SSE streaming |
| OpenCode | opencode | Persistent HTTP server, SSE streaming |
| Pi | pi | Subprocess per invocation, JSONL events |
| Copilot | copilot | Subprocess per invocation, JSONL events |
| Cursor | cursor-agent + acpx | cursor-agent acp through the ACP bridge |
| ACP target | acpx | Optional user-installed ACP bridge |
Runner requirements
A complete gate never degrades silently when its configured pipeline agent is unavailable.
The daemon resolves the effective agent before creating pipeline step records, and the run fails immediately with setup guidance if the configured binary cannot run.
This refusal also applies when deterministic test or lint commands are configured because review and documentation always require agent judgment, while rebase, PR, and CI paths may need an agent to resolve conflicts, generate content, or fix failures.
| Surface or capability | Works without a runnable pipeline agent? | Behavior |
| --- | ---: | --- |
| Install, init, daemon lifecycle, status, runs, and doctor | Yes | Local setup and diagnostics remain available. doctor reports that gate validation is unavailable. |
| Start or rerun a validation gate | No | The run fails before any pipeline step starts. |
| Review | No | Requires agent judgment and structured findings. |
| Test with commands.test | No, as part of a full gate | The command is deterministic, but the gate refuses before steps start rather than presenting command-only validation as a complete pass. |
| Test without commands.test, or evidence validation with user intent | No | Requires the agent to discover checks and gather end-to-end evidence. |
| Document | No | Requires the agent to discover and update documentation gaps. |
| Lint with commands.lint | No, as part of a full gate | The command is deterministic, but the full gate still requires an agent. |
| Lint without commands.lint and all fix rounds | No | The document step performs the initial combined housekeeping pass, and an agent is still needed for fallback assessment or code changes. |
| Push, PR, and CI as part of a gate | No | They run only after the required validation steps, and PR or CI paths may invoke the agent themselves. |
Antigravity and Gemini setups
Running the gate from Antigravity or another Gemini-based coding environment does not make that calling model available to the daemon automatically.
Choose one of these supported setups:
1. Install any supported native agent CLI and leave agent: auto, or select it explicitly in ~/.no-mistakes/config.yaml.
2. Install both cursor-agent and acpx, then leave agent: auto or select agent: cursor.
3. Install acpx, confirm that the Gemini ACP target works locally, and configure agent: acp:gemini.
~/.no-mistakes/config.yaml
agent: acp:geminiOptional when acpx is not on PATH.
acpx_path: C:\path\to\acpx.exeRun no-mistakes doctor afterward and look for a successful gate validation line.
Doctor checks the global agent configuration; each run performs the authoritative check again after applying any trusted repository-level agent override.
If the calling environment exposes neither a supported native CLI nor a working ACP target, it can still inspect and respond to existing AXI state, but it cannot start an honest validation gate by itself.
Setting the agent
Global default
~/.no-mistakes/config.yaml
agent: autoPer-repo override
.no-mistakes.yaml
agent: codexRepo config takes precedence over global config.
Ordered fallback list
~/.no-mistakes/config.yaml or .no-mistakes.yaml
agent: [codex, claude]Optional ACP target
If you install acpx separately, you can opt into any ACP target with the acp: prefix, for example agent: acp:gemini.agent: auto probes native agents and first-class ACP aliases (such as cursor), and never auto-selects arbitrary acp:<target> entries.
The agent field reference owns the exact resolution order, fallback-list filtering and retry semantics, and the failure behavior when no entry is runnable.
Where agent choice matters most
Changing agents most directly affects:
- review quality and tone
- test evidence collection, plus test and lint detection when commands are not configured
- how good auto-fix attempts are for your stack
- branch name and commit subject suggestions in the setup wizard
It does not change the pipeline order or the meaning of a passed gate.
Driving no-mistakes as an agent
The primary way to put a change through the gate from inside a coding agent is the /no-mistakes skill.
A skill-aware tool like Claude Code supports two invocation modes.
Use bare /no-mistakes to validate existing committed work.
Use /no-mistakes <task> to have the agent first do the task, commit only that task's changes on a feature branch, then run the pipeline with the task text as --intent.
In both modes, it resolves low-risk findings on its own and stops to relay anything that needs your decision.
no-mistakes init installs that skill at user level: ~/.claude/skills/no-mistakes/SKILL.md for Claude Code and ~/.agents/skills/no-mistakes/SKILL.md for Codex, OpenCode, Rovo Dev, and Pi.
One install makes the skill available to every supported agent in every repo, without committing tool-generated files to any repo.
If your home directory consolidates .claude and .agents with symlinks, init follows the links and keeps the skill reachable from both logical paths.
Re-run no-mistakes init after an upgrade to refresh that skill, including overwriting stale SKILL.md content from an older binary.
Older versions vendored the skill into each initialized repo's .claude/skills and .agents/skills; those copies are no longer needed, and init prints a notice when it finds one so you can remove it.
The skill drives no-mistakes axi, a non-interactive command surface that prints TOON to stdout and progress to stderr.
When CI is ready - either its registered checks are green or the trusted default-branch config declares no_ci: true with no registered checks - but the PR is still open, axi run and axi respond return outcome: checks-passed with a help line pointing at the PR instead of waiting for a human merge. An empty check result without that declaration is not ready; see the CI step reference for the readiness rules.
That is a successful agent stopping point: report that the PR is ready and ask the user to review and merge it.
Successful outcomes also instruct the agent to summarize the run for the user.
When the pipeline applied fixes, successful outcomes include a fixes table listing each fix so the agent can acknowledge what it missed and the user can review them.
If that PR later falls behind the default branch or hits a merge conflict - commonly because another PR merged first - the agent runs no command and must never hand-rebase.
The CI monitor stays live in the background after checks pass, and when it sees an actual conflict it rebases onto the base, resolves it, and re-pushes the branch itself, so no agent or user action is needed.
A PR that is merely behind but still clean needs nothing either, since the platform merges it.
The one exception is when that monitor is no longer running - the PR was closed, the run was aborted or superseded, it idle-timed-out, or its auto-fix attempts were exhausted - in which case the agent recovers with no-mistakes rerun, which cancels the stale monitor and re-runs the full pipeline including a deterministic rebase step.
The agent must not use no-mistakes axi run to refresh a still-active PR: after checks-passed it reattaches to the running monitor with HEAD unchanged and returns the monitor output without rebasing.
In task-first mode, if the repo is on the default branch, the skill tells the agent to create a feature branch before committing because the gate validates committed history on a non-default branch.
The agent should inspect git status before changing or committing anything, preserve unrelated pre-existing uncommitted changes, and commit only the changes that belong to the user's task.
Agents can also call no-mistakes axi directly:
no-mistakes axi run --intent "the user's goal"
no-mistakes axi status
no-mistakes axi sync --check
no-mistakes axi sync
no-mistakes axi sync --recover
no-mistakes axi respond --action approve
no-mistakes axi logs --step review --full
no-mistakes axi abort
no-mistakes axi abort --run <id>Before any post-pipeline local commit or fresh run, read branch_sync.
Only when its structured next_action.code is sync, run no-mistakes axi sync first.
When next_action.code is recover_custody - a terminal run left unpublished pipeline commits preserved in the local gate - run no-mistakes axi sync --recover to return custody, or no-mistakes rerun to resume validating the preserved head.
A branch_sync.state of user_owned means the run went terminal before changing the submitted head and cancellation released the branch: it is immediately usable and needs no sync action.
When next_action.code is continue_active_run, run the reported command and keep driving the active run.
If synchronization is blocked, process that state instead of improvising reset, stash, merge, rebase, force, or branch replacement.
Then commit follow-up work on top so every pipeline fix commit remains in the branch.
The full driving protocol - how to read the home view and gate: objects, when to respond, fix, approve, or relay ask-user findings, and how to interpret axi status fields like awaiting_agent and active_steps - is owned by the skill itself and by the live axi output.
Each axi response carries version-matched help lines for its state, and no-mistakes axi run --help and no-mistakes axi respond --help describe the loop authoritatively for the installed binary, so agents driving a gate never need this page open.
The CLI reference documents each axi command and output field for humans.
Binary resolution
When the daemon is running through a managed service, its PATH comes from your login shell environment on macOS and Linux plus common user, Homebrew, and system binary directories; on Windows it reuses the current process environment.
If native agent discovery does not resolve the binary you expect, check ~/.no-mistakes/logs/daemon.log and set an explicit override; Environment the daemon sees owns the full resolution story.
Five global config fields tune resolution and invocation, and the Global Config Reference owns each one:
- agent_path_override - custom binary paths per native agent, plus the default native binary-name table.
- agent_args_override - extra CLI flags per native agent for model selection, service tier, reasoning depth, or permission mode, including the reserved-flag rules and smart defaults. Keep it global-only; it reflects your local agent setup rather than repo policy.
- acpx_path - the bridge binary path for explicit ACP targets and first-class ACP aliases.
- acp_registry_overrides - raw ACP target commands, including replacements for alias defaults such as cursor-agent acp, plus their availability-probing rules.
- agent - the auto resolution order and ordered fallback-list semantics.
Review session reuse
With the default session_reuse: true, Claude and Codex keep one durable review-fixer session per run, and resume failures fall back to a fresh fixer session instead of skipping the fix turn.
Review turns always run in fresh, session-free invocations: a rereview certifies fixes that implement the previous review turn's findings, so it must never resume the session that prescribed them.
The session_reuse field reference owns the exact reuse, fallback, privacy, and restart-recovery semantics.
Agent interface
All agents implement the same interface. Each invocation receives:
- Prompt - the task description (review this diff, fix these findings, etc.), prefixed during pipeline runs with the workspace-boundary steering described above
- CWD - the worktree directory
- Environment - the daemon environment plus non-interactive Git overrides (GIT_EDITOR=true, GIT_SEQUENCE_EDITOR=true, and GIT_TERMINAL_PROMPT=0) so agent-invoked Git commands do not hang on editors or credential prompts
- JSONSchema - optional structured output schema for typed responses
- OnChunk - callback for streaming text output to the TUI
- OnLifecycle - callback for native subprocess start, exit, and retry activity that is recorded in step logs and AXI active-step status
- Session - optional no-mistakes-owned native session identity for review-fixer reuse
- Purpose - local performance label for the pipeline duty served
Each invocation returns:
- Output - structured JSON output; native structured responses are returned as-is, while text-parsed fallbacks are validated before return and may use null for optional fields
- Text - raw text output
- Usage - token counts (input, output, cache read, cache creation)
- SessionID and Resumed - the adapter-native session identity and whether this invocation resumed it, when supported
- Model and Provider - adapter-reported serving metadata when available
One-shot subprocess agents (Claude, Codex, Pi, Copilot CLI, and acpx) are invocation-scoped.
After no-mistakes starts one, it terminates any remaining child processes when the invocation exits, fails, or is cancelled, so agent-spawned test workers, build watchers, and dev servers do not survive the step.
Step logs record their process lifecycle, including start and exit lines with the PID, and AXI status exposes that PID while the subprocess is still active.
Persistent server agents (Rovo Dev and OpenCode) use their managed server lifecycle instead.
Transient API and network failures are retried up to three times with exponential backoff. Retry messages are recorded as lifecycle activity for native subprocess agents, falling back to the streaming text path for direct callers that do not supply OnLifecycle.
Intent extraction
When an agent starts a run through no-mistakes axi run --intent, no-mistakes uses that supplied intent verbatim as authoritative acceptance criteria and skips transcript-based inference, even if intent.enabled is false.
Review checks the diff against those criteria, and a change that removes required behavior or adds forbidden behavior becomes an ask-user finding instead of being resolved automatically.
Otherwise, when intent.enabled is true, no-mistakes reads recent local transcripts from Claude Code, Codex, OpenCode, Rovo Dev, Pi, and the GitHub Copilot CLI during the intent pipeline step.
It matches sessions against non-deleted changed files when present, falls back to all changed files for all-deletion diffs, summarizes the likely author intent with the configured pipeline agent, includes that summary as an untrusted, low-confidence hint in rebase fixes, review checks and fixes, test detection, evidence validation, and fixes, lint detection and fixes, documentation checks and fixes, CI auto-fixes, and PR prompts, and renders it in generated PR descriptions.
Transcript readers collect user and assistant text messages but exclude tool call output.
They read Claude Code transcripts from ~/.claude/projects, Codex metadata from ~/.codex/state_*.sqlite plus referenced rollout files, OpenCode messages from $XDG_DATA_HOME/opencode/opencode.db or ~/.local/share/opencode/opencode.db, Rovo Dev sessions from ~/.rovodev/sessions, Pi transcripts from ~/.pi/agent/sessions, and GitHub Copilot CLI sessions from ~/.copilot/session-state.
Sessions are eligible when they come from the same working directory or an equivalent Git checkout with the same common Git directory or normalized remote URL.
ACP transcripts are not currently read for intent extraction.
When deterministic matching leaves multiple plausible sessions, no-mistakes may ask the configured pipeline agent to choose among them using the matching file paths and sanitized transcript packet files.
The selected transcript text is then sent to the configured pipeline agent for summarization during the intent step, so intent extraction may incur additional agent or API invocations.
Before disambiguation or summarization, no-mistakes excludes tool output, redacts likely secrets, strips common prompt-control markers, and clamps long transcripts while preserving the beginning and end.
no-mistakes stores derived intent summaries and matching metadata in ~/.no-mistakes/state.sqlite, including the source, session ID, and match score on each run plus cached summaries for matching transcript sessions.
It does not store raw transcript text in its database.
The step logs accepted candidate match diagnostics, then logs the matched source, score, and sanitized inferred intent when a transcript matches.
Use intent.disabled_readers to disable specific transcript sources, or set intent.enabled: false to opt out entirely.
Claude
Spawns a claude subprocess for each invocation with --output-format stream-json. The print-mode user prompt is sent as text on stdin rather than placed in the process arguments. By default it also adds --dangerously-skip-permissions, unless you already set your own Claude permission flag through agent_args_override. Reads JSONL events from stdout. Supports native structured output via --json-schema.
For review-fixer reuse, Claude starts a stream-json session and resumes it with claude -p --resume <id>.
Codex
Spawns a codex subprocess for each invocation with exec --json. When structured output is requested, no-mistakes also writes a normalized schema file and passes it with --output-schema. By default it also adds --dangerously-bypass-approvals-and-sandbox, unless you already set your own Codex approval or sandbox flag through agent_args_override. Reads JSONL events. Structured output is returned from the final agent_message text, with fallback parsing that accepts JSON fences, inline fence markers, or a final bare JSON object after prose, then validates the result against the normalized schema.
Codex model and config overrides, such as -m gpt-5.4, -c service_tier="priority", or -c model_reasoning_effort="low", belong in global agent_args_override.codex.
For review-fixer reuse, Codex resumes the reported thread with codex exec resume <id> <prompt>.
That resume command has a narrower flag surface than codex exec, so a resume that rejects an override falls back to a fresh fixer session rather than skipping the fix turn.
Rovo Dev
Starts a persistent HTTP server (acli rovodev serve) on first use and reuses it across invocations. If a reused server refuses a connection, no-mistakes discards it and retries with a fresh server. Any agent_args_override.rovodev flags are inserted before no-mistakes' managed serve flags. Communicates via REST API and SSE streaming. Each invocation creates a session, sends the prompt, streams results, then deletes the session. Structured output is handled by injecting schema instructions into a system prompt, then parsing the final text with fallback parsing that accepts JSON fences, inline fence markers, or a final bare JSON object after prose, and validates the result against the requested schema while allowing null for optional fields.
OpenCode
Starts a persistent HTTP server (opencode serve) on first use and reuses it across invocations. If a reused server refuses a connection, no-mistakes discards it and retries with a fresh server. Any agent_args_override.opencode flags are inserted before no-mistakes' managed serve flags. Similar session lifecycle to Rovo Dev: create session, send message, stream SSE events until idle, delete session. Supports json_schema format in the message request for structured output, with retryCount: 2 so the model gets a second chance to emit a structured response. When opencode reports info.error.name = "StructuredOutputError" (the model did not call the StructuredOutput tool after those retries), no-mistakes surfaces a clean error including the retry count rather than falling through to text-parsing the streamed reasoning prose. When native structured output is genuinely absent, it falls back to parsing the final text with the same JSON fence and bare-object fallback, validating that fallback result against the requested schema while allowing null for optional fields.
Pi
Spawns a pi subprocess for each invocation with --mode json --no-session.
See agent_args_override for Pi override precedence.
Reads JSONL events from stdout and streams incremental text deltas to the TUI.
When structured output is requested, no-mistakes injects the JSON schema into the prompt and validates the final text response.
Copilot CLI
Spawns a copilot subprocess for each invocation with -p <prompt> --output-format json.
It also adds --no-color and --no-ask-user so the run is non-interactive, plus --allow-all-tools (required for non-interactive mode) unless you already set your own Copilot permission flag through agent_args_override.
Any agent_args_override.copilot flags are inserted before no-mistakes' managed flags, so user choices such as --model or --effort take effect.
Reads JSONL events from stdout, streaming incremental assistant.message_delta text to the TUI and capturing the final assistant.message content.
The Copilot CLI has no output-schema flag, so when structured output is requested no-mistakes injects the JSON schema into the prompt and validates the final text response with the same JSON fence and bare-object fallback used by Pi and Rovo Dev.
ACP aliases
ACP aliases are first-class agent names that resolve to ACP targets.agent: cursor is the first alias: it is shorthand for the cursor ACP target with the default raw command cursor-agent acp, not a separate native backend.agent: acp:cursor uses that same default command, so either spelling works without an acp_registry_overrides.cursor entry.
Because aliases still run through acpx, they use acpx_path for the bridge binary and share the same ACP prompt and structured-output behavior as agent: acp:<target>.
Unlike arbitrary acp:<target> entries, aliases may participate in agent: auto when their availability checks pass.
The Global Config Reference owns ACP availability, bridge-path, command-override, and equivalent-spelling deduplication rules.
ACP via acpx
ACP support is optional and requires a separately installed acpx binary.
Use agent: acp:<target> to run a target known to acpx, for example agent: acp:gemini.
When the target matches a first-class alias such as acp:cursor, no-mistakes supplies that alias' default raw command.
Configure custom target commands in the Global Config Reference.
no-mistakes invokes acpx with JSON output, approve-all permissions, denied non-interactive permission prompts, and the repo worktree as --cwd.
Structured output is handled by appending the requested JSON schema to the prompt and validating the final assistant text.
Checking agent availability
Run no-mistakes doctor to inspect individual native and ACP runner binaries and to check the effective global agent configuration:
$ no-mistakes doctor
✓ git
✓ gh
✓ data directory
✓ database
✓ daemon running
✓ claude
– codex (not found)
– rovodev (not found)
– opencode (not found)
– pi (not found)
– copilot (not found)
– acpx (not found)
– cursor (not found (cursor-agent, acpx))
✓ gate validation claude is runnable✓ = available, – = not found (optional), ✗ = problem detected.
The standalone acpx and cursor rows inspect the default binary names.
The gate validation line is the decisive result: when the configured global runner is unavailable, doctor fails because a complete gate cannot validate without it.
See the Global Config Reference for ACP availability and probing behavior.
Every new validation run resolves its effective agent again after applying any trusted repository-level override.
---
Src/Content/Docs/Guides/Configuration
---
title: Configuration
description: Global and per-repo configuration options.
---
Configuration is optional. Without any config files, no-mistakes defaults toagent: auto, which picks the first supported native agent or ACP alias available on your system,
with sensible defaults for everything else.
The goal is not to make you configure a mini CI system. The default path should
work. Config exists for the parts that genuinely vary by machine or repo:
- which agent or ordered fallback list you prefer
- which test or lint commands are the canonical ones for this repo
- which extra review rules apply to which paths
- where test evidence artifacts should be stored
- how aggressive the auto-fix loop should be
- which subject template pipeline-generated fix commits should use
- how soon AXI should call an active step quiet
- whether the review loop reuses supported native agent sessions
- whether no-mistakes should infer intent from recent local agent transcripts
Config is split across two files:
| File | Scope | Full field reference |
| ---------------------------- | ----------------------------- | ------------------------------------------------------------- |
| ~/.no-mistakes/config.yaml | Global defaults for all repos | Global Config Reference |
| <repo>/.no-mistakes.yaml | Per-repo overrides | Repo Config Reference |
Set NM_HOME to relocate the global config directory (the global file becomes $NM_HOME/config.yaml).
Bitbucket Cloud credentials come from environment variables rather than config files.
For Azure DevOps, authenticate the az CLI with either az devops login or AZURE_DEVOPS_EXT_PAT for non-interactive daemon auth; see Environment Variables.
How to think about config
- Global config is for your machine-level defaults.
- Repo config is for codebase-specific behavior that should travel with the repo.
In practice, most teams should keep personal preferences global and repo policy
local.
What to configure first
If you are not sure where to start, configure these in this order:
1. Set commands.lint (and a targeted commands.test only when you want a deterministic local baseline - not a full CI suite) so the gate runs the exact local checks your repo expects.
2. Override agent per repo only when one codebase clearly works better with a different tool or fallback order.
3. Tune auto_fix after you have seen how much automation you actually want.
Everything else can usually wait.
The reference pages own each field's syntax, defaults, and exact semantics.
The rest of this page covers only the cross-cutting rules that involve both files at once.
Precedence
- Repo config overrides global config field by field: repo agent replaces the global agent (including a full ordered fallback list), while auto_fix, ci, commit, intent, and the repository-scoped test.evidence fields overlay individual fields and fall through to the global default for anything unset (intent.disabled_readers adds to the globally disabled readers instead of replacing them). Local evidence location and retention are machine-wide and remain global-only; the Global Config Reference owns the exact boundary.
- agent_path_override, agent_args_override, acpx_path, acp_registry_overrides, ci_timeout, daemon_connect_timeout, step_quiet_warning, log_level, and session_reuse are global-only fields.
- commands, ignore_patterns, document.instructions, review.path_instructions, allow_repo_commands, and disable_project_settings are repo-only fields. By default, commands and agent are read from the trusted default branch; a trusted allow_repo_commands: true opt-in instead honors their pushed-branch values. The other gate-control fields, including review.path_instructions and the repo ci overlay, always come from the trusted default branch. See the Repo Config Reference security note.
- no-mistakes reloads global config while setting up each run, so edits made before starting a run apply to it. For repeatable profiles (for example fast versus deep Codex settings), use separately initialized NM_HOME roots; NM_HOME moves all no-mistakes state, not just config.
House rules for part of the tree
Most review guidance belongs in the repository's own agent instructions, which every gate agent already reads. Use review.path_instructions for the rules that apply to only part of the tree: each entry pairs a path glob with guidance, and the review step appends only the entries whose glob matches a file the change actually touched, each labelled with the path and files it was selected for. A branch that matches nothing, or a repo with nothing configured, gets the review prompt it would get without the setting.
These blocks steer a gate agent, so they are read from your default branch rather than from the branch being reviewed, and allow_repo_commands does not change that. Commit them to the default branch before expecting a run to honor them. The Repo Config Reference owns the syntax, the glob rules, the size limits, and the exact trust semantics.
Explicit commands versus agent detection
Explicit commands.test and commands.lint give you deterministic local baseline behavior, while leaving either empty asks the configured agent to fill the gap: empty commands.test has the agent select the smallest relevant tests under the targeted-validation contract (broad regression stays in remote CI), and empty commands.lint folds lint into the document step's combined housekeeping pass.
An empty commands.format runs no separate formatter, so configure it explicitly when the push step must format agent changes.
Either way, available user intent can trigger an evidence-oriented agent follow-up after a successful test baseline. Evidence stays in no-mistakes-managed local storage unless a supported provider publishes it to an orphan evidence branch through test.evidence.store_in_repo; the Global Config Reference owns its location, cleanup, provider support, and fail-closed behavior.
The Repo Config Reference owns the exact per-command semantics (including that commands.test is targeted, not CI-parity), command process lifetime, and the ignore_patterns match rules.
Before a new validation gate starts, its effective agent configuration must resolve to a runnable native agent or ACP runner; otherwise the gate fails before its first pipeline step, even when explicit commands are configured.
Run no-mistakes doctor to check the global runner, and see Choosing an Agent for how agent selection and fallback lists behave.
---
Src/Content/Docs/Guides/Provider Integration
---
title: Provider Integration
description: Set up GitHub, GitLab, Bitbucket Cloud, or Azure DevOps for PR creation and CI monitoring.
---
The PR and CI steps need to talk to your git host. Four hosts are supported:
GitHub, GitLab, Bitbucket Cloud (bitbucket.org), and Azure DevOps
(dev.azure.com and legacy *.visualstudio.com). Everything else
short-circuits the PR and CI steps with skipped.
Provider integration is optional for the local gate. You only need it for the
steps that happen after validation: opening or updating the PR, watching hosted
CI, and fixing remote-only failures.
Without any provider setup, no-mistakes still gives you the local gate:
- rebase
- review
- test
- document
- lint
- push through normal Git transport
What you do not get is PR automation and CI monitoring.
What each step needs
| Step | GitHub | GitLab | Bitbucket Cloud | Azure DevOps |
|---|---|---|---|---|
| PR (create/update) | gh CLI, authenticated | glab CLI, authenticated | NO_MISTAKES_BITBUCKET_EMAIL + NO_MISTAKES_BITBUCKET_API_TOKEN | az CLI + azure-devops extension, authenticated |
| CI (polling, auto-fix) | gh CLI | glab CLI | same env vars | az CLI |
| Merge conflict auto-fix | gh CLI | glab CLI | not supported | az CLI |
| Mergeability polling | gh CLI | glab CLI | not supported | az CLI |
| Failed check log fetching | gh CLI | glab CLI | supported | not yet |
| Cancelled-check rerun | gh CLI | not supported | not supported | not supported |
What changes when provider wiring is present
Once the host is wired up, no-mistakes can keep owning the branch after it
pushes to the configured target:
- create or update the PR automatically
- keep polling hosted CI until the PR is merged, closed, declined, or the configured ci_timeout idle window elapses
- fetch failing job logs for the CI auto-fix loop
- on GitHub, GitLab, and Azure DevOps, watch mergeability and fix merge conflicts when possible
GitHub
Install the GitHub CLI and authenticate:
macOS
brew install ghLinux
see https://github.com/cli/cli/blob/trunk/docs/install_linux.md
gh auth login
Verify:
gh auth statusno-mistakes doctor also checks for gh availability.
For PR and workflow-run commands, no-mistakes passes the repository slug from the recorded upstream remote or PR URL to gh, so daemon-run commands do not depend on the daemon's current working directory.
What you get:
- PR creation and update on pushes
- CI check polling with exponential backoff (30s → 60s → 120s) until the PR is merged, closed, or the configured ci_timeout idle window elapses
- Failed job log fetching (gh run view --log-failed) for the CI auto-fix step
- PR mergeability polling, and agent-driven resolution when the provider reports an actual merge conflict
GitHub fork contributions
Fork routing is available for GitHub when you need to push branches to your fork but open PRs against the parent repository.
Keep origin pointed at the parent repository, then initialize with your fork URL:
git remote set-url origin [email protected]:parent-owner/repo.git
no-mistakes init --fork-url [email protected]:your-user/repo.gitWith this setup, the push and CI auto-fix push steps update the fork, while the PR and CI steps stay scoped to the parent repository.
The GitHub PR step opens PRs with a fork-qualified head such as your-user:feature-branch.
Re-running no-mistakes init later preserves the stored fork URL unless you pass a new --fork-url.
Fork routing currently requires both origin and --fork-url to be GitHub remotes with owner/repo paths.
GitLab and Bitbucket fork MR/PR routing are not implemented yet; if a legacy or manually edited repo record has fork_url set for those providers, PR creation skips instead of opening an unsafe self PR.
GitLab
Install the GitLab CLI and authenticate:
macOS
brew install glabLinux
see https://gitlab.com/gitlab-org/cli
glab auth login
What you get:
- PR (merge request) creation and update
- CI pipeline status polling until the merge request is merged, closed, or the configured ci_timeout idle window elapses
- Failed job trace fetching (glab ci trace) for the CI auto-fix step
- Merge-conflict polling and auto-fix, same as GitHub
Bitbucket Cloud
Bitbucket Cloud uses the REST API directly rather than a provider CLI. Set two environment variables (and optionally a third):
export [email protected]
export NO_MISTAKES_BITBUCKET_API_TOKEN=your-api-tokenOptional: override the API base URL
export NO_MISTAKES_BITBUCKET_API_BASE_URL=https://api.bitbucket.org/2.0Get an API token from Bitbucket account settings.
What you get:
- PR creation and update
- CI pipeline status polling until the PR is merged, declined, or the configured ci_timeout idle window elapses
- Failed pipeline step log fetching for the CI auto-fix step
What you don't get (yet):
- PR mergeability polling
- Merge-conflict auto-fix
These are GitHub, GitLab, and Azure DevOps only right now.
Azure DevOps
Azure DevOps uses the Azure CLI with the azure-devops extension. Install both
and authenticate:
macOS
brew install azure-cliLinux / Windows
see https://learn.microsoft.com/en-us/cli/azure/install-azure-cli
az extension add --name azure-devops
Authenticate with a Personal Access Token (Code: Read & Write, Pull Request
Threads, Build: Read). Either run az devops login and paste the PAT, or
export it for non-interactive use:
export AZURE_DEVOPS_EXT_PAT=your-patCreate a PAT from User settings → Personal access tokens in your Azure
DevOps organization. The daemon inherits AZURE_DEVOPS_EXT_PAT from the
environment it runs under, the same way the GitHub backend inherits gh auth.
Both https://dev.azure.com/{org}/{project}/_git/{repo} and the legacyhttps://{org}.visualstudio.com/{project}/_git/{repo} remotes are detected, as
well as their SSH forms ([email protected]:v3/...).
What you get:
- PR creation and update (az repos pr create / update); Azure DevOps caps
PR descriptions at 4000 characters, so the pipeline builds the body within
that budget and applies a final truncation backstop with a visible marker.
See the PR step reference for
section composition and truncation behavior.
- CI status polling - Azure branch policy evaluations (build validation and
status checks) are read via az repos pr policy list until the PR is
completed, abandoned, or the configured ci_timeout idle window elapses
- Merge-conflict polling and auto-fix from the PR's mergeStatus
What you don't get (yet):
- Failed check log fetching for the CI auto-fix step (the az CLI has no
first-class build-log command)
- Fork PR routing (same as GitLab and Bitbucket)
Self-hosted GitHub/GitLab
Self-hosted GitHub Enterprise and self-hosted GitLab instances work through the same gh and glab CLIs. Authenticate the CLI against your instance (gh auth login --hostname your-ghe.example.com, glab auth login --hostname gitlab.example.com) and no-mistakes will route through the CLI as usual.
Self-hosted GitHub Enterprise
GitHub Enterprise Server is detected the same way github.com is, as long as the host is one gh is authenticated against.
When the upstream hostname is not github.com, no-mistakes consults gh's configured hosts (hosts.yml, honoring GH_CONFIG_DIR then XDG_CONFIG_HOME/gh, then ~/.config/gh) and treats the upstream as GitHub if its host appears there.
Running gh auth login --hostname your-ghe.example.com is enough to make detection succeed; if gh is not configured for the host, detection fails closed and the upstream is treated as unsupported.
On GHE, gh --repo expects a host-prefixed slug in the form host/owner/name.no-mistakes builds that automatically from the recorded upstream remote or PR URL, so daemon-run gh commands resolve the right repository regardless of the daemon's working directory.
The fork owner extracted from the fork URL keeps the plain owner/name form because that side only feeds --head owner:branch.
Self-hosted GitLab
Self-hosted GitLab is detected out of the box even when the hostname carries no gitlab marker (for example git.example.com).
When the hostname is not obviously GitLab, no-mistakes consults glab's configured hosts (config.yml, honoring GLAB_CONFIG_DIR then XDG_CONFIG_HOME/glab-cli, then ~/.config/glab-cli) and treats the upstream as GitLab if its host appears there as a configured host or api_host.
Running glab auth login --hostname your-gitlab.example.com is enough to make detection succeed; if glab is not configured for the host, detection fails closed and the upstream is treated as unsupported.
The GitLab backend is pinned against glab v1.5x. Self-hosted detection and the merge-request and CI steps rely on its current flag and API surface, so keep glab reasonably up to date.
SSH host aliases
SSH remotes that use a host alias from your SSH configuration (for example git@github-personal:owner/repo or git@gitlab-work:group/repo, where github-personal/gitlab-work map to a real HostName via ~/.ssh/config) are supported. no-mistakes resolves the alias through ssh -G to its real host name and uses that host only for provider detection and for scoping the provider CLI (gh/glab) to the right instance. The original Git remote URL is left untouched, so authentication and pushes continue to use the alias exactly as your SSH configuration expects.
If ssh -G is unavailable or the alias does not resolve, detection falls back to the literal host in the remote URL rather than failing the run.
Unsupported hosts
If your upstream isn't GitHub, GitLab, Bitbucket Cloud, or Azure DevOps:
- The push step still runs - no-mistakes pushes through git to the configured target like any other remote.
- The PR step marks itself as skipped.
- The CI step marks itself as skipped.
Everything before push (rebase, review, test, document, lint) still works regardless of host. If your host has a CLI that exposes CI status and PR state, open an issue - new providers are straightforward to add.
Checking what's wired up
no-mistakes doctordoctor checks gh and az availability. For GitLab, confirm glab is installed and authenticated. For Bitbucket Cloud, confirm the two env vars are set in the environment the daemon runs under. For Azure DevOps, confirm the azure-devops extension is installed (az extension show --name azure-devops) and a PAT is available.
:::note
When the daemon runs through a managed service (launchd, systemd, Task Scheduler), it reloads environment from your login shell on macOS and Linux so gh auth and NO_MISTAKES_BITBUCKET_* vars are picked up, and it augments PATH with common binary directories. If credentials or PATH-derived tools are missing, check ~/.no-mistakes/logs/daemon.log for a login-shell environment resolution warning. On Windows it reuses the current process environment.
:::
---
Src/Content/Docs/Guides/Setup Wizard
---
title: Setup Wizard
description: What bare no-mistakes does when there's no active run on the current branch.
---
When you run no-mistakes with no arguments and there is no active run on the
current branch, no-mistakes can walk you through creating a branch,
committing local changes, and pushing through the gate, then attach if the
daemon registers the new run. This is the setup wizard.
The point of the wizard is to make bare no-mistakes a useful starting
command, not just an attach command. If you have local work but no run yet, the
wizard helps turn that state into branch -> commit -> push -> attach when the
daemon registers the new run.
The wizard kicks in when:
- You're in an interactive terminal, or you passed no-mistakes -y / no-mistakes --yes.
- The gate is initialized for the current repo (no-mistakes init has been run).
- There's no active run on the current branch.
In non-interactive contexts, bare no-mistakes without -y falls back to listing the last 5 runs instead.
With -y / --yes, the wizard takes the default automated path for each step: use agent suggestions for branch and commit when needed, then push to the gate. In a TTY, that path stays visible and auto-advances through the wizard. Without a TTY, it falls back to the headless path.
Pass --skip to skip comma-separated pipeline steps for the new run created by the wizard, for example no-mistakes --skip test,lint.
It only applies when the wizard starts a new pipeline run; if bare no-mistakes attaches to an active run or lists recent runs, --skip exits with an error.
If you want to attach to any active run in the repo (not just the current branch), use no-mistakes attach - that path skips the wizard entirely.
Wizard flow
flowchart TD
start["Run no-mistakes"] --> active{"Active run on current branch?"}
active -- "yes" --> attach["Attach to run"]
active -- "no" --> interactive{"Interactive terminal, or -y/--yes, and gate initialized?"}
interactive -- "no" --> recent["Show recent runs"]
interactive -- "yes" --> branch["Branch step if needed"]
branch --> commit["Commit step if needed"]
commit --> push["Push step"]
push --> registered{"Run registered?"}
registered -- "yes" --> tui["Attach to new run"]
registered -- "no" --> error["Show notify-push error"]Steps
The interactive wizard is a full-screen flow that runs only the steps your current repo state needs, up to three total. The -y / --yes path runs the same steps and accepts the automated default at each one. In a TTY, the TUI stays visible and auto-advances. Without a TTY, it runs headlessly.
While the wizard is running, it also updates your terminal window title with the current setup step and branch. On exit or cancel, it clears that temporary title.
1. Branch
Shown when you're on the default branch or a detached HEAD. Prompts for a branch name.
- Type a name to create a new branch.
- Leave blank and press enter to ask the configured agent for a branch name suggestion based on your local changes.
- Press q to quit.
2. Commit
Shown when you have uncommitted changes. Prompts for a commit message.
- Type a message to commit all changes.
- Leave blank and press enter to ask the configured agent for a commit subject suggestion based on the diff.
3. Push
Always shown. Asks whether to push the current branch to the no-mistakes gate.
- Press y to push.
- Press n to stop.
If the push succeeds, the interactive wizard stays visible in a brief waiting for run… state while the daemon registers the new run, then hands off to the main TUI and attaches. If no run appears in time, the wizard exits with an error instead of silently falling through, and points you at the gate's notify-push.log for hook diagnostics.
The goal is to keep the setup path short. If you already have a branch, it does
not ask for one. If everything is already committed, it skips straight to push.
Retry on failure
If any step fails (git error, agent error, network error), the interactive wizard shows the error and lets you press r to retry the step without restarting the whole flow.
With -y / --yes, the wizard exits on the first error instead of prompting to retry, whether it is auto-advancing in a TTY or running headlessly.
Quitting safely
Press q to quit.
If the wizard has already created a branch or commit on your behalf, quitting requires pressing q twice. The first press shows a confirmation warning so you don't accidentally leave those side effects behind. The second press exits.
That double-confirm is intentional. The wizard is allowed to make real Git side
effects, so exiting should not be too easy once those side effects exist.
Agent suggestions
When you leave branch name or commit subject blank, the wizard invokes the configured agent (global or per-repo agent setting, including fallback lists) to produce a suggestion. The agent sees the local diff and returns:
- A kebab-case branch name prefixed with a type (feat/, fix/, chore/, etc.)
- A conventional-commit subject line, using feat or fix for user-facing product impact so release automation can pick it up
The managed agent server (Rovo Dev or OpenCode) writes its output to ~/.no-mistakes/logs/wizard-agent.log during these runs.
Environment sanity
The wizard requires:
- The gate to be initialized (no-mistakes init has run).
- A clean enough state to commit and push.
- A configured native or ACP agent, only when the wizard needs to suggest a branch name or commit subject. For an ordered fallback list, at least one configured entry must be available. See the Global Config Reference for ACP aliases such as agent: cursor and target requirements.
If you already have a branch and clean working tree, or you enter those values yourself in the interactive flow, the wizard can continue without agent suggestions.
If any of those are missing, the wizard reports the problem and exits.no-mistakes doctor is the fastest way to check whether the configured global runner can start a validation gate.
The wizard can proceed without an agent when it does not need a suggestion, but the pushed validation gate still fails before its first step unless the effective pipeline-agent configuration resolves to a runnable runner.
---
Src/Content/Docs/Guides/Troubleshooting
---
title: Troubleshooting
description: Common problems and how to debug them.
---
Most problems fall into one of three buckets: daemon not running, agent not
found, or push not triggering the pipeline. This page walks each one.
First stop for anything: no-mistakes doctor.
Debug in this order
flowchart TD
problem["Something is wrong"] --> doctor["Run no-mistakes doctor"]
doctor --> daemon{"Daemon issue?"}
daemon -- "yes" --> daemonpath["Check daemon status and daemon.log"]
daemon -- "no" --> triggered{"Did the push trigger a run?"}
triggered -- "no" --> gate["Check remote, hook, and socket"]
triggered -- "yes" --> provider["Check agent or provider setup"]That order matches the actual boundaries in the system:
- local environment and binaries
- daemon and gate wiring
- provider-specific PR or CI integration
Daemon won't start
Symptoms: no-mistakes daemon status shows stopped, or no-mistakes exits with "daemon not running."
Start it manually
no-mistakes daemon startThis installs or refreshes the managed service (launchd, systemd user service, or Task Scheduler), then starts it. If service install or startup fails, it falls back to a detached daemon.
Check logs
tail -f ~/.no-mistakes/logs/daemon.logCheck for stale artifacts
A leftover socket from an unclean exit no longer blocks startup: the daemon probes the socket path before binding and removes it only when nothing is listening on it.
A stale PID file can still confuse status reporting:
ls -la ~/.no-mistakes/daemon.pid ~/.no-mistakes/socketIf the PID file points at a process that's no longer running, remove it and run no-mistakes daemon start again.
"a no-mistakes daemon is already running for this NM_HOME"
This error always means a genuinely live daemon: the lock it reports cannot go stale (see Daemon & Worktrees for the singleton-lock model).
Manage that daemon with no-mistakes daemon status and no-mistakes daemon stop instead of deleting the lock file - deleting the file does not release the lock and only weakens the guard.
If the socket exists and the process is running but stuck or unresponsive, no-mistakes bounds the connection wait with daemon_connect_timeout and fails fast with an error naming the socket path instead of silently starting a second daemon. Restart the stuck daemon:
no-mistakes daemon stop
no-mistakes daemon startIf the socket file exists but nothing answers at all (a dead socket left behind by an unclean exit, e.g. a crash or SIGKILL), commands that ensure the daemon is running (no-mistakes, init, attach, rerun, axi run, axi respond) now fail fast with a connect to daemon socket error instead of silently starting a replacement daemon. The error message itself includes a (run 'no-mistakes daemon start' to recover) hint - run no-mistakes daemon start directly to recover, since it self-heals past a dead socket and starts a fresh daemon.
Managed service logs
- macOS (launchd): launchctl list | grep no-mistakes and check ~/Library/LaunchAgents/com.kunchenguid.no-mistakes.daemon.*.plist
- Linux (systemd): systemctl --user status no-mistakes-daemon- and journalctl --user -u no-mistakes-daemon- -f
- Windows (Task Scheduler): schtasks /query /tn "no-mistakes-daemon-*"
NM_HOME collisions
If you have multiple installs with different NM_HOME roots, each gets its own scoped service name (with a short suffix derived from the path). Make sure you're looking at the right one - no-mistakes daemon status reports which.
no-mistakes update refuses or aborts
Symptom: update refuses because active pipeline runs are in progress, prompts because the daemon is running from a different executable path, or aborts because the daemon executable path cannot be determined.
update, daemon stop, and daemon restart all refuse by default while pipeline runs are active and list the affected runs; Daemon & Worktrees owns the guard's exact rules, including why -y/--yes does not bypass it.
First inspect each listed run with no-mistakes axi status --run <id>.
A parked CI gate can clear itself after its PR becomes terminal, including after a daemon restart.
The ci_timeout reference owns the exact fail-closed reconciliation rules, and Daemon & Worktrees owns restart behavior.
After upgrading from an older release, starting the daemon automatically completes stale active rows that already have a persisted merged or closed PR state.
Do not edit state.sqlite directly.
Only when you have confirmed it is acceptable for every remaining listed active run to fail, force the lifecycle operation:
no-mistakes daemon stop --force
no-mistakes updateAgent binary not detected
Symptom: doctor reports that gate validation is unavailable, or a run fails before its first pipeline step because no runnable agent was found.
This is a hard failure, not a degraded validation mode.no-mistakes will not silently skip review, test evidence, documentation, or agent-assisted lint and report the remaining work as a passed gate.
Check PATH
The daemon uses the same binary-discovery order described in Choosing an Agent. When it's running through a managed service, it reloads PATH from your login shell on macOS and Linux and appends common install locations such as ~/.local/bin, ~/go/bin, ~/.cargo/bin, ~/bin, /opt/homebrew/bin, /usr/local/bin, /usr/bin, and /bin.
If a native agent is installed in a version-manager shim directory or another nonstandard location, set an explicit override in ~/.no-mistakes/config.yaml:
agent_path_override:
claude: /Users/you/.local/bin/claudeFor agent: acp:<target> and ACP aliases such as agent: cursor, set acpx_path for the bridge.
If the raw target command is also outside PATH, set its target key in acp_registry_overrides; agent_path_override applies only to native agents:
acpx_path: /Users/you/.local/bin/acpx
acp_registry_overrides:
cursor: /Users/you/.local/bin/cursor-agent acpFor Antigravity or Gemini-based driving agents, install a supported native agent CLI separately or configure a working ACP target such as agent: acp:gemini with acpx installed.
The calling agent is the AXI driver, not an implicit pipeline-agent backend.
The daemon logs its effective PATH at startup in ~/.no-mistakes/logs/daemon.log with the message daemon environment ready. If the log contains login shell environment resolution failed or login shell environment resolution returned no entries, the daemon used a degraded fallback PATH that may omit version-manager directories such as nvm, fnm, or volta, so tools like pnpm may be missing.
Restart the daemon after installing a new agent
no-mistakes daemon stop
no-mistakes daemon startAgents fail with "403 Request not allowed" behind a proxy
Symptom: runs fail and the step log shows agents (for example claude --print) unable to reach the network, often with 403 Request not allowed.
A managed daemon started by launchd or systemd inherits only a minimal environment, so it does not see the HTTP_PROXY / HTTPS_PROXY / NO_PROXY / ALL_PROXY variables from your shell. no-mistakes bakes any proxy variables that are set when you install or refresh the service into the generated service definition. If you set up the proxy after installing, re-run the installer or no-mistakes daemon restart (with the proxy variables exported) so they get baked in, then confirm them in ~/.config/systemd/user/no-mistakes-daemon-.service on Linux or ~/Library/LaunchAgents/com.kunchenguid.no-mistakes.daemon..plist on macOS. Once baked in, the values survive later restarts and binary upgrades even from a shell that does not export them, so you only need the variables exported the first time. Windows Task Scheduler inherits your logon environment and needs no forwarding.
macOS App Management prompts during agent runs
Pipeline prompts steer agents to keep intentional writes inside the disposable worktree and avoid mutating system locations such as /Applications, Homebrew-managed packages, or global tool configuration.
This reduces macOS App Management prompts from agent-invoked commands, but it is not an OS sandbox.
If you still see prompts, check the step log for commands that intentionally write outside the worktree and move that setup into your normal development environment or an explicit repo-local command.
Requested test evidence may still be written under the managed evidence directory (<NM_HOME>/evidence/<run-id> by default). On GitHub, it is published to the push-target repository's orphan evidence branch when test.evidence.store_in_repo is enabled; the Global Config Reference lists the cases that leave it local instead.
Normal tool temp or cache writes can still happen outside the worktree.
Testing prompts ask agents to remove transient working-tree artifacts they created, such as downloaded models, caches, build outputs, large binaries, or generated data directories, before completion.
A pipeline step failed
Symptom: a run stops with a failed step.
Check the per-step log at ~/.no-mistakes/logs/<runID>/<step>.log.
Fatal step errors are appended to that log, so failures such as rejected pushes include the returned error output there instead of only appearing in daemon.log.
Push fails with refusing to force-push
This means the live remote branch changed after the pipeline's last observed head and contains commit(s) the validated worktree did not incorporate.no-mistakes refuses the push instead of overwriting that remote work.
Fetch and inspect the configured push target, then rebase or merge the remote work into your branch before pushing through no-mistakes again.
If the overwrite is intentional, push manually to the actual remote after reviewing the commits that would be discarded.
Rebase pauses because the branch carries unpushed default-branch commits
This means the branch was created from a local default branch that is ahead of origin/<default_branch>, so its history includes commits that exist only on your local default branch.no-mistakes pauses with an ask-user finding instead of silently bundling that unrelated local work into the PR.
Push the default branch to origin if those commits belong in the shared base, or rebase your feature branch onto origin/<default_branch> to remove the unrelated work before running the gate again.
Approve the finding only when you intentionally want that local default-branch work to stay in the branch.
git push no-mistakes doesn't start a pipeline
Symptom: push succeeds but no-mistakes shows no active run.
Check the remote
git remote -v | grep no-mistakesIf it's missing, run no-mistakes init again.
Re-running init refreshes an existing gate and repairs the no-mistakes remote when it is missing.
It also reattaches an existing gate after you rename or move the repo directory, as long as the old path no longer exists.
Check the receive hooks
The gate's bare repo has a pre-receive hook that authorizes ref updates before mutation and a post-receive hook that notifies the daemon after an admitted push. Look at the gate path:
no-mistakes status
gate path is shown in the output
ls -la <gate-path>/hooks/pre-receive <gate-path>/hooks/post-receive
Both hooks should be executable. If either is missing or non-executable, no-mistakes init will reinstall it for an existing no-mistakes-managed gate.
For validated registered gates and strictly named legacy gates, no-mistakes daemon restart also installs missing no-mistakes-managed hooks and refreshes legacy managed hooks. An existing custom pre-receive hook is preserved behind the managed admission wrapper.
Current managed hooks resolve the gate as an absolute bare-repo path before notifying the daemon, so a shell with a bad PWD value cannot accidentally report the gate as ..
If notify-push.log mentions invalid gate path: ., refresh the managed hook with no-mistakes init or no-mistakes daemon restart, then push again.
Also check <gate-path>/notify-push.log. The hook now appends daemon notification failures there and prints the same error back to the pushing client.
Check the daemon socket
Both receive hooks talk to the daemon over ~/.no-mistakes/socket. If the daemon is not running, pre-receive admission fails closed and the push is rejected before any gate ref changes. Start the daemon and push again.
If the gate is older, re-running no-mistakes init or restarting the daemon also reapplies hook-path isolation when Git supports config --worktree.
That protects the gate hook if a tool such as Husky wrote core.hookspath into shared git config from inside a linked worktree. Crash recovery owns the gate validation and migration rules used during restart.
PR step is skipped
Symptom: pipeline completes but the PR step shows skipped.
Check the Provider Integration requirements. Most common causes:
- gh or glab not installed
- gh auth status shows not authenticated
- Bitbucket env vars not set in the daemon's environment
- Upstream is on a host that isn't supported (GitHub, GitLab, bitbucket.org, or Azure DevOps)
- Self-hosted GitHub Enterprise on a hostname that is not github.com isn't detected because gh isn't configured for the host; run gh auth login --hostname your-ghe.example.com so detection finds it. Once detection succeeds, the availability check is host-scoped (gh auth status --hostname your-ghe.example.com), so a stale token on github.com or any other configured gh host can no longer falsely mark the GHE repo as unauthenticated.
- Self-hosted GitLab on a hostname with no gitlab marker isn't detected because glab isn't configured for the host; run glab auth login --hostname your-gitlab.example.com so detection finds it. Once detection succeeds, the availability check is host-scoped (glab auth status --hostname your-gitlab.example.com), so a stale token on gitlab.com or any other configured glab host can no longer falsely mark the self-hosted repo as unauthenticated.
- A GitLab, Bitbucket, or Azure DevOps repo record has a fork URL set; fork MR/PR routing is currently GitHub-only
- You pushed the default branch (PR step always skips on the default branch)
CI step stuck or timed out
Symptom: CI step keeps monitoring an open PR longer than expected, or pauses after the idle timeout.
Monitoring while the PR remains open - even after checks are currently healthy - is intended behavior, because a later default-branch update can make the PR conflict or rerun CI.
Once the CI monitor reports readiness and the PR is mergeable, the CI panel shows ✓ Checks passed and the terminal title switches to Checks passed, so you can tell when to go merge the PR; the signal clears automatically if checks start re-running or a new failure appears. A trusted no_ci: true declaration can establish readiness for a zero-check repository; an empty forge response without that declaration is not ready.
How long the monitor runs is controlled by ci_timeout in ~/.no-mistakes/config.yaml, an idle timeout that re-arms whenever the upstream default branch advances; the ci_timeout field reference owns the default, the unlimited keyword and its aliases, and the exact re-arm semantics.
Older config files may still contain an explicit ci_timeout: "4h" value; update it if you want the newer default behavior.
If the PR is still open at the timeout, the step pauses for approval with findings for the open monitoring state or any known unresolved failures.
You can approve, fix, or skip from the TUI or no-mistakes axi respond.
Use no-mistakes axi abort only when you mean to cancel the whole active run.
Step looks quiet or wedged
Symptom: no-mistakes axi status shows an active step with last_activity prefixed by quiet, or a review/test/lint step appears to run for longer than expected.
quiet means the step has not recorded a step-log line or native-agent lifecycle event for longer than step_quiet_warning.
It is only a liveness signal.
It does not cancel the step, fail the run, or mean the pipeline is safe to bypass.
Start by reading the active run and the step log:
no-mistakes axi status
no-mistakes axi logs --step <step> --fullThe active_steps table shows how long the step has been active, the latest activity, the native subprocess PID when one is running, and the current round such as round 1, auto-fix 1/3, or fix 2.
The step log records native subprocess start, exit, and retry lines plus markers for automatic and user-triggered fix rounds.
If the step is parked at a gate, use no-mistakes axi respond instead of waiting.
If the run is genuinely stuck and you want to discard it, use no-mistakes axi abort.
Start a new run only after abort confirms the terminal state; see the abort command contract.
Worktree won't clean up
Symptom: ~/.no-mistakes/worktrees/<repoID>/<runID>/ sticks around after a run ends.
The daemon removes worktrees at run completion, and also on daemon startup (crash recovery). If one is still there:
From inside the repo the worktree belongs to:
git worktree list
git worktree remove --force <path>Or let the daemon clean it on next startup:
no-mistakes daemon stop
no-mistakes daemon startReset everything
When state is genuinely wedged:
no-mistakes daemon stop --force
rm -rf ~/.no-mistakes/worktrees ~/.no-mistakes/servers ~/.no-mistakes/socket ~/.no-mistakes/daemon.pid ~/.no-mistakes/daemon.lock
no-mistakes daemon startThis keeps your gate repos, database, and config but clears transient state. For a full wipe, see the Uninstall section.
Wedged state often means a run is stuck pending or running, so daemon stop refuses without --force; only force through once you've confirmed it's fine for the listed runs to fail.
Still stuck
- Check ~/.no-mistakes/logs/daemon.log at log_level: debug
- File an issue: <https://github.com/kunchenguid/no-mistakes/issues>
- Discord: <https://discord.gg/Wsy2NpnZDu>
---
Src/Content/Docs/Guides/Tui
---
title: Using the TUI
description: Terminal UI layout, keybindings, and approval workflow.
---
The TUI is how you interact with running pipelines. Launch it withno-mistakes or no-mistakes attach.
Think of it as the control surface for the gate. It is optimized for one job:
show you where the run is, why it paused, what changed, and what your choices
are without making you bounce between logs, diffs, and provider tabs.
Bare no-mistakes can also open the Setup Wizard first when there is no active run on the current branch and you need to create one.
What the TUI is for
flowchart LR
running["Step running"] --> decision{"Needs human judgment?"}
decision -- "no" --> next["Advance to next step"]
decision -- "yes" --> pause["Pause in TUI"]
pause --> approve["Approve"]
pause --> fix["Fix selected findings"]
pause --> skip["Skip"]
pause --> abort["Abort"]In practice, each part of the screen answers a different question:
- Pipeline box - where am I in the run?
- Findings panel - why did this pause?
- Diff panel - what changed during the fix cycle?
- Log tail - what is the step doing right now?
Layout
The layout adapts to terminal width:
- Wide (100+ columns): pipeline box on the left, findings/log/diff panel on the right, side by side
- Narrow (<100 columns): pipeline box stacked above the findings panel
Pipeline box
Shows the branch name and run status in the header, followed by each step:
feature/login-fix running
────────────────────────────
– Intent
│
✓ Rebase 320ms
│
⏸ Review - awaiting approval 2/3 fixed
│
○ Test
│
○ Document
│
○ Lint
│
○ Push
│
○ PR
│
○ CIStep status icons:
| Icon | Status |
|---|---|
| ○ | Pending |
| (spinner) | Running / Fixing |
| ⏸ | Awaiting approval / Fix review |
| ✓ | Completed |
| – | Skipped |
| ✗ | Failed |
Completed steps show their duration.
Steps with fixed findings, and steps currently fixing reported findings, show a right-aligned count such as 2/3 fixed or 0/3 fixed.
The first number counts completed fixes, not findings selected for an in-progress fix.
Connectors (│) between steps are hidden when the terminal height is under 30 lines.
Findings panel
When a step pauses for approval, the findings panel shows structured results:
Risk: MEDIUM
Potential null pointer in error path > [x] E src/handler.go:42
Missing nil check before dereferencing resp.Body
> keep the existing retry behavior
[x] I [user]
Also update the CLI help text for this new flag
> mention the env var in the docs too
[x] W src/handler.go:78
Error string should not be capitalized
[ ] I src/handler.go:95
Consider extracting this into a helper function
- Severity icons: E (error, red), W (warning, yellow), I (info, blue)
- Checkboxes: [x] (selected, green), [ ] (deselected, dim)
- Blue > marks the focused finding
- User-added findings are marked with [user]
- Per-finding notes render inline as > ... and are sent with the next fix request
- Bottom hint shows ↑ N above / ↓ N more below (j/k) when scrolling, or (j/k) whenever there are multiple findings
Diff panel
After a fix cycle, press d to toggle the diff view:
- Stats header showing files changed, additions, and deletions
- Syntax-colored unified diff with line number gutter
- Finding context line showing which finding you're viewing
- Scroll position in the box title: Diff (45/312)
The TUI loads this working-tree diff on demand when the fix-review gate opens. If loading either the authoritative run state or the diff fails, approval actions stay disabled and the action bar offers r retry. Diff previews are capped at 512 KiB; when a preview is truncated, the TUI shows a warning because approval still applies to the complete working-tree diff.
Log tail
During running steps, shows streaming agent output. Lines starting with PASS are green, FAIL are red, everything else is dim.
On narrow terminals, the log panel expands to fill the remaining vertical space below the pipeline box instead of staying at the compact fixed height used in shorter layouts.
CI panel
While the CI step is active, the TUI shows a dedicated CI panel instead of the generic findings view.
It shows the PR label, the latest CI activity, and a log tail.
When a real CI auto-fix attempt starts, the panel increments CI auto-fixes: N.
Once the CI monitor reports readiness and known mergeability is clear, the panel shows ✓ Checks passed with still monitoring until merged or closed, and the terminal title switches to Checks passed. Readiness includes the trusted no_ci: true declaration when no checks are registered; an empty forge response alone is not ready.
That text means the CI monitor is still active; it can still pause later if the configured idle timeout elapses with no base-branch movement.
That ready signal clears if checks start running again, new failures appear, provider state becomes uncertain, or the PR is merged or closed.
The ready signal is persisted, so a fresh attach shows Checks passed without depending on delivery of an earlier log line.
Local branch
When the pipeline creates a fix commit in its isolated worktree, one compact Local branch box explains whether the invoking branch is unchanged, behind, dirty, diverged, synchronized, or retired after PR merge or close.
Passive TUI rendering uses cached pipeline push provenance and never fetches or mutates the checkout.
When a clean strict-behind relation is eligible, or a diverged relation may be equivalent after refresh, the box alone offers u sync branch.
Pressing u explicitly refreshes the configured upstream or fork target, then opens a confirmation with both full SHAs, the exact target ref, and the clean-worktree proof.
Confirm with u or Enter, or cancel with Escape.
The apply path rechecks every mutable assumption and can only perform the same exact strict fast-forward or anchored equivalent-diverged advance as no-mistakes sync; blocked states never trigger destructive Git recovery.
When the owning run ended without publishing its pipeline commits, the same box offers u recover custody instead: u opens a confirmation naming the terminal status, the local head, and the preserved head, and applying routes through the guarded recovery documented in no-mistakes axi sync.
Footer
The footer shows detach/help/yolo actions and, when no-mistakes attach has a cached newer release available, a right-aligned <version> available indicator. That update indicator stays visible after reruns in the same TUI session.
When yolo mode is on, the footer changes from y yolo to y end yolo.
Keybindings
Navigation
| Key | Action |
|---|---|
| j / k | Scroll down / up |
| g / G | Jump to start / end |
| Ctrl+d / Ctrl+u | Half-page down / up |
| n / p | Next / previous finding |
Actions (when a step is awaiting approval)
| Key | Action |
|---|---|
| a | Approve - continue to next step |
| f | Fix - send selected findings to agent for fixing |
| s | Skip - skip this step and continue |
| x | Abort - press twice to confirm (first press shows warning) |
| o | Open PR URL in browser (when available) |
Selection
| Key | Action |
|---|---|
| space | Toggle current finding |
| A | Select all findings |
| N | Deselect all findings |
| e | Edit fix note for the current finding |
| + | Add a user-authored finding |
| D | Delete the current user-authored finding |
When the instruction editor is open, press Ctrl+s or Ctrl+enter to save, or esc to cancel. In the add-finding editor, use tab / shift+tab to move between fields, Ctrl+s to save, and esc to cancel.
View
| Key | Action |
|---|---|
| d | Toggle diff view (after fix cycle) |
| esc | Exit diff view back to findings |
| ? | Toggle help overlay |
| y | Toggle yolo mode, which auto-resolves paused steps |
| r | Retry a failed fix-review state or diff load; otherwise start a rerun after a failed or cancelled run |
| u | Refresh and confirm local branch synchronization, or confirm custody recovery, when offered |
| q | Detach from TUI (or quit if run is done) |
In diff view, n/p jumps the viewport to the file and line of the next/previous finding.
Action bar
The action bar appears below the pipeline box when a step is awaiting approval:
Review awaiting action:
a approve f fix (3/5) s skip x abort d diff
[space] toggle e edit + add A all N noneThe f fix (3/5) label shows how many findings are selected out of the total.
Press e to add or edit extra guidance for the current finding. Press + to add your own finding to the list. User-authored findings start selected by default and can be removed with D.
Press y to toggle yolo mode when you want paused approval gates to resolve automatically.
Yolo fixes gates with auto-fix and ask-user findings by selecting every finding, then approves the resulting fix-review gate.
It approves gates with no findings or only action: no-op findings as-is, and fixes each step at most once so unresolved findings do not loop forever.
Outcome banner
When a run finishes, a one-line banner appears:
- ✓ Pipeline passed 4.2s (green) - the run finished successfully, even if later steps were auto-skipped
- ✗ Review failed 1.8s (red) - names the failing step
- ✗ Pipeline cancelled (red) - user aborted
After a failed or cancelled run, press r to start a rerun. The TUI switches to the new run automatically.
Detaching
Press q to detach from the TUI. The pipeline continues running in the background. Run no-mistakes again to reattach to the active run on your current branch, or no-mistakes attach to reattach to the repo's active run without branch scoping.
If the run is already finished, q exits the TUI.
---
Src/Content/Docs/Concepts/Auto Fix
---
title: Auto-Fix Loop
description: How the automatic fix loop works.
---
When a pipeline step finds issues, no-mistakes can automatically ask the agent to fix them before pausing for your approval. This is controlled by the auto_fix configuration.
flowchart TD
run["Run step"] --> findings{"Findings?"}
findings -- "no" --> done["Step completes"]
findings -- "yes" --> eligible{"Auto-fix enabled and eligible findings?"}
eligible -- "no" --> pause["Pause for user approval"]
eligible -- "yes" --> fix["Agent applies fixes"]
fix --> rerun["Re-run step"]
rerun --> clean{"Blocking findings remain?"}
clean -- "no" --> done
clean -- "yes, attempts left" --> eligible
clean -- "yes, limit hit" --> pauseHow it works
1. A step executes and returns findings (e.g., test failures, lint warnings, review issues)
2. If auto_fix is enabled for that step (limit > 0) and the attempt count is below the limit, the executor re-runs the step with fixing=true
3. The agent receives the previous findings and applies fixes
4. The step re-runs to verify the fixes
5. If issues remain and attempts are left, the loop continues
6. Once the limit is reached or all issues are resolved:
- If issues remain, the step pauses for user approval
- If everything passes, the step completes and the pipeline moves on
The document step applies fixes during its initial pass instead of relying on a follow-up automatic fix loop.
When commands.lint is empty, that same invocation is a combined documentation-and-lint housekeeping pass: it updates documentation, detects relevant linters and formatters, applies safe fixes, verifies both duties, and categorizes any unresolved findings for the document or lint gate.
The lint step consumes a usable lint result from that pass instead of starting a second cold agent invocation; when the combined pass is skipped, cannot produce trustworthy structured output, or loses its in-memory result across a daemon restart, lint falls back to its own agent pass.
Unresolved documentation findings and unresolved blocking lint findings pause for approval instead of entering another automatic fix loop.
Before the agent: deterministic CI reruns
The CI step has one cheaper option than a fix round, and it tries it first.
A check the provider reports as cancelled is the provider telling you about itself, not about your commit. Handing that to the fix agent spends an agent round reading a run that never tested anything, and the fix it invents edits code that was never broken. So when every terminally failed check on the pull request is cancelled and the configured budget authorizes a rerun, the CI step asks the provider to run those checks again for the same commit and keeps polling.
That deterministic rerun sits strictly before the agent rounds described above:
1. Every check finishes and at least one has failed.
2. If all of those failures are cancelled checks, the pull request has no merge conflict, and the configured budget authorizes it, each one is re-run and the monitor keeps polling. No auto_fix.ci attempt is consumed.
3. When cancellation is the only remaining issue, a check with no authorized or outstanding rerun pauses for a decision without consuming an auto_fix.ci attempt.
4. Every other failure escalates into the auto_fix.ci loop on its first observation.
ci.rerun_transient owns the budget, the exact classification, and every case that skips the rerun.
Nothing that survives a rerun falls into the agent loop either. A check the provider cancels again is still not a verdict on the code, so it pauses for a decision instead of spending a fix round on a run that never tested anything. A cancellation no rerun is going to replace - the default budget is 0 - reaches that same decision directly: the provider has published its conclusion and will not replace it, so waiting on it would never end. A rerun costs another CI run of that job, so the budget is deliberately small and is spent when the rerun is requested, which bounds the loop by construction. Each rerun is announced in the step log, so a run that is waiting on one says so instead of looking stalled. Reruns never cross a head change: if the published branch head no longer matches the commit the run delivered, the step pauses with the expected and observed commits rather than re-running checks against a revision it never produced.
Configuration
Per-step attempt limits come from the auto_fix config object; the auto_fix field reference owns the defaults, per-step meanings, and the legacy alias.
Setting a step to 0 disables the follow-up auto-fix loop, so the pipeline pauses for human input when that step finds issues; auto_fix.review defaults to 0, so review findings require manual approval unless you opt in.
Repo config overlays global config field by field - you can set auto_fix.lint: 5 in a repo's .no-mistakes.yaml to override just that step while inheriting the rest from global.
Finding actions
Agent-driven findings now use an action field instead of requires_human_review:
- auto-fix - objective issues that can be fixed automatically
- ask-user - intent-sensitive or ambiguous issues that pause for approval instead of entering the normal auto-fix loop
- no-op - informational notes that do not need a fix
If an agent or integration omits action, no-mistakes fails closed by treating the finding as ask-user.
An unclassified finding is never eligible for automatic fixing.
ask-user is meant for findings that need human judgment - for example, questioning an intentional product or design choice, arguing that an intentional addition, removal, or guard should be undone, or reporting that the test step could not produce enough evidence for the available intent. Routine correctness, reliability, or security fixes still stay auto-fix even if the smallest fix reintroduces a small amount of previously deleted logic. Agents driving the AXI skill should relay ask-user findings to the user unless they have explicit --yes consent to resolve gates unattended.
In the TUI, yolo mode is an explicit override that auto-resolves paused steps by treating auto-fix and ask-user findings as consent to run one fix round.
Steps with only no-op findings are approved as-is.
The review, test, and configured-command lint steps use this shared model directly. The document step also uses the same action field, but unresolved documentation findings pause for approval because the initial document pass already attempted the documentation updates it could make safely.
When commands.lint is empty, the combined housekeeping pass routes documentation and lint findings to their owning gates. Its unresolved lint findings describe issues left after safe fixes, so blocking findings pause for approval instead of remaining eligible for another automatic fix loop.
Documentation findings use the same approval UI, but the document step treats any finding as an unresolved documentation gap or judgment call that should pause for approval.
User-triggered fixes
When the pipeline pauses for approval, you can manually trigger a fix from the TUI or AXI interface:
1. The findings panel shows all findings with checkboxes
2. Toggle individual findings with space, or use A (all) / N (none)
3. Optionally press e to attach a note to the current finding, or + to add your own finding to the fix request
4. Press f to fix the selected findings
The agent receives the merged fix payload for that round: the selected agent findings, any per-finding user notes, any selected user-authored findings added from the TUI or AXI interface, and a sanitized history of previous rounds for that step.
That history includes which finding IDs were selected for a prior fix attempt, which findings were left unselected by the user, and any one-line summaries from earlier fix commits.
On follow-up review passes, that history tells the agent not to re-report user-ignored findings unless the code now presents a materially different issue.
After a user-triggered fix, the step re-runs and pauses again to show you the results (fix_review status). You can then approve, fix again, skip, or abort.
Yolo and AXI --yes approve that fix review automatically after their one fix round, so a finding that remains after the fix does not trigger an unbounded fix loop.
Fix commits
When the Review, Test, Document, or Lint step commits auto-fix changes, its subject comes from commit.fix_message.
The global config reference owns the template syntax, default, validation rules, size limits, and supported placeholders; the repo config reference owns the repository override and trust behavior.
The pipeline validates the template, agent summary, predicted output size, and final rendered subject before git add -A, so a rejected value does not leave changes staged.
The combined document-and-lint housekeeping pass runs in the Document step, so its documentation and safe lint fixes use the Document value for {{.Step}}; configured-command lint fixes use the Lint value.
Before a step-specific fix commit, the pipeline verifies that the live worktree HEAD still descends from the head recorded after its previous commit.
It allows a legitimate forward commit made by an agent, but aborts the run if an out-of-band backward or divergent reset would drop the reviewed history.
The template does not control commits created by the Rebase, CI, or Push steps.
The CI step uses no-mistakes: apply CI fixes, and the Push step uses no-mistakes: apply agent fixes for remaining uncommitted changes.
Step rounds
Each execution of a step (initial run or follow-up auto-fix run) is recorded as a "round" in the database.
A round stores its findings, duration, any selected finding IDs and whether that selection came from the user or auto-fix filtering, the merged finding payload actually sent to the fix agent for that round, and any one-line fix summary from that execution.
That merged payload can include per-finding user notes and user-authored findings added from the TUI or AXI interface.
AXI status uses the same round history and the persisted auto-fix limit to show the active fix attempt, for example auto-fix 1/3 or fix 2.
The step log records a marker when each automatic or user-triggered fix round starts.
The generated PR surfaces this recorded evidence in deterministic Risk Assessment, Testing, and Pipeline sections. The pipeline steps reference owns the PR body composition and size-limit contract.
The full round history remains available in the run log.
Round trigger types:
- initial - first execution
- auto_fix - triggered by the automatic fix loop
- auto_fix - also used when you press f in the TUI or use no-mistakes axi respond --action fix to run a follow-up fix
Legacy user_fix rounds are still rendered as auto-fix in PR summaries for backward compatibility.
---
Src/Content/Docs/Concepts/Daemon
---
title: Daemon & Worktrees
description: Background process management, worktrees, state, and recovery.
---
The daemon is a long-running background process that manages pipeline runs. The
installer prefers setting it up as a managed background service, andno-mistakes, init, attach, rerun, and update keep that service
installed and running for you when that path is available.
Why a daemon exists
The daemon exists so git push no-mistakes stays fast and the gate can keep
working after your shell command returns.
- Git hands the push to the local gate repo.
- The hook notifies the daemon and exits immediately.
- The daemon owns the long-running work: worktrees, pipeline execution, TUI
events, state, cleanup, and crash recovery.
flowchart LR
push["git push no-mistakes"] --> gate["Gate repo hook"] --> daemon["Daemon"]
daemon --> run["Run in detached worktree"]
daemon --> state["Persist state + logs"]
run --> tui["TUI can attach or detach"]
run --> cleanup["Cleanup when run finishes"]On macOS this is a per-user launchd agent, on Linux a per-user systemd service, and on Windows a Task Scheduler task. The installed artifact names are scoped by NM_HOME with a short stable suffix, so the paths and service identifiers look like ~/Library/LaunchAgents/com.kunchenguid.no-mistakes.daemon.<suffix>.plist, ~/.config/systemd/user/no-mistakes-daemon-<suffix>.service, and the Windows task no-mistakes-daemon-<suffix>. That keeps multiple no-mistakes installs from colliding when they use different NM_HOME roots. Those service managers keep the daemon available across CLI invocations and restart it after no-mistakes update replaces the binary. A managed service starts with a minimal environment, so at daemon startup it resolves PATH and proxy variables from your login shell and the baked-in service definition; Environment the daemon sees owns that resolution story. Restart the daemon after changing those values. If managed service install or startup is unavailable or fails, no-mistakes falls back to starting a detached daemon process instead.
Starting and stopping
Most people do not need to manage the daemon directly. The usual commands
already make sure it exists when needed.
Explicit management
no-mistakes daemon start
no-mistakes daemon stop
no-mistakes daemon restart
no-mistakes daemon statusEnsures the daemon is running, using the managed service when possible
no-mistakes
no-mistakes init
no-mistakes attach
no-mistakes rerun
no-mistakes axi run
no-mistakes axi respondResets the daemon after replacing the binary
no-mistakes updateno-mistakes update stops and starts the daemon when it is running, or when stale daemon artifacts exist, so the new executable is used.
It prefers the managed service path and falls back to a detached daemon if service startup is unavailable or fails.
If pending or running pipeline runs exist, update refuses to restart the daemon by default and prints each active run's ID, status, branch, and short head SHA. Pass --force to restart the daemon anyway and accept that those runs may fail; -y/--yes does not bypass this guard.
If the daemon is already running from a different executable path, update still prompts before replacing it; -y/--yes answers that prompt non-interactively.
If the daemon executable path cannot be determined, the update aborts before replacing anything.
no-mistakes daemon stop and no-mistakes daemon restart apply the same guard: if pending or running pipeline runs exist, each refuses by default and lists the active runs, and each takes its own --force to proceed anyway.
That --force override is available only to an ordinary top-level caller. A
process descended from an active validation-step agent cannot start, stop,
restart, or update the daemon; recursive containment refuses the command before
any lifecycle mutation, with no --force or --yes bypass.
Every invocation of daemon stop, daemon restart, or update - forced or not - logs the caller's PID, parent PID, and parent command line to ~/.no-mistakes/logs/cli.log so a later incident can identify which agent or process triggered it.
The daemon writes an identity record to ~/.no-mistakes/daemon.pid and listens on a Unix socket at ~/.no-mistakes/socket. On Windows, it uses a localhost TCP listener and a protected endpoint file at the same path. CLI clients bound how long they wait for that socket to accept a connection with daemon_connect_timeout (default 3s, override with NM_DAEMON_CONNECT_TIMEOUT), so a daemon process that is alive but stuck fails the connection instead of hanging the caller; see Troubleshooting.
Commands that ensure the daemon is running (no-mistakes, init, attach, rerun, axi run, axi respond) also fail fast rather than silently starting a replacement daemon when the socket file exists but nothing answers at all, such as a dead socket left behind by an unclean exit; no-mistakes daemon start self-heals past that case.
After accepting a shutdown request, daemon stop waits for the daemon process itself to exit before returning success. Losing IPC health is not enough because the listener closes near the start of shutdown, while the singleton lock and other process-owned resources are released only at process exit. daemon restart uses the same complete-stop handoff before starting the replacement, so the old and new processes do not contend for the root.
Process launch and daemon readiness are separate states. After taking the singleton lock, the daemon publishes its PID before exclusive crash recovery begins, but startup is not successful until the IPC server returns a real health response. daemon start allows up to 45 seconds for cold environment setup and recovery, reports a child that exits before readiness promptly, and never treats the PID file or a bound socket as proof that the daemon is ready. If detached startup times out, the command kills and reaps that child before returning; if managed startup fails, it cleans up the managed attempt before trying the detached fallback and preserves both errors when both paths fail.
Only one live daemon can own an NM_HOME at a time.
At startup - before crash recovery runs and before the socket is bound - the daemon takes an exclusive OS file lock on ~/.no-mistakes/daemon.lock and holds it for the life of the process.
A second daemon started against the same root fails with "a no-mistakes daemon is already running for this NM_HOME" (with the holder's PID and start time when available) instead of stealing the first daemon's socket and running crash recovery against its live runs.
The OS releases the lock automatically when the owning process exits or crashes, even on SIGKILL, so unlike the PID file the lock can never go stale.
As an independent safety layer, the daemon also refuses to bind the Unix socket while something is still answering on it; only a provably stale socket file (nothing listening) is removed and rebound.
What it does
When a push arrives via the post-receive hook:
1. Creates a detached worktree at ~/.no-mistakes/worktrees/<repoID>/<runID>/
2. Starts the pipeline executor in that worktree
3. Streams events to any connected TUI clients and serves request/response state to AXI clients
4. Cleans up the worktree when the run finishes (success or failure)
Event delivery is bounded, so a slow or wedged client can never stall a run. Under pressure the daemon may drop ordinary log output, but it never silently loses a state change: it coalesces those into a single gap signal, and the TUI and axi respond by re-reading authoritative run state. A live view can therefore skip log lines while it is behind, but it converges on the run's real state. After a dropped connection, the TUI retries with a bounded delay and reconciles when it reattaches; if the daemon remains unavailable, it surfaces the connection error instead of retrying forever.
Pipeline agents are prompted to keep intentional writes inside that detached worktree and avoid changing system state outside it, such as Homebrew packages, apps under /Applications, or global tool configuration.
That reduces surprising machine-level side effects and macOS App Management prompts, but it is prompt steering rather than a true sandbox.
While executing steps, the daemon also owns child-process cleanup.
Configured commands and one-shot agent subprocesses are terminated as a process tree on completion, failure, or cancellation so leaked test workers, build watchers, or dev servers cannot accumulate across runs.
Each process is asked to exit first and only forcibly killed if it is still running a few seconds later.
A process can still escape that tree by detaching itself into its own session, so when a run finishes the daemon also terminates anything still standing in that run's worktree before removing the directory.
That sweep is scoped by working directory: it never touches a worktree whose run is still active, and it can never reach a process working outside ~/.no-mistakes/worktrees/.
Concurrent push handling
If you push to the same branch while a run is already active, the daemon:
1. Cancels the in-progress run (reason: "cancelled: superseded by new push")
2. Waits for it to finish
3. Starts a new run with the latest push
Pushes to different branches run concurrently.
This is another reason the daemon exists: branch-level coordination is easier to
reason about in one long-lived process than inside independent hook invocations.
Crash recovery
On startup, the daemon checks for runs that were left in pending or running status (which means the daemon crashed while they were active):
- Completes legacy active rows whose persisted PR state is already merged or closed, including their CI step, before active-run recovery and parked-run planning
- Resumes only fully recorded parked approval gates whose worktree and step history can be validated; incomplete or ambiguous active runs fail closed
- Before resuming a parked CI gate, re-checks its persisted PR URL through the configured provider; a currently merged or closed PR completes the stale gate, while an open, unknown, or unreachable PR remains parked
- Marks every other stale active run as failed with the message "daemon crashed during execution"
- Reaps orphaned managed agent servers left behind by a crashed daemon or setup wizard
- Terminates processes a crashed daemon left running in worktrees no run owns any more, using the same working-directory scoping as run cleanup plus a ten-minute age floor so a run starting concurrently with startup is never mistaken for a leak
- Removes orphaned worktree directories via git worktree remove --force - but never one whose run is still pending or running; only leftovers from terminal runs or directories with no matching run record are removed
- Migrates gates named by authoritative repository records, plus legacy directories with the strict <repoID>.git shape. Before changing an unstamped candidate, it validates that the directory is a bare repository without relying on the current directory or ancestor Git discovery; unrelated and malformed directories are rejected without hook or Git mutation
- For a validated legacy gate, installs or refreshes the no-mistakes-managed pre-receive admission and post-receive notification hooks, preserving an existing custom pre-receive hook behind the admission wrapper, then enables push-option support and reapplies per-worktree hook-path isolation
- Records a content-versioned gate configuration stamp only after the whole migration succeeds. Normal restarts check current stamped gates from the filesystem without rerunning the mutating Git commands
- Clears any parked-awaiting-agent marker so a recovered failed run is not shown as still waiting for axi respond
Logging
Daemon lifecycle logs go to ~/.no-mistakes/logs/daemon.log. Startup logs report concise phase durations, gate migration counts, and a final daemon ready message only after IPC health succeeds. Successful read-only IPC requests such as health and run-state reads appear only at debug; mutations, stream starts, lifecycle transitions, and failed requests remain visible at info or warn.
Managed Rovo Dev and OpenCode server stdout and stderr go to ~/.no-mistakes/logs/managed-server.log, separate from concise server startup, exit, and failure summaries in the lifecycle log. Output written before the lifecycle logger is ready, plus direct crash output, goes to ~/.no-mistakes/logs/daemon-bootstrap.log. The lifecycle log retains a 32 MiB current file and three backups, managed-server output retains a 16 MiB current file and two backups, and bootstrap/crash output retains a 1 MiB current file and two backups. Backups use .1 for the newest retained file.
The setup wizard separately captures managed agent-server output in ~/.no-mistakes/logs/wizard-agent.log. Each pipeline step writes to ~/.no-mistakes/logs/<runID>/<step>.log, and fatal step errors are appended there so the step log includes the failure reason even when the detail comes from command stderr. daemon stop, daemon restart, and update invocations are logged separately to ~/.no-mistakes/logs/cli.log with the caller's PID, parent PID, and parent command line.
Set the log level in global config:
log_level: debug # debug | info | warn | errorShutdown
no-mistakes daemon stop stops the current daemon process without removing the managed service. The next no-mistakes daemon start, no-mistakes, init, attach, rerun, or update will start it again through the same service manager when available, or as a detached daemon otherwise.
The starting and stopping section owns the active-run
guard, the top-level --force override, and the separate validation-step
containment rule.
1. Cancels all active runs
2. Waits up to 30 seconds for goroutines to finish
3. Removes the PID file and socket
---
Src/Content/Docs/Concepts/Gate Model
---
title: The Gate Model
description: Architecture and data flow of no-mistakes.
---
no-mistakes intercepts pushes by placing a local bare git repo between your
working repo and the configured push target. That bare repo is the gate.
The point is not to hide Git. The point is to create one deliberate place where
validation can happen before a branch is shared.
Architecture overview
flowchart TD
repo["Working repo"] -->|"git push no-mistakes"| gate["Local bare gate repo"]
gate --> admission["pre-receive admission"]
admission --> hook["post-receive notification"]
admission --> daemon["Daemon"]
hook --> daemon
daemon --> worktree["Disposable worktree"]
worktree --> pipeline["intent -> rebase -> review -> test -> document -> lint -> push -> pr -> ci"]
pipeline --> target["Push target"]
daemon --> db["SQLite state"]
daemon --> ipc["IPC socket"]
ipc --> tui["TUI clients"]
ipc --> axi["AXI clients"]What no-mistakes init does
When you run no-mistakes init in a repo:
1. It creates a local bare gate repo under ~/.no-mistakes/repos/<id>.git.
2. It installs a pre-receive admission hook and a post-receive notification hook in that gate repo.
3. It enables Git push options for the gate repo.
4. It best-effort isolates the gate repo's hooks path from shared local Git config writes when Git supports config --worktree.
5. It adds a no-mistakes remote to your working repo that points at the gate.
6. When --fork-url is supplied, it records that GitHub fork as the branch push target while keeping origin as the parent repository used for PR bases.
7. It installs or refreshes the /no-mistakes agent skill at user level, into ~/.claude/skills/no-mistakes/SKILL.md and ~/.agents/skills/no-mistakes/SKILL.md, on a best-effort basis, following existing symlinks between the home .claude and .agents skill directories. It writes no skill files into the repo; if the repo still carries a vendored copy from an older version, init prints a notice that the copy can be removed.
8. It makes sure the daemon is running so incoming pushes can start runs.
init is idempotent.
If the repo is already initialized, it refreshes the existing gate instead of failing: managed hook installation, push-option support, hook-path isolation, gate and working remotes, origin/default-branch metadata, and the /no-mistakes agent skill are repaired or updated where needed.
If the working repo was renamed or moved and the old path no longer exists, init reattaches the existing gate from the leftover no-mistakes remote, updates the stored working path, and preserves the repo ID plus run history.
If the working repo was copied and the original path still exists, init treats the copy as a new repo and repoints the copied no-mistakes remote to a fresh gate.
If daemon startup fails during a refresh, init reports the error but does not eject the pre-existing gate.
After init, your original origin still points at the real upstream remote.
With --fork-url, that origin should be the parent repository, and the fork URL is stored separately for branch pushes.
That is a core design choice, not an implementation detail.
How a push flows
1. You run git push no-mistakes <branch>.
2. The gate repo's pre-receive hook asks the daemon to admit the update before Git changes any gate ref. An active validation-step descendant is refused, including a direct push that bypasses the CLI.
3. Git writes an admitted push into the local bare gate repo.
4. The gate repo's post-receive hook notifies the daemon.
5. The daemon creates a detached worktree for this run.
6. The pipeline runs in order: intent -> rebase -> review -> test -> document -> lint -> push -> pr -> ci.
7. If a step pauses, you can attach with the TUI or use no-mistakes axi respond to approve, fix, or skip.
Use no-mistakes axi abort only when you mean to cancel the whole run.
AXI run objects show awaiting_agent: parked <duration> while a non-terminal run is parked at that gate, so a supervising agent can distinguish a waiting run from active work in one status read.
While a step is actively running or fixing, AXI run objects can also show active_steps with the active duration, latest activity, native agent PID, and current execution or fix round.
8. After local checks pass, the push step forwards the branch to the configured push target only after verifying that the update will not discard unincorporated commits already on that target, and the PR step creates or updates the pull request.
For GitHub fork routing, the push target is the fork and the PR base repository is the parent from origin.
9. The CI step keeps watching the open PR until it is merged, closed, or its configured idle timeout elapses with no base-branch movement, and can auto-fix failures or merge conflicts when supported.
While it watches, the TUI and terminal title surface a Checks passed signal once checks are green and the PR is mergeable (or the trusted default-branch config declares no_ci: true and no checks are registered), and no-mistakes axi returns outcome: checks-passed with instructions to summarize the run and list any pipeline fixes, so agents stop and ask you to review and merge it. An empty forge response without that declaration stays not-ready.
Key design decisions:
- Named remote - origin is never hijacked. You push to no-mistakes on purpose, so regular git push still works normally.
- Recursive-run containment - managed gate identity and authenticated daemon peer ancestry prevent active validation steps from starting or controlling another pipeline. NO_MISTAKES_GATE is diagnostic evidence only, not authorization.
- Disposable worktrees - each run happens in its own detached worktree under ~/.no-mistakes/worktrees/. The daemon can safely modify files, run tests, and commit fixes without touching your working directory.
- Fixed pipeline - the step order is opinionated and not configurable: intent → rebase → review → test → document → lint → push → pr → ci. What you _can_ configure is the commands each step runs, how many auto-fix attempts are allowed, and whether transcript-based intent extraction is used when intent is not supplied directly.
- Remote data-loss guard - force-pushes are checked against the live push target and refused when they would discard commits the run did not incorporate.
Why it is built this way
Named remote
The remote is explicit because trust matters. no-mistakes is an opt-in gate,
not a trap door that silently rewires normal Git behavior.
Bare gate repo
The local bare repo gives Git a normal place to receive pushes. A managedpre-receive hook asks the daemon to authorize the update before any gate ref
changes, and a post-receive hook hands an admitted push off to the daemon.
Git operations on the gate name the bare repo explicitly with --git-dir
instead of relying on working-directory discovery, so hardened environments
that set safe.bareRepository=explicit (common in agent harnesses and CI)
work unchanged.
Daemon
The daemon owns long-running work: creating worktrees, running the pipeline,
streaming events, tracking state, and recovering from crashes. Without it, the
CLI would need to stay attached to every run.
Disposable worktrees
The worktree is where no-mistakes can safely rebase, run commands, let the
agent edit files, and commit fixes. Your day-to-day working tree stays clean.
Component overview
Receive hooks
Before Git changes a managed gate ref, the pre-receive hook asks the daemon
to authorize the pushing process. The daemon refuses descendants of an active
validation step before mutation, including direct pushes, and safely omits run
or phase details when authenticated ancestry cannot identify them uniquely.
An existing custom pre-receive hook is preserved and runs after admission.
When git push no-mistakes <branch> lands, the bare repo's post-receive hook
fires. It resolves the gate to an absolute bare-repo path using Git's own view
of the repository, falling back to the hook location if needed, then callsno-mistakes daemon notify-push with that gate path, ref name, old/new SHAs,
and any Git push options such as no-mistakes.skip=test,lint.
For compatibility with older managed hooks, notify-push also normalizes
relative gate paths before handing them to the daemon.
The post-receive hook never blocks an already admitted push - Git ignores its
exit status - but notification failures are surfaced to the pushing client on
stderr and appended to notify-push.log in the bare repo for later inspection.
Daemon
A long-running background process that manages pipeline runs. It:
- Listens on a Unix socket at ~/.no-mistakes/socket
- Writes its identity record to ~/.no-mistakes/daemon.pid
- Holds an exclusive OS lock on ~/.no-mistakes/daemon.lock for its whole lifetime, so only one live daemon can own an NM_HOME at a time
- Serializes concurrent pushes to the same branch (new push cancels the in-progress run)
- Creates and cleans up worktrees
- Scopes configured commands and one-shot agent subprocesses to the step lifetime by terminating remaining child processes on completion, failure, or cancellation
- Persists state to SQLite
- Streams events to connected TUI clients via IPC
The installer prefers setting up the daemon as a managed background service, and no-mistakes, init, attach, rerun, and update make sure the daemon is running when needed.
Bare no-mistakes then attaches to the active run on the current branch when one exists, or routes to the setup wizard when it needs to create a new branch/run.
If managed service install or startup is unavailable or fails, startup falls back to a detached daemon process.update resets the daemon after replacing the binary when the daemon is running or stale daemon artifacts exist.
If the daemon is already running from a different executable path, update prompts before replacing it.
If the daemon executable path cannot be determined, update aborts before replacing anything.
You can also manage it explicitly with no-mistakes daemon start|stop|restart|status.
Daemon & Worktrees
owns the active-run guard, the scope of --force and --yes, and recursive
validation-step containment for lifecycle commands.
On startup, the daemon validates crash-recovery state before resuming work.
Daemon & Worktrees owns the exact restart, parked-gate reconciliation, cleanup, and fail-closed behavior.
Pipeline executor
The executor runs each step sequentially and manages the approval/fix loop. It
can also end early after rebase if the branch has no diff against the default
branch, marking the remaining steps as skipped.
1. Execute the step
2. If the step finds action: auto-fix findings, the step result is auto-fixable, and auto-fix is enabled, loop back with the agent to fix them (up to the configured limit)
3. If blocking findings remain, or any finding has action: ask-user, pause and wait for user action
4. action: no-op findings are informational only; the user can approve, fix selected findings, skip, or cancel the run when the step pauses
While the executor is paused at an approval or fix-review gate, it persists a run-level awaiting-agent timestamp that AXI renders as awaiting_agent: parked <duration>.
That timestamp is observability only and does not alter approval behavior.
When the wait ends, it atomically clears the marker and adds the elapsed wall time to the run's local parked-time total, so a crash cannot leave that time undercounted.
While a step is running or fixing, the executor also records the latest meaningful step activity from log lines and native subprocess lifecycle events.
AXI renders that activity in active_steps, including a quiet prefix when no activity has arrived for longer than the configured step_quiet_warning.
IPC
Communication between the CLI and daemon uses JSON-RPC 2.0 over the Unix socket. The subscribe method streams real-time events (step progress, log chunks, findings) to the TUI, while the axi commands use request/response IPC for non-interactive agent control.
Database
SQLite at ~/.no-mistakes/state.sqlite tracks repos, runs, step results, step rounds, derived intent summaries, local agent invocation performance, and the minimum session metadata needed to resume review-loop roles.
Step rounds record each execution attempt (initial, auto-fix) with its own findings and duration, plus selected finding IDs, whether the selection came from the user or auto-fix filtering, the merged finding payload actually sent to the fix agent for that round, and the one-line fix summary for fix rounds.
Step results also store the last active timestamp, last activity text, native agent PID while a subprocess is active, and the effective auto-fix limit used by AXI status.
That merged payload can include per-finding user notes and user-authored findings from the TUI or AXI interface.
Intent stores the summary, source, session ID, and match score on each run when transcript matching is used, plus cached summaries for matching transcript sessions.
An agent-supplied AXI intent is stored directly on the run.
Raw transcript text is not stored in this database.
Legacy user_fix rounds are still read as auto-fix for backward compatibility.
Run records also store the nullable awaiting_agent_since timestamp used only to render the AXI parked signal while a gate is waiting for the driving agent, plus accumulated parked_ms for local performance reporting. For version-specific debugging, inspect runs.no_mistakes_version and runs.no_mistakes_build_sha: each new run records the version returned by internal/buildinfo.CurrentVersion() and the internal/buildinfo.Commit build SHA embedded through release -ldflags, the same identity shown by no-mistakes --version. Historical rows remain NULL.
Each agent invocation records local-only purpose, provider/model metadata, session mode and a truncated session-identity hash, timing, failure category, and token usage; prompts, outputs, diffs, and credentials are never stored there.
Use no-mistakes stats --agents for aggregates or no-mistakes stats --run <id> for a run timeline and parked time.
Repo records store the parent upstream_url and an optional fork_url; branch pushes use fork_url when present, while PR and CI provider context stays anchored to the parent.
At the start of each run, no-mistakes best-effort refreshes those URLs from the working clone without changing any clone or gate remote.origin is the upstream authority, and an existing fork registration is refreshed only when exactly one other clone remote identifies the same fork repository.
The two registered URLs are replaced atomically after validation; an unreadable, invalid, credential-bearing, or ambiguous remote, or a database failure, leaves the exact prior registration in place and does not stop the run.
Local state
Everything lives under ~/.no-mistakes/ by default. Set NM_HOME to relocate it.
| Path | Contents |
| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| state.sqlite | SQLite database |
| socket | Unix domain socket for IPC |
| daemon.pid | Daemon identity record |
| daemon.lock | Singleton lock; the OS lock a live daemon holds so a second daemon for the same root cannot start |
| config.yaml | Global configuration |
| telemetry-gate.json | Persistent read-only telemetry dedupe state |
| update-check.json | Cached update check result |
| servers/ | PID-tracking records for managed agent servers |
| repos/<id>.git | Bare gate repos |
| repos/<id>.git/notify-push.log | Persistent hook notification failure log |
| worktrees/<repoID>/<runID>/ | Disposable worktrees (cleaned up after each run) |
| logs/<runID>/<step>.log | Per-step log files |
| logs/daemon.log | Bounded daemon lifecycle log |
| logs/daemon-bootstrap.log | Bounded pre-logger bootstrap and direct crash output |
| logs/managed-server.log | Bounded stdout and stderr from daemon-managed Rovo Dev and OpenCode servers |
| logs/wizard-agent.log | Managed agent-server output captured during setup wizard runs |
| logs/cli.log | Caller attribution (PID, parent PID, parent command line) for daemon stop, daemon restart, and update invocations |
New repo IDs are the first 6 bytes (12 hex chars) of sha256(absolute_working_path).
When an initialized working repo is renamed or moved, init preserves the existing repo ID instead of deriving a new one from the new path.
---
Src/Content/Docs/Concepts/Pipeline
---
title: Pipeline
description: The nine steps that run on every gated push.
---
The pipeline runs a fixed, opinionated sequence of steps. Order is not configurable. What each step runs is.
intent → rebase → review → test → document → lint → push → pr → ciflowchart LR
intent["Intent"] --> rebase["Rebase"] --> review["Review"] --> test["Test"] --> document["Document"] --> lint["Lint"] --> push["Push"] --> pr["PR"] --> ci["CI"]
review -. findings .-> action["Approve / fix / skip / abort"]
test -. findings .-> action
document -. findings .-> action
lint -. findings .-> action
ci -. failures .-> actionThis page is the overview. For each step's exact behavior, defaults, skip rules, and fix-commit format, see Pipeline Steps.
What a passed gate means
The pipeline is opinionated so that "passed the gate" has a stable meaning:
- the branch was checked against fresh remote upstream and the pushed-branch target first
- review, tests, user-facing test evidence when available, docs, and lint happened before any branch push to the configured target
- the human stayed in control when a step needed judgment
- the final branch update was guarded against discarding unincorporated commits already on the push target
- push, PR creation, and CI monitoring only happened after the local gate was satisfied
The nine steps
| # | Step | What it does | Default auto-fix limit |
|---|---|---|---|
| 1 | Intent | Use supplied intent or infer it from recent local agent transcripts | n/a |
| 2 | Rebase | Fetch fresh remote upstream and the configured branch target, then rebase your branch onto them | 3 |
| 3 | Review | AI code review of your diff | 0 (requires approval) |
| 4 | Test | Targeted local validation of the change and intent (not a full CI suite), plus evidence when intent is available | 3 |
| 5 | Document | Update docs when needed and report unresolved gaps | initial pass |
| 6 | Lint | Run lint/static analysis; shares the document step's initial housekeeping pass when no lint command is configured | 3 |
| 7 | Push | Safely push the validated branch to the configured target | n/a |
| 8 | PR | Create or update the pull request | n/a |
| 9 | CI | Watch CI + mergeability, auto-fix failures | 3 |
Why these steps, in this order
- Intent first so downstream agent prompts and generated PR descriptions can include author intent supplied by the agent or inferred from transcripts.
- Rebase next so everything else runs against the latest upstream and pushed-branch target.
It also stops when the branch would silently bundle commits from a local default branch that were never pushed to origin/<default_branch>.
If there's no diff left after the rebase, the pipeline skips the rest.
- Review before test so the agent reads fresh code, not code it may have touched during fixes.
A later run's initial review also receives fix-round provenance for any uncertified pipeline-authored commits left on the branch when a previous run's re-review did not complete.
- Document after test so docs are updated against code that's known to work.
- Lint last among local checks so it doesn't churn over code that may still change.
- Push → PR → CI happens after all local checks pass.
The push and CI auto-fix paths refuse to overwrite commits that reached the configured push target out of band.
CI is the only step that talks to the outside world for validation.
What each step can do
Every step can:
- Complete cleanly and advance the pipeline.
- Return findings with severity (error, warning, info) and an action (auto-fix, ask-user, no-op).
- Trigger auto-fix if the step's auto_fix limit is above 0, the step result is auto-fixable, and any finding is auto-fix-eligible. The document step applies safe documentation fixes during its initial pass and, when commands.lint is empty, combines that pass with initial safe lint fixes before the lint step consumes its findings.
- Pause for approval if blocking findings remain after auto-fix, or if any finding is ask-user.
- Skip when there's nothing to do (e.g., no diff, unsupported host).
- Fail on fatal errors and stop the pipeline.
See Auto-Fix Loop for how the fix cycle works, and Using the TUI for what the approval UI looks like.
What you can configure
You can't reorder steps. You can:
- Swap the agent, or configure an ordered fallback list, globally or per-repo.
- Set explicit commands.lint, commands.format, and an optional targeted commands.test (local intent validation only; not a full CI suite).
- Store test evidence locally by default or, on a supported provider, opt into publishing it to an orphan evidence branch with test.evidence.store_in_repo.
- Control auto-fix limits per step.
- Ignore paths during review and documentation checks.
- Disable or tune transcript-based intent extraction when intent is not supplied directly.
- Skip steps for one run with no-mistakes --skip <steps>, git push -o no-mistakes.skip=<steps>, no-mistakes axi run --skip <steps>, or from the TUI.
See Configuration.
What you can't configure
- The step order.
- Skipping specific steps permanently - per-run skips are allowed, but the pipeline itself always has all nine.
- Adding new steps.
This is intentional. The pipeline is opinionated so that "passed the gate" means the same thing across repos.
---
Src/Content/Docs/Reference/Cli
---
title: CLI Commands
description: Complete reference for all no-mistakes commands and flags.
---
no-mistakes
Attach to the active pipeline run for the current branch when one exists. If none exists, bare no-mistakes can start the setup wizard to create a branch, commit changes, push through the gate, wait for the daemon to register the new run, and then attach. If the push succeeds but no run is registered, that wizard path now exits with an explicit error instead of silently falling through. By default this wizard path is interactive and only runs in a TTY session. In non-interactive contexts, bare no-mistakes falls back to showing the last 5 runs inline unless you pass -y or --yes to run the wizard and accept defaults automatically. When a TTY is available, -y keeps the wizard visible, shows a brief waiting for run… state after push, and auto-advances the default path; without a TTY it falls back to the headless path.
no-mistakes
no-mistakes --skip test,lint| Flag | Type | Default | Description |
| ------------- | -------- | ------- | ---------------------------------------------------- |
| -y, --yes | bool | false | Run setup wizard and accept defaults automatically |
| --skip | string | (none) | Comma-separated pipeline steps to skip for a new run |
Unlike no-mistakes attach, bare no-mistakes only auto-attaches to an active run on the current branch.--skip only applies when bare no-mistakes starts a new pipeline run through the wizard; it does not skip a step on an already-active run.
Valid step names are intent, rebase, review, test, document, lint, push, pr, and ci.
no-mistakes init
Initialize or refresh the gate for the current repository.
init requires an origin remote to identify the upstream repository: later pipeline steps push validated branches to the configured target and open pull requests against that upstream. If origin is missing, add it with git remote add origin <url>, replacing <url> with the upstream repository's URL, then re-run init.
no-mistakes init
no-mistakes init --fork-url [email protected]:you/my-repo.git| Flag | Type | Default | Description |
| ------------ | -------- | ------- | ----------------------------------------------------------------------------- |
| --fork-url | string | (none) | GitHub fork remote URL to push branches to while opening PRs against origin |
Creates or refreshes a local bare repo, installs the managed pre-receive admission and post-receive notification hooks, best-effort isolates the gate repo's hook path from shared git config changes when Git supports config --worktree, adds or repairs the no-mistakes git remote, detects the default branch, records or updates the repo in SQLite, installs the /no-mistakes agent skill at user level into ~/.claude/skills/no-mistakes/SKILL.md and ~/.agents/skills/no-mistakes/SKILL.md, and ensures the daemon is running, installing the managed service when available and falling back to a detached daemon otherwise.init writes no skill files into the repo; the user-level copies cover every supported agent (~/.claude/skills for Claude Code, ~/.agents/skills for Codex, OpenCode, Rovo Dev, and Pi) across all repos.
If the home .claude links to .agents, .claude/skills links to .agents/skills, or the reverse, init follows that layout and still makes the skill readable from both logical paths.
If the repo still contains a vendored skill copy written by an older no-mistakes version, init leaves it untouched and prints a notice that it is no longer needed and can be removed.
The gate advertises Git push-option support, so you can skip steps for one push with git push -o no-mistakes.skip=test,lint no-mistakes <branch>.
For GitHub fork contributions, keep origin pointed at the parent repository and pass --fork-url with your fork remote URL.
The push, rebase branch-sync, and CI auto-fix pushes use the fork, while GitHub PR and CI commands stay scoped to the parent repository and create PRs with --head <fork-owner>:<branch>.
Fork routing currently requires both origin and --fork-url to be GitHub remotes with owner/repo paths.
Re-running init on an already-initialized repo succeeds and reports Gate already initialized (refreshed).
It refreshes managed gate wiring, origin/default-branch metadata, hook-path isolation, and the installed agent skill, overwriting any stale SKILL.md content from an older binary.
When a fork URL is already recorded, re-running init without --fork-url preserves it.
Passing --fork-url again replaces the stored fork URL after validation.
If you rename or move an initialized working directory and the old path no longer exists, re-running init from the new path reattaches the existing gate, preserves the repo ID and run history, and updates the stored working path.
If you copy an initialized working directory while the original still exists, the copy is treated as a separate repo and gets a fresh gate.
Fresh init rolls back gate setup when a required gate or daemon step fails; refresh does not eject a pre-existing gate if daemon startup fails.
Skill installation is best-effort: if the skill write fails, init reports it and leaves the working gate in place.
no-mistakes axi
Agent eXperience Interface for non-interactive agents.
Most agent workflows use the installed /no-mistakes skill, which drives this command surface underneath.
It prints TOON to stdout, prints progress to stderr, and uses structured stdout errors with exit code 1 for operational failures and 2 for bad usage.
At the TOON output boundary, unsupported C0 control bytes are rendered as visible \xNN escapes while tabs, carriage returns, newlines, printable Unicode, and the underlying durable logs remain unchanged.
If TOON encoding still fails, AXI prints a structured error instead of returning successful empty stdout.
The calling agent drives AXI approval gates but does not replace the configured pipeline agent that performs validation.
no-mistakes axiWith no subcommand, shows the executable path, description, repo, current branch, daemon state, recent runs, and next-step help, including a pointer to no-mistakes axi run --help and the installed /no-mistakes skill for full driving guidance.
When the current branch has an active run, that run appears as active_run with any approval gate and help for axi respond when it is parked or axi status when it is still running.
If an active run object is parked at a decision gate, it includes awaiting_agent: parked <duration> immediately after status.
That field is observability only; the gate: object still tells the agent which response to send.
If a step is actively running or fixing, the run object can also include an active_steps table with active_for, last_activity, native agent_pid when one is currently running, and the current execution or fix round.
When only another branch has an active run, that run appears as other_branch_active_run; the help tells agents to leave it alone and start validation for the current branch.
AXI help and outputs always repeat the preserve-prior-gate-progress contract: after a gate round has already produced fix commits, additional fixes belong on the same branch.
When a relevant branch_sync object is present, they also include version-matched synchronization guidance to follow before a post-pipeline local commit or fresh run.
Agents must not abort-and-restart, reset, replace the branch, or improvise Git recovery in a way that drops prior gate-fix commits.
A fresh run re-validates the current branch state, so already-resolved findings do not re-surface.
no-mistakes axi run
Start or reattach to validation for the current branch, blocking until the first approval gate, CI-ready decision point, or final outcome.
An active run on another branch does not block starting validation for the current branch.
no-mistakes axi run --intent "the user's goal"
no-mistakes axi run --intent "the user's goal" --skip test,lint
no-mistakes axi run --intent "the user's goal" --yes| Flag | Type | Default | Description |
| ------------- | -------- | ------- | ---------------------------------------------------------------- |
| --intent | string | (none) | What the user set out to accomplish; required to start a new run |
| -y, --yes | bool | false | Auto-resolve every gate until a decision point or outcome |
| --skip | string | (none) | Comma-separated pipeline steps to skip |
--intent is not a description of the diff.
It is the user's goal or request, and no-mistakes uses it verbatim instead of transcript inference.
Err on the side of completeness: include the goal, important decisions and tradeoffs, constraints or approaches ruled in or out, and explicit requests that might otherwise look surprising in the diff.
When starting a new run, axi run refuses the default branch and uncommitted working trees with actionable errors instead of auto-branching or auto-committing.
Reattaching to an in-flight run does not require --intent.
Reattachment accepts either the run's immutable submitted head or its current pipeline head, so pipeline-created fix commits do not detach an unchanged submitting worktree.
When neither identity matches, axi run keeps the fresh-run path but refuses a gate push while branch_sync says the pipeline still owns the branch.
That refusal returns the complete structured state and its continue_active_run or recover_custody next action instead of a raw Git non-fast-forward.
Reattaching to an in-flight run can proceed while the daemon is already running even if the global config file has become invalid, but starting a fresh run still requires valid global config.
Starting a fresh run also requires a runnable effective pipeline agent.
If the configured native agent or ACP runner is unavailable, the run fails before any pipeline step starts instead of reporting command-only validation as a passed gate.
With --yes, axi run treats both action: auto-fix and action: ask-user findings as standing consent for the pipeline to fix them by selecting every finding, then accepts the resulting fix review.
Gates with no findings or only action: no-op findings are approved as-is, and each step is fixed at most once so unresolved findings do not loop forever.
Without --yes, an agent driving axi run should stop when a gate contains action: ask-user findings and relay each finding's ID, file, and full description to the user before responding.
Review gates include a note field reminding agents that auto_fix.review defaults to 0, so blocking and ask-user review findings park for a decision unless configuration explicitly opts back into review auto-fix.
Long-running axi run calls are working, not stalled; if one returns a gate:, read that output and answer it with axi respond.
Backgrounding a call is fine for an agent harness, but the run never advances past a gate on its own.
When the CI step is still monitoring an open PR and checks are green - or the trusted default-branch config declares no_ci: true with no registered checks - axi run exits successfully with outcome: checks-passed instead of waiting for a human merge. A generic empty check list without that declaration is not ready.
Treat that as the agent stopping point: ask the user to review and merge the PR from the help line.
If that PR later falls behind the default branch or hits a merge conflict, do not run axi run, rerun, or a manual rebase while the CI monitor is still running.
The monitor auto-rebases onto the base, resolves actual conflicts, and re-pushes the branch; a PR that is merely behind but clean needs no command.
Use no-mistakes rerun only after that monitor is no longer running, such as a closed PR, aborted or superseded run, idle timeout, or exhausted CI auto-fix attempts.
Successful outcomes (checks-passed and passed) also carry help instructions telling the agent to summarize the run.
When the pipeline applied fixes, they include a fixes table and a help instruction to acknowledge the misses and list those fixes for the user's review.
no-mistakes axi respond
Answer the current approval gate and continue until the next gate, CI-ready decision point, or final outcome.
no-mistakes axi respond --action approve
no-mistakes axi respond --action fix --findings F1,F2 --instructions "optional guidance"
no-mistakes axi respond --action fix --add-finding '{"description":"...","action":"auto-fix"}'
no-mistakes axi respond --action skip| Flag | Type | Default | Description |
| ---------------- | -------- | ------------- | -------------------------------------------------------------------- |
| --action | string | (none) | approve, fix, or skip; required |
| --step | string | awaiting step | Step to respond to |
| --findings | string | (none) | Comma-separated finding IDs for --action fix |
| --instructions | string | (none) | Guidance applied to selected findings |
| --add-finding | string | (none) | JSON finding object to add and fix |
| -y, --yes | bool | false | Auto-resolve every subsequent gate until a decision point or outcome |
After the explicit response, --yes uses the same auto-resolution behavior as axi run --yes: have the pipeline fix auto-fix and ask-user findings once, approve the fix review, approve gates that only contain non-actionable no-op findings, and stop at outcome: checks-passed when the CI monitor reports readiness but the PR still needs a human merge.
Each axi respond blocks until the next gate, CI-ready decision point, or final outcome.
If it returns another gate:, answer that gate; do not idle-wait for the run to move forward by itself.
When the daemon is already running, axi respond can continue an active run even if the global config file has become invalid, because it is not starting a fresh run.
The same successful-output reporting instructions apply to axi respond results.
no-mistakes axi status
Show a run, preferring the current branch's active or most recent run before falling back to repo-wide active or recent runs.
no-mistakes axi status
no-mistakes axi status --run <id>| Flag | Type | Default | Description |
| ------- | -------- | ------------ | ------------------------- |
| --run | string | resolved run | Inspect a specific run ID |
When the resolved run is parked at an awaiting_approval or fix_review gate, its top-level run: object includes awaiting_agent: parked <duration> immediately after status.
The field disappears after axi respond, on cancel, and on terminal outcomes; use it to distinguish a run waiting for the driving agent from one actively running, fixing, or watching CI.
When the resolved run has a running or fixing step, the run object includes active_steps.
Each row reports how long the step has been active, the latest meaningful log or native-agent lifecycle activity, the native agent PID if one is currently running, and the current round such as round 1, auto-fix 1/3, or fix 2.
If no activity arrives for longer than step_quiet_warning, last_activity is prefixed with quiet; this is only a liveness signal and does not cancel the step.
For older active runs with no recorded activity timestamp, AXI falls back to the step log file modification time.
Gate summaries and finding descriptions are bounded in this default status view; truncated values disclose their original length, and the gate help points to no-mistakes axi logs --step <step> --full for the complete step log.
Relevant current-branch states also include a cached branch_sync object with full SHAs, the run's status, the persisted pipeline push binding, target kind and ref, relation, safety result, PR lifecycle, and a structured next action.
Cached home and status rendering performs no network read and labels the remote observation pipeline_push; only explicit sync check or apply reports live freshness.
no-mistakes axi sync
Freshly check or apply the guarded synchronization offered by a branch_sync.next_action.
no-mistakes axi sync --check
no-mistakes axi sync
no-mistakes axi sync --recover
no-mistakes axi sync --recover --keep-local| Flag | Type | Default | Description |
| -------------- | ------ | ------- | ---------------------------------------------------------------------------- |
| --check | bool | false | Verify the live target and exact plan without changing HEAD |
| --recover | bool | false | Return custody of a branch stranded by a terminal run with unpublished pipeline commits (a no-op when cancellation already released the branch) |
| --keep-local | bool | false | With --recover: keep the current local head; never touches the worktree |
The default command is an explicit non-interactive apply request and never prompts.
All modes return the complete branch_sync object as TOON.
Exit code 0 means an eligible check, applied synchronization or recovery, already-synchronized, custody-returned, or user-owned no-op, or expected merged-and-removed no-op; blocked operational states return 1.
The ordinary worktree mutation is either a strict fast-forward of the invoking clean checked-out branch to the freshly verified pipeline-owned pushed SHA, or an equivalent-diverged advance.
When a clean local branch and the pipeline-pushed head are diverged but the local unique work is content-equivalent to work already represented in the live pipeline head, sync reports safety: safe_equivalent_advance, anchors the pre-sync head under refs/no-mistakes/sync-anchor/<run>, and moves to the pipeline head with reset semantics.
Genuine divergence still reports safety: blocked_diverged and changes nothing.
Under --recover, the possible worktree mutation is a strict fast-forward to the preserved pipeline head, or an adoption of a preserved head proven to carry every local change, both after relation-specific preservation checks.
When the local gate branch is exactly at a newer same-branch pushed binding and Git proves that an older terminal run's unpublished preserved head is its ancestor, branch synchronization selects the newer binding; missing gate evidence, non-ancestor heads, or different or ambiguous target provenance remain blocked.
Fork configurations verify the configured fork URL and exact feature ref rather than assuming origin.
Dirty, in-progress, ahead, genuinely diverged, detached, wrong-branch, offline, changed-target, rewritten, deleted, legacy, or retired states fail closed without destructive recovery.
Run axi sync only when structured output offers next_action.code: sync; process any blocked state instead of substituting reset, stash, merge, rebase, force, or branch replacement.
Custody recovery
A run that goes terminal (cancelled, failed, or completed without a push stage) after moving the pipeline head leaves the branch pipeline_owned with safety: blocked_pipeline_owned_recoverable, the run's terminal pipeline.status, the exact submitted_head/current_head/relation ownership facts, and next_action.code: recover_custody.
A run whose terminalization verifies that the managed worktree head never changed from the submitted head releases the branch instead: the terminal outcome, including cancellation, ends ownership; status reports state: user_owned with the same exact ownership facts and no next_action; the branch and head are immediately usable for any separately authorized delivery; and nothing blocks a direct push or PR.
Without that positive terminal head evidence, custody stays recoverable rather than being guessed away.
While a run is still active, it reports state: pipeline_owned, the exact submitted/current heads and their relation, and next_action.code: continue_active_run with no-mistakes axi status, even when its head has not moved yet.--recover verifies the run is terminal, anchors the preserved head under refs/no-mistakes/recover/<run> in the invoking repository, and stamps custody returned so a fresh run can start.
For equal or ahead worktrees where the preserved head is already locally reachable, recovery writes that anchor locally without gate access.
For behind or diverged worktrees, recovery verifies the preserved head at the local gate branch and fetches it into the anchor before moving or refusing.
A clean behind worktree fast-forwards.
A diverged worktree is adopted only when the preserved head provably carries every local change, proven by an executable three-way merge whose result is exactly the preserved head's tree.
This covers a pipeline rebase onto a newer base once a later pipeline commit has also advanced the gate branch to the preserved head.
A rebase-only cancelled run can still refuse recovery because its detached worktree advances the recorded run head without advancing that gate branch; use no-mistakes rerun in that case.
That adoption anchors the pre-recovery local head under refs/no-mistakes/recover-local/<run>, then moves the branch with Git operations that refuse on their own rather than after a preceding check: an atomic compare-and-swap on the branch ref, and a working-tree update that aborts instead of overwriting a modified or untracked file.
The proof is deliberately narrow and never uses patch identity, which discards hunk locations and whitespace and so cannot tell a genuine replay from a same-shaped edit elsewhere.
Anything it cannot decide - unlanded local commits, or a rebase whose fix rounds also rewrote your own lines - still refuses with the anchor named, because only escalation can tell a deliberate pipeline fix apart from a dropped change.
A dirty worktree refuses with explicit choices.
When you explicitly keep a behind or diverged local head instead of taking the preserved head, --keep-local returns custody at the current head without touching the worktree and atomically points the gate branch at it, so a concurrent gate push wins and the recovery refuses instead.no-mistakes rerun is the alternative exit that resumes validating the preserved head instead of taking the branch back.
A recovered never-pushed run reports state: custody_returned; a recovered pushed run reports its ordinary classification against the last push binding, typically local_ahead.
On a user_owned branch, --recover is an idempotent no-op success: nothing pipeline-created exists to recover, and no file, ref, or database row changes.
no-mistakes axi logs
Show the log output of one pipeline step.
no-mistakes axi logs --step review
no-mistakes axi logs --step review --full
no-mistakes axi logs --step review --run <id>| Flag | Type | Default | Description |
| -------- | -------- | ------------ | --------------------------------------- |
| --step | string | (none) | Step name; required |
| --run | string | resolved run | Run ID to inspect |
| --full | bool | false | Show the entire log instead of the tail |
Without --full, long logs show the last 40 lines and a help hint for the full log.
Step logs include native subprocess agent lifecycle lines such as codex started pid=4242, codex exited pid=4242 status=success, and transient retry messages when the selected agent supports lifecycle events.
They also include fix-loop markers such as auto-fix round 1/3 starting after round 1 and user-fix round starting after round 2.
no-mistakes axi abort
Cancel the active run for the current branch.
Active runs on other branches are left alone.
no-mistakes axi abortIf there is no active run, this succeeds as a no-op.
Pass --run <id> to cancel a specific run by its id instead of resolving the current branch:
no-mistakes axi abort --run <id>--run does not need a repo, branch, or worktree, so it works from anywhere.
Use it to reap an orphaned CI monitor whose worktree was torn down before the PR merged - the run id is shown in axi run output and in the axi home view.
A --run id that is not currently active is resolved against the exact run's durable record rather than trusted blindly: a known already-terminal run returns an idempotent success carrying its terminal run_status with no fabricated new cancellation, a positively proven unknown id keeps the documented successful no-op with no fabricated state, and a run that is recorded as still nonterminal or cannot be read returns the nonzero terminal-unconfirmed contract.
When the daemon is not running, nothing can be cancelled and abort never starts one: the durable record alone decides the same three outcomes, and a recorded nonterminal run reports that cancellation could not be requested.
When the daemon is already running, axi abort can cancel an active run even if the global config file has become invalid, because it is not starting a fresh run.
Both abort surfaces report a completed cancellation only after the exact run positively confirms a terminal state within the bounded wait; success then includes the terminal run_status, and branch-scoped abort renders the refreshed branch_sync object and its exact next action, if any.
When terminal quiescence cannot be confirmed - the bounded wait expires, the wait is cancelled, or a status read fails - abort exits nonzero, states explicitly that cancellation was requested but terminal quiescence is unconfirmed, includes the last structured run state when one is available, and never claims aborted: true or presents user-owned or recoverable ownership guidance as authoritative; re-run the abort or watch axi status --run <id> until a terminal status is confirmed.
Pipeline-created commits remain preserved in the gate and a recoverable cancellation points directly to no-mistakes axi sync --recover; when the submitted head never moved, cancellation instead reports state: user_owned with no sync action.
While a run is active, do not use axi abort or no-mistakes rerun to go fix a finding yourself.
That cancels the pipeline's in-flight work and forces a full re-validation; use axi respond --action fix at the gate so the pipeline applies and re-checks the fix.
no-mistakes eject
Remove the gate from the current repository.
no-mistakes ejectRemoves the no-mistakes remote, deletes the bare repo directory, cleans up worktrees, and deletes the database record (cascades to runs and steps).
It does not remove any legacy repo-local agent skill files left by older versions; current init installs the skill at user level instead.
no-mistakes attach
Attach to the active pipeline run.
no-mistakes attach [--run <id>]| Flag | Type | Default | Description |
| ------- | -------- | ------- | ----------------------------------------------------- |
| --run | string | (none) | Attach to a specific run ID instead of the active run |
Opens the TUI for the active run anywhere in the current repo. If --run is specified, attaches to that specific run regardless of branch. Unlike bare no-mistakes, this does not stay branch-scoped before falling back.
no-mistakes rerun
Rerun the pipeline for the current branch.
no-mistakes rerun
no-mistakes rerun --intent "the revised user goal"Starts a new pipeline run using the last-known head SHA on the current branch.
If the selected prior run has explicit intent, rerun inherits it exactly by default;
otherwise it performs fresh intent inference. --intent supplies a new canonical
explicit intent in either case. Inherited intent keeps distinct rerun provenance;
an override is recorded as newly supplied explicit intent, while fresh inference
records the transcript source. If another run is active on that branch, rerun
cancels it before starting over. Treat rerun as a between-runs action after a
failed or cancelled outcome, or after you have committed a separate fix outside
an active run; do not use it to bypass a gate.
| Flag | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| --intent | string | (none) | Explicit intent overriding inherited intent or fresh inference |
no-mistakes sync
Freshly verify and, with confirmation, safely move the invoking branch to an exact pipeline-owned push binding.
no-mistakes sync
no-mistakes sync --check
no-mistakes sync --yes
no-mistakes sync --recover
no-mistakes sync --recover --keep-local| Flag | Type | Default | Description |
| -------------- | ------ | ------- | --------------------------------------------------------------- |
| --check | bool | false | Verify and print the fresh plan without changing HEAD |
| -y, --yes | bool | false | Apply an eligible guarded synchronization without an interactive prompt |
| --recover | bool | false | Return custody of a branch stranded by a terminal run with unpublished pipeline commits (a no-op when cancellation already released the branch) |
| --keep-local | bool | false | With --recover: keep the current local head; never touches the worktree |
Without --yes, apply prints the exact full-SHA plan and requires TTY confirmation; --recover prompts the same way before returning custody.
A non-TTY apply or recovery refuses with a direct --yes hint.
The command uses the same service and safety contract as no-mistakes axi sync, including the guarded equivalent advance and custody recovery documented there; it never stashes, rebases, creates a merge commit, switches branches, deletes a branch, or updates an external remote.
no-mistakes status
Show repo, daemon, active run, and relevant cached local-branch synchronization status.
no-mistakes statusDisplays:
- Repo path, upstream URL, and fork URL when configured
- Gate path
- Daemon status (running/stopped, PID)
- Active run details: ID, branch, status, head SHA, start time
no-mistakes runs
List recorded pipeline runs for the current repo.
no-mistakes runs [--limit <n>]| Flag | Type | Default | Description |
| --------- | ----- | ------- | --------------------------------- |
| --limit | int | 10 | Maximum number of runs to display |
Shows runs newest-first with branch, status (styled), short SHA, timestamp, and PR URL if set.
no-mistakes eval
Inspect the locally collected review-case corpus before spending tokens, replay an explicit agent and model in isolation, and report finding-level scores, token cost, wall time, and the recall-versus-cost frontier. Eligible cases are collected automatically as runs finish; eval capture <run-id> collects one on demand; eval miss ingest <run-id> --finding '<json>' labels a confirmed post-PR miss (review passed green, later caught) as false-negative gold.
See Evaluation toolkit for the local-only boundary, collection and retention, command flags, label policy, and reporting semantics.
no-mistakes stats
Show historical usage stats across all repos.
no-mistakes statsDisplays total changes, rescued changes, rescue rate, reported and fixed mistakes, fixes by pipeline step, and the top repos by rescue activity.
Use --agents for local, per-purpose agent performance aggregates: duration and the subprocess-vs-model time split, session mode, errors, the token totals (input, output, cache-read, cache-creation, fresh input, reasoning), and the model round-trip and tool-category activity histogram, with a METRICS coverage count that tells a real zero apart from missing instrumentation.
Use --run <id> to inspect the individual agent invocations for one run - including each invocation's per-round token deltas next to the raw (cumulative for resumed sessions) counters, tool-category breakdown, workload size, finding count, and fallback reason - plus the total time parked at approval gates; it implies --agents.
Nullable fields an adapter did not report render as - (unknown), which is distinct from a recorded 0; the legacy raw input, output, and cache-read counters remain numeric.
no-mistakes stats --agents
no-mistakes stats --run <id>This detailed performance evidence stays local in state.sqlite; it is not sent to telemetry.
The field definitions and their local/remote split are owned by the environment reference.
no-mistakes doctor
Check system health and dependencies.
no-mistakes doctorChecks:
- git binary
- gh CLI (optional, needed for GitHub PR and CI steps)
- az CLI (optional, needed for Azure DevOps PR and CI steps)
- Data directory (~/.no-mistakes/)
- SQLite database
- Daemon status
- Agent runners: native binaries claude, codex, acli, opencode, pi, and copilot, plus the optional ACP bridge acpx
- ACP alias default binaries: cursor-agent plus acpx for cursor
- Effective global agent configuration, reported as gate validation; an unavailable configured runner is a failed check because the gate cannot validate without it
Uses indicators: ✓ (available), – (not found, optional), ✗ (problem detected).
The standalone runner rows inspect default binary names; the cursor row reports whichever of cursor-agent and acpx are missing.
The Global Config Reference owns ACP gate-validation availability and probing semantics.
Each validation run performs the authoritative agent resolution again after applying any trusted repository-level override.
doctor checks gh and az availability. For GitLab PR and CI steps, install and authenticate glab. For Bitbucket Cloud PR and CI steps, set NO_MISTAKES_BITBUCKET_EMAIL and NO_MISTAKES_BITBUCKET_API_TOKEN. For Azure DevOps PR and CI steps, install the azure-devops extension and provide a PAT.
no-mistakes update
Update the installed binary and reset the daemon.
no-mistakes update
no-mistakes update --beta
no-mistakes update -y
no-mistakes update --forceDownloads the latest release, verifies the SHA-256 checksum, atomically replaces the running binary, and resets the daemon when it is running or stale daemon artifacts exist so the new executable is picked up, preferring the managed service path and falling back to a detached daemon if service startup is unavailable or fails.
By default this installs the latest stable release.
Pass --beta to include prereleases and install the latest beta when one is newer than the current stable release.
If the daemon is running from a different executable path, update still prompts before replacing it; pass -y/--yes to answer that prompt non-interactively.
If the daemon executable path cannot be determined, the update aborts before replacement.
If the daemon does not come back cleanly after a successful replacement, the command reports that failure.
On macOS, removes the quarantine extended attribute.
Daemon & Worktrees
owns the active-run guard, the scope of --force and --yes, and recursive
validation-step containment.
Because update installs the latest official release binary, the replacement binary includes the default self-hosted telemetry host and website ID. Disable telemetry with NO_MISTAKES_TELEMETRY=0, or override the host and website ID with NO_MISTAKES_UMAMI_HOST and NO_MISTAKES_UMAMI_WEBSITE_ID.
Background update checks run automatically on each CLI invocation (except update itself and version queries --version / -v, which stay side-effect-free). If a newer version is available, a notification is printed to stderr. Suppressed for dev builds or when NO_MISTAKES_NO_UPDATE_CHECK=1 is set.
no-mistakes daemon start
Start the daemon, installing or refreshing the managed service when possible.
no-mistakes daemon startPrefers the managed service path and falls back to a detached daemon if service install or startup is unavailable or fails. If the daemon is already running, the command refreshes a stale macOS launchd or Linux systemd service definition and restarts through the managed service; if the definition is unchanged, it reports that the daemon is already running. Daemon & Worktrees owns the startup readiness, timeout, fallback cleanup, and singleton lifecycle details.
no-mistakes daemon stop
Stop the running daemon process.
no-mistakes daemon stop
no-mistakes daemon stop --forceDaemon & Worktrees
owns the active-run guard, the scope of --force, and recursive
validation-step containment.
This does not remove the managed service. A later no-mistakes, no-mistakes daemon start, init, attach, rerun, or update can start the daemon again through the same service manager when available, or as a detached daemon otherwise.
no-mistakes daemon restart
Restart the daemon.
no-mistakes daemon restart
no-mistakes daemon restart --forceStops the current daemon and starts it again. This works whether the daemon is currently running or not.
Daemon & Worktrees
owns the active-run guard, the scope of --force, and recursive
validation-step containment.
no-mistakes daemon status
Check whether the daemon is running.
no-mistakes daemon statusShows the PID if the daemon is running.
---
Src/Content/Docs/Reference/Environment
---
title: Environment Variables
description: All environment variables recognized by no-mistakes.
---
NM_HOME
Override the data directory.
| | |
| ------- | ---------------- |
| Type | string |
| Default | ~/.no-mistakes |
When set, everything else moves under this root:
- Global config: $NM_HOME/config.yaml
- Gate repos: $NM_HOME/repos/<id>.git
- Worktrees: $NM_HOME/worktrees/<repoID>/<runID>/
- Logs: $NM_HOME/logs/
- Database: $NM_HOME/state.sqlite
- Socket / PID / singleton lock: $NM_HOME/socket, $NM_HOME/daemon.pid, and $NM_HOME/daemon.lock
- Managed agent server PID records: $NM_HOME/servers/
- Local evaluation cases and registry: $NM_HOME/eval/ (created by automatic collection or an explicit no-mistakes eval command)
- Managed service names get a short stable suffix derived from $NM_HOME so multiple installs don't collide.
NM_DAEMON_CONNECT_TIMEOUT
Override how long a CLI client waits for an existing daemon socket to accept a connection before failing instead of hanging.
| | |
| ------- | ------------------------------------------------------------------------------------------------- |
| Type | string (Go duration) |
| Default | unset (falls back to the daemon_connect_timeout global config value, itself defaulting to 3s) |
Takes precedence over daemon_connect_timeout in config.yaml. An empty, unparsable, or non-positive value is ignored and the config value (or its default) is used instead.
NO_MISTAKES_BITBUCKET_EMAIL
Bitbucket Cloud account email used for PR creation and CI monitoring.
| | |
| ------- | --------------------------------------------- |
| Type | string |
| Default | (none; Bitbucket PR/CI steps skip when unset) |
Used alongside NO_MISTAKES_BITBUCKET_API_TOKEN. See Provider Integration.
NO_MISTAKES_BITBUCKET_API_TOKEN
Bitbucket Cloud API token.
| | |
| ------- | -------- |
| Type | string |
| Default | (none) |
Get one from Bitbucket account settings.
NO_MISTAKES_BITBUCKET_API_BASE_URL
Override the Bitbucket Cloud API base URL.
| | |
| ------- | ------------------------------- |
| Type | string |
| Default | https://api.bitbucket.org/2.0 |
Useful for mocking in tests or pointing at a proxy.
AZURE_DEVOPS_EXT_PAT
Azure DevOps Personal Access Token inherited by the daemon for non-interactive az CLI auth.
Alternatively, authenticate the Azure DevOps extension with az devops login.
| | |
| ------- | -------------------------------------------------- |
| Type | string |
| Default | (none) |
See Provider Integration.
GITHUB_TOKEN
GitHub token used to authenticate updater release requests.
| | |
| ------- | -------- |
| Type | string |
| Default | (none) |
When set, the updater sends the token as a Bearer authorization header for release metadata requests, including background update checks, and release asset downloads. GITHUB_TOKEN takes precedence over GH_TOKEN; when neither variable is set, these requests remain anonymous. The token is not printed, logged, or persisted.
GH_TOKEN
Fallback GitHub token used by no-mistakes update when GITHUB_TOKEN is unset or empty.
| | |
| ------- | -------- |
| Type | string |
| Default | (none) |
See GITHUB_TOKEN for the updater's authentication behavior and precedence.
NO_MISTAKES_NO_UPDATE_CHECK
Disable background update checks.
| | |
| ------- | ---------------------------------------------- |
| Type | 1 to disable, anything else to leave enabled |
| Default | unset (checks enabled) |
Update checks run on every CLI invocation except update itself and version queries (--version / -v, which stay side-effect-free), hit GitHub releases, cache the result in $NM_HOME/update-check.json, and print a one-line notification to stderr when a newer version is available. Dev builds (non-semver versions) suppress the check automatically.
XDG_DATA_HOME
Data directory used to discover OpenCode transcripts for intent extraction.
| | |
| ------- | ---------------- |
| Type | string |
| Default | ~/.local/share |
When set, no-mistakes looks for OpenCode's intent transcript database at $XDG_DATA_HOME/opencode/opencode.db.
When unset, it falls back to ~/.local/share/opencode/opencode.db.
GLAB_CONFIG_DIR
Directory holding glab's config.yml, consulted when detecting self-hosted GitLab.
| | |
| ------- | -------- |
| Type | string |
| Default | (none) |
When the upstream hostname carries no gitlab marker, no-mistakes reads glab's configured hosts from $GLAB_CONFIG_DIR/config.yml to decide whether the host is a GitLab instance. It takes precedence over XDG_CONFIG_HOME. See Provider Integration.
GH_CONFIG_DIR
Directory holding gh's hosts.yml, consulted when detecting self-hosted GitHub Enterprise.
| | |
| ------- | -------- |
| Type | string |
| Default | (none) |
When the upstream hostname is not github.com, no-mistakes reads gh's configured hosts from $GH_CONFIG_DIR/hosts.yml to decide whether the host is a GitHub Enterprise instance. It takes precedence over XDG_CONFIG_HOME. See Provider Integration.
XDG_CONFIG_HOME
Config directory used to locate glab's config.yml for self-hosted GitLab detection and gh's hosts.yml for self-hosted GitHub Enterprise detection.
| | |
| ------- | ----------- |
| Type | string |
| Default | ~/.config |
When GLAB_CONFIG_DIR is unset, no-mistakes looks for glab's configured hosts at $XDG_CONFIG_HOME/glab-cli/config.yml, falling back to ~/.config/glab-cli/config.yml when XDG_CONFIG_HOME is unset.
When GH_CONFIG_DIR is unset, no-mistakes looks for gh's configured hosts at $XDG_CONFIG_HOME/gh/hosts.yml, falling back to ~/.config/gh/hosts.yml when XDG_CONFIG_HOME is unset.
NO_MISTAKES_UMAMI_HOST
Override the telemetry collection host.
| | |
| ------- | --------------------------- |
| Type | URL |
| Default | https://a.kunchenguid.com |
When set, telemetry sends events to this host's /api/send endpoint. If it is unset in a dev build, no-mistakes also checks a repo-local .env file for NO_MISTAKES_UMAMI_HOST. If no runtime value is found, it falls back to any host embedded at build time and then the default self-hosted Umami instance.
NO_MISTAKES_UMAMI_WEBSITE_ID
Override or enable the telemetry website ID.
| | |
| ------- | ----------------------------------------------------------------------- |
| Type | string |
| Default | embedded in Makefile and release builds; unset in unembedded dev builds |
When set, telemetry uses this website ID at runtime. If it is unset in a dev build, no-mistakes also checks a repo-local .env file for NO_MISTAKES_UMAMI_WEBSITE_ID. If no runtime value is found, it falls back to any website ID embedded at build time.
When telemetry is enabled, no-mistakes sends command, run, approval, fix, and wizard events, completed step events with awaiting_approval, fix_review, or failed status, and pageviews for the human surfaces /wizard and /tui and the state-changing agent surfaces /axi/run, /axi/respond, and /axi/abort to Umami.
Mutation pageviews are sent alongside command events, so command status and duration remain available.
They include only flag-derived context: /axi/run records whether --yes, --intent, or --skip was present, and /axi/respond records the sanitized action and whether --yes was present.
Read-only surfaces (axi home, axi status, axi logs, status, runs) emit no pageview and rate-limit their command event: it is sent when the observed run state changed since the last emit, and otherwise at most once per 10 minutes, with the dedupe state persisted at <NM_HOME>/telemetry-gate.json so agent polling loops stay bounded across processes.
The axi logs command event records the sanitized step, whether --full was present, and whether --run was present; axi status records whether --run was present.
Each explicit human CLI, AXI, or TUI branch-sync check/apply attempt emits one command event and no additional pageview.
Its fields are bounded enums and booleans only: surface, mode, state, relation, target kind, pipeline phase, PR state, result, refusal reason, dirty state, and duration.
It never sends a SHA, run ID, path, branch name, URL, remote name, or command argument.
What stays local and what leaves the machine
Everything sent remotely is low-cardinality: command names, statuses, durations, counts, flag booleans, agent and step names, and - on the single terminal run finished event - the bounded performance rollup agent_invocations, resumed_invocations, and fallback_invocations (small counts only).
Run IDs, repository paths, branch names, session identities, prompts, model outputs, diffs, and per-invocation performance records are never sent.
Detailed performance evidence stays on the machine in the local state database (<NM_HOME>/state.sqlite): one agent_invocations row per agent invocation, plus each run's accumulated parked-at-gate time.
Each row records run and step identity, purpose (such as review/review-fix/housekeeping), the reported model and its provider, the cold/started/resumed/fallback session mode, a truncated session-identity hash, timestamps, duration, exit status, and failure category, alongside the session-fidelity metrics below.
It never stores prompts, model outputs, diffs, raw command arguments, secret values, or credentials - only bounded counts, low-cardinality categories, and durations.
The additive session-fidelity fields are nullable and read back as unknown (rendered -) rather than a fabricated zero when the adapter did not report them, so rows written before a field existed, and adapters that do not surface a datum, stay honest.
The legacy raw input, output, and cache-read token counters render numerically; use the nullable per-round and derived fields to determine whether the adapter reported comparable usage:
- Token detail: input_tokens/output_tokens/cache_read_tokens (raw, cumulative across a resumed session for codex), fresh_input_tokens (input minus cache reads), cache_creation_tokens (unknown when the provider does not surface it), reasoning_tokens, and delta_input_tokens/delta_output_tokens/delta_cache_read_tokens (the correct per-round amounts, so a resumed session's cumulative counter is never mistaken for one round's usage).
- Activity: model_roundtrips (a proxy for productive model turns), tool_calls, and a bounded tool-category histogram (tool_wait_calls, tool_test_lint_calls, tool_edit_calls, tool_read_calls, tool_git_calls, tool_other_calls); a compound command counts once per sub-command, so the histogram can sum higher than tool_calls.
- Timing split: subprocess_wait_ms is the wall-clock spent inside tool subprocesses; model/reasoning time is the invocation duration minus it, clamped at zero.
- Context: workload_files/workload_lines (bounded change size), finding_count (findings in the structured output), and fallback_reason (why a failed resume forced a fresh session, one of transient/parse/exit/spawn/unsupported/other).
The count and timing definitions live in one authoritative place (internal/agent/invocationmetrics.go).
Inspect the evidence with no-mistakes stats --agents (per-purpose aggregates, including a METRICS coverage count so a real zero is distinguishable from missing instrumentation) or no-mistakes stats --run <id> (one run's invocations, the per-round-vs-cumulative token split, and parked time).
NO_MISTAKES_TELEMETRY
Disable telemetry collection.
| | |
| ------- | ----------------------------------------------------------------- |
| Type | 0, false, or off to disable; anything else to leave enabled |
| Default | unset |
When set to a disabling value, telemetry stays off even if a runtime or embedded website ID is available.
Environment the daemon sees
When the daemon runs through a managed service (launchd, systemd user service, Task Scheduler), the macOS and Linux service definitions include a default PATH with common user and system binary directories. They also bake in any proxy variables (HTTP_PROXY, HTTPS_PROXY, NO_PROXY, ALL_PROXY) that were set when you installed or refreshed the service, so the daemon and the agents it spawns can reach the network through your proxy even when the login-shell probe is unavailable. Once baked in, the values are preserved across later service refreshes and restarts even when the proxy variables are not exported in that shell, so a routine daemon restart or a binary upgrade will not strip them; export the variables again only when you need to change or remove them. Both the upper- and lower-case spellings are forwarded exactly as you set them, because tooling is inconsistent about which it reads (curl, for example, honors only the lower-case http_proxy for plain-HTTP requests). Because a proxy URL can embed credentials (for example http://user:pass@host), the generated service file is restricted to owner-only 0600 permissions whenever proxy values are forwarded into it. When no proxy variables are set, the generated definition is unchanged and keeps the conventional 0644 mode. Windows Task Scheduler inherits your logon environment and needs no forwarding. At daemon startup, the daemon resolves environment from your login shell on macOS and Linux, preserves your shell PATH order, and appends any missing well-known directories such as ~/.local/bin, ~/go/bin, ~/.cargo/bin, ~/bin, /opt/homebrew/bin, /usr/local/bin, /usr/bin, and /bin. If login-shell resolution fails or returns no entries, the daemon logs a warning and uses an augmented process-environment fallback that may omit version-manager directories such as nvm, fnm, or volta. On Windows it reuses the current process environment.
If your env vars aren't set in your login shell's rc files (.zprofile, .zshrc, .profile, .bash_profile, .bashrc, PowerShell profile), the daemon won't see them. Put them somewhere a login shell will load, then restart the daemon to pick them up.
---
Src/Content/Docs/Reference/Eval
---
title: Evaluation toolkit
---
no-mistakes eval is a local-only toolkit for comparing review candidates against review passes your own pipeline has already recorded.
The corpus collects itself: eligible finished runs' decided review passes become cases, so the sets are populated by the time you want to compare something. Replay and reporting stay explicit commands you run.
The eval commands do not start or use the shared daemon, alter a gate, emit remote telemetry, push a branch, open a PR, or run CI. Cases, source findings, decisions, candidate outputs, and metrics are stored only under <NM_HOME>/eval/; there is no export, sharing, synchronization, or remote case store.
Replay does invoke the selected agent normally, so that agent may send the restored code and review context to its configured model provider. The local-only guarantee concerns eval storage and transport added by no-mistakes, not the selected agent's ordinary provider traffic.
How cases are collected
Cases arrive on their own. When an eligible run finishes, its decided Review passes are frozen into the local corpus - one case per pass. Collection happens after the pipeline has already reported its outcome, so it can never change or fail the run; a problem is logged and nothing else.
Two settings in config.yaml govern it, both on by default and both documented in Global configuration:
- eval.capture_provenance records the exact commit and configuration inputs a replay needs. It is written when the review round is written and cannot be added afterwards, so a run reviewed with it off is never capturable - not by the automatic path and not by hand.
- eval.auto_capture performs the collection. Turning it off leaves provenance recorded, so runs stay capturable by hand.
You can also capture a specific run yourself:
no-mistakes eval capture <run-id>A confirmed post-PR miss - review passed green, and a later human-vetted finding showed a real defect - is ingested as false-negative gold through the same local corpus:
no-mistakes eval miss ingest <run-id> \
--finding '{"id":"stable-id","file":"path.go","line":12,"severity":"error","description":"one-sentence defect"}'--finding is repeatable. The command captures the run if needed (recapture is a no-op, so existing labels survive), then writes false-negative gold onto the last completed non-blocking review pass. Duplicate finding IDs are no-ops. A parked or blocking review is refused: that class found something, so it is not a post-PR miss.
The ingest payload is the source of truth. Eval does not scrape GitHub review comments and does not read an external markdown ledger. The curator (a human, or an automation that already vetted the miss) supplies the structured finding.
Automatic collection and eval capture do the same freeze, so a case is equally trustworthy either way. Capturing a run that was already collected relabels gold from later merge evidence and otherwise leaves the frozen case in place. eval miss ingest can still attach confirmed post-PR-miss gold afterwards.
A run is skipped when there is nothing honest to freeze: no Review step, no finished pass, a gate decision the human has not made yet, or rounds recorded before provenance was on. An incomplete later review round (no recorded findings) is skipped so a completed sibling of the same run can still be captured. Capturing a run with nothing capturable reports the reason instead of freezing an incomplete label; for a parked Review, retry after the decision is recorded.
A case includes:
- the reviewed commit, base, and trusted-config commit pinned at capture
- agent-neutral global configuration and the effective repository configuration frozen at capture
- the original run, step, review-round, decision, and local invocation-metric records
- a manifest with commit pins, changed-file counts, build identity, and a hash of the redacted remote URL
- a local labels.json file that stores finding-level gold and queued unmatched candidate findings
The manifest never stores a remote URL. Capture is read-only against the existing local database and gate. It does not fetch from the network.
Finding-level gold
The unit of truth is whether a review finding was a real issue, scored with scientific terms, not whether the run parked or passed.
Capture writes gold from recorded gate evidence: human Fix and add-finding decisions, plus the merge-derived auto-fix and shipped-unfixed rules below. A merged PR is not a case-level pass or fail:
- A finding the human selected for Fix (selected_finding_ids with a user source) is true-positive gold: that finding is a true issue. Merge is not required.
- A finding the human added (user_findings_json, source user) is false-negative gold: the original review missed a real issue.
- A finding the pipeline auto-fixed that later landed in a merged PR is true-positive gold (recorded-auto-fix-merged). Closed-not-merged, still-open, reverted, and superseded auto-fixes stay unlabeled.
- A finding that was raised (auto-fix or ask-user, including a missing action that defaults to ask-user) and then shipped unfixed in a merged PR is false-positive gold (recorded-shipped-unfixed). If a later review round exists and the last of those rounds no longer raises the same issue, earlier rounds stay unlabeled - an intermediate re-raise that was gone before merge is a fix, not a false positive. Informational no-op findings are not labeled this way.
- A confirmed post-PR miss ingested with eval miss ingest is also false-negative gold (recorded-post-pr-miss): review passed green, and a later vetted finding showed a real defect.
- Skip, and approve-with-findings on an unmerged PR, stay unlabeled / pending until later adjudication.
- A later replay that raises a new issue absent from the gold set is queued as an unmatched candidate finding. It is never auto-scored as a false positive.
If a PR merges after the first capture, already-captured cases are relabeled. The daemon does this best-effort when it observes the merge; eval relabel [run-id] or recapture is the CLI path. Relabel adds merge-derived labels onto previously unlabeled findings and drops obsolete derived merge labels that the current rounds no longer support. Adjudicated, user-fix, and ingested post-PR-miss labels are never overwritten.
A case with no finding-level gold is unlabeled / pending, never a pass. True-negative also stays unlabeled because the current capture evidence cannot establish that a finding is invalid without the shipped-unfixed or adjudication paths above.
Disk use and retention
Cases from the same repository share one local Git object pool under <NM_HOME>/eval/pools/. The first case from a repository stores its history once; every later case adds only the objects its own commits introduced, which is normally a few kilobytes.
eval.max_cases (default 200) is the retention target enforced after automatic collection. When it is exceeded the oldest unprotected cases are dropped first. A case that has a replay in progress or already has recorded candidate replays is never dropped - an eval report's cohort pins the case IDs it compared, so reclaiming one would invalidate a comparison you already paid for. Protected cases can therefore keep the corpus above the target. Set it to 0 to keep every case.
Because the objects live in the pool rather than inside each case, a case directory is not a portable archive: copying it elsewhere does not carry the code it replays.
Finding-level gold uses labels.json schema version 2. There is no migration from labels that store a park/pass verdict, and manifest version 1 cases are also incompatible. If an eval command reports an unsupported case or labels version, remove <NM_HOME>/eval/ to start a fresh corpus; automatic collection will refill it from later runs.
Inspect case sets before spending tokens
no-mistakes eval setsThe command shows counts, finding-level gold coverage, unlabeled / pending cases, queued candidate findings, and composition by repository fingerprint, dominant language, change-size bucket, source severity, and finding type.
Four logical sets are available to replay:
- all - every captured review pass
- labeled - only cases with at least one finding-level gold label
- diversified - the official gold-only holdout: a pinned, size-capped stratified sample of labeled cases (repository, language, size, severity, finding-type). Empty gold produces an empty set and a warning, never a silent unlabeled fill. Rebuild pins with eval sets --refresh-diversified.
- tune - leftover labeled cases after the diversified pins. Iterate matcher thresholds and prompt experiments here, never on diversified.
eval.diversified_size (default 32, documented in Global configuration) caps the official set. 0 keeps one gold case per stratum. Pins stay until a case is pruned, loses its gold, or an explicit refresh. Lowering the cap takes effect on the next eval sets / ListCases read: oldest pins are trimmed to the live cap, at most one per stratum, without waiting for --refresh-diversified. Seats freed by collapsing duplicates fill new strata at most one case each.
Do not fit matcher thresholds or review product prompts against diversified. That set is the held-out official measurement; tune is the only labeled leftover it is safe to iterate on.
Replay a candidate
no-mistakes eval run \
--cases diversified \
--candidate codex+gpt-5.4 \
--repeats 3A candidate is always explicit: agent+model. The replay restores each case into a fresh temporary bare gate and worktree, then invokes only the existing Review step. Push, PR, CI, test, lint, document, and fix loops are outside this subject under test.
Replay scores each candidate finding against that gold:
- true-positive: the candidate raises the same underlying issue as a true-issue gold finding (user Fix, auto-fix-merged, human-added miss, or a confirmed post-PR miss)
- false-negative: the candidate misses a true-issue gold finding
- false-positive: only when a candidate finding matches explicit false-positive gold (adjudicated invalid, or shipped-unfixed). Unmatched candidate findings are never treated as false positives
- pending / unlabeled: unmatched candidate findings, and cases with no finding-level gold yet
Matching is a documented cascade of strengths: the same finding ID, the same file and description after whitespace and case normalization, the same file with lines within 3 and token-Jaccard ≥ 0.5, then gated containment (same file, one normalized description contains the other, shorter side ≥ 8 tokens). Assignment is maximum matching per strength tier, preferring exact over fuzzy, so gold-label order cannot undercount. Headline recall uses the full cascade. Reports also show recall-if-exact-only so a fuzzy-threshold change is visible. File-less or description-less findings do not match on the text, location, or containment strengths.
The report prints recall, precision bounds (adjudicated vs pending-as-FP), and F1 as the headline metric only when false-positive gold exists so precision is real. Otherwise F1 is withheld rather than reported as recall-in-disguise.
--repeats defaults to 3 and must be at least 1. Candidates must use an agent that can enforce an explicit model; ACP targets such as cursor and acp:<target> are rejected. Replays are intentionally isolated from the production NM_HOME; they do not contact the shared no-mistakes daemon. The selected agent still communicates with its configured model provider in the normal way.
Report results
no-mistakes eval reportThe report groups local replays by candidate and cohort. A cohort pins the selected case IDs and repeat count, so frontier comparisons only compare candidates run over the same corpus and repeat plan. It shows:
- finding-level true-positive, false-negative, false-positive, and pending counts
- recall over gold issues, or unlabeled / pending when a case has no finding-level gold
- precision bounds, and F1 only when false-positive gold exists
- queued unmatched candidate findings, which are not scored as false positives
- failed candidate invocations
- reported fresh-input plus output token cost
- average wall time
- a finite-sample case-level recall range, with repeats averaged inside each case
- whether a candidate lies on the observed recall-versus-token-cost frontier
The report is deliberately cautious. It never treats an unadjudicated candidate finding as a false positive, excludes candidates with failed replays from the frontier, and distinguishes missing token instrumentation from a real zero.
Current boundary
Finding-level gold is derived from recorded Fix, add-finding, auto-fix-merged, and shipped-unfixed evidence, plus confirmed post-PR misses ingested through eval miss ingest. An adjudication CLI, PR-comment miss scanning, sharing, sync, and full-pipeline replay are not part of this command surface. A live merge, eval relabel, or recapture backfills merge-derived labels onto already captured cases.
---