Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8cab788
feat(config): add global Codex review fleet
kunchenguid Aug 18, 2026
70a8a17
feat(review): add local multi-agent certification pipeline
kunchenguid Aug 18, 2026
edd90bf
fix(review): harden fleet recovery and isolation
kunchenguid Aug 19, 2026
773d602
fix(review): bind fleet recovery and sanitize logs
kunchenguid Aug 19, 2026
fd58f67
fix(review): close fleet state isolation gaps
kunchenguid Aug 19, 2026
ef6cb38
no-mistakes(review): Harden fleet review certification
kunchenguid Aug 19, 2026
388cfa4
no-mistakes(review): Seal fleet prompt and Git isolation
kunchenguid Aug 19, 2026
080b2fd
no-mistakes(review): Harden fleet input and Git isolation
kunchenguid Aug 19, 2026
a51739b
no-mistakes(review): Block uncertified fleet CI delivery
kunchenguid Aug 19, 2026
7f1e133
no-mistakes(review): Bind fleet reviews to exact head
kunchenguid Aug 19, 2026
90a538c
no-mistakes(review): Harden fleet prompt and SHA binding
kunchenguid Aug 19, 2026
b04bbae
no-mistakes(review): Tighten fleet isolation and delivery guards
kunchenguid Aug 19, 2026
95a0eaf
no-mistakes(review): Harden fleet certification and review bindings
kunchenguid Aug 19, 2026
893499a
no-mistakes(review): Bind fleet certification to reviewed intent
kunchenguid Aug 19, 2026
fde6899
no-mistakes(review): Harden fleet mutation provenance and isolation
kunchenguid Aug 19, 2026
46a228e
no-mistakes(review): Include inert intent in fleet reviews
kunchenguid Aug 19, 2026
2f6c2c7
no-mistakes(review): Reject no-op selected review fixes
kunchenguid Aug 19, 2026
37c1366
no-mistakes(review): Align certifier inert-intent prompt test
kunchenguid Aug 19, 2026
2227aa0
no-mistakes(review): Bind fleet heads to CAS provenance
kunchenguid Aug 19, 2026
7f259af
no-mistakes(review): Record produced fleet commits before continuity
kunchenguid Aug 19, 2026
7efa13d
docs(review): default adversarial role to Terra xHigh
kunchenguid Aug 19, 2026
2efa7b7
no-mistakes(review): Tightened fleet trust boundaries
kunchenguid Aug 19, 2026
4453c89
fix(agent): stream Codex prompts over stdin
kunchenguid Aug 19, 2026
6c49275
fix(review): enforce owned fleet transitions
kunchenguid Aug 19, 2026
b8a8687
no-mistakes(review): Harden fleet terminal and sandbox checks
kunchenguid Aug 19, 2026
d3e2ee9
no-mistakes(review): Harden fleet terminal and deterministic gates
kunchenguid Aug 19, 2026
9778102
no-mistakes(review): Harden fleet proof and auto-fix mutation checks
kunchenguid Aug 19, 2026
4249cb1
no-mistakes(review): Bind fleet PRs to certified heads
kunchenguid Aug 19, 2026
391fdbf
no-mistakes(review): Harden fleet isolation and mandatory gate enforc…
kunchenguid Aug 19, 2026
b44c81e
no-mistakes(review): Moved fleet finalization before deterministic gates
kunchenguid Aug 19, 2026
e193a30
no-mistakes(review): Revalidate approved certification candidates and…
kunchenguid Aug 19, 2026
b683c90
no-mistakes(review): Exported object-free fleet review sandboxes
kunchenguid Aug 19, 2026
a26dddf
no-mistakes(review): Harden fleet certification and sandbox exports
kunchenguid Aug 19, 2026
75573d0
no-mistakes(review): Hardened fleet artifact provenance and finalization
kunchenguid Aug 19, 2026
0f0a0b8
no-mistakes(review): Harden fleet review provenance and failure handling
kunchenguid Aug 19, 2026
846d503
no-mistakes(review): Stage both formatter rename paths
kunchenguid Aug 19, 2026
a141ffd
no-mistakes(review): Harden fleet CI terminal and approval provenance
kunchenguid Aug 19, 2026
27e51a2
fix(review): close final verification gaps
kunchenguid Aug 19, 2026
a7103cb
fix(review): close final fleet delivery gaps
kunchenguid Aug 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions cmd/fakeagent/codex.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@ import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"strings"
)

func runCodex(args []string, scenario *Scenario) int {
prompt := extractCodexPrompt(args)
func runCodex(args []string, stdin io.Reader, scenario *Scenario) int {
prompt, err := readCodexPrompt(args, stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "fakeagent: codex stdin: %v\n", err)
return 1
}
logInvocation("codex", prompt, args)

action := scenario.Match(prompt)
Expand Down Expand Up @@ -78,6 +83,18 @@ func runCodex(args []string, scenario *Scenario) int {
return 0
}

func readCodexPrompt(args []string, stdin io.Reader) (string, error) {
prompt := extractCodexPrompt(args)
if prompt != "-" {
return prompt, nil
}
body, err := io.ReadAll(stdin)
if err != nil {
return "", err
}
return string(body), nil
}

// patchCodexFixture rewrites the agent_message item's text body to
// match the scenario action. The wire envelope (thread.started,
// turn.started, item.completed shape, turn.completed.usage) stays
Expand Down Expand Up @@ -200,6 +217,10 @@ func extractCodexPrompt(args []string) string {
i++
continue
}
if a == "-" {
positionals = append(positionals, a)
continue
}
if len(a) > 0 && a[0] == '-' {
continue
}
Expand Down
11 changes: 11 additions & 0 deletions cmd/fakeagent/codex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"reflect"
"strings"
"testing"
)

Expand Down Expand Up @@ -196,3 +197,13 @@ func TestExtractCodexPromptSkipsOutputSchemaValue(t *testing.T) {
t.Fatalf("prompt = %q, want %q", got, "review this diff")
}
}

func TestReadCodexPromptReadsStdinMarker(t *testing.T) {
got, err := readCodexPrompt([]string{"exec", "-", "--json"}, strings.NewReader("review the stdin diff"))
if err != nil {
t.Fatal(err)
}
if got != "review the stdin diff" {
t.Fatalf("prompt = %q, want stdin prompt", got)
}
}
2 changes: 1 addition & 1 deletion cmd/fakeagent/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func run(argv []string) int {
case "claude":
return runClaude(args, os.Stdin, scenario)
case "codex":
return runCodex(args, scenario)
return runCodex(args, os.Stdin, scenario)
case "opencode":
return runOpencode(args, scenario)
case "gh":
Expand Down
2 changes: 2 additions & 0 deletions cmd/fakeagent/scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,10 @@ func defaultScenario() *Scenario {
"summary": "no issues found",
"risk_level": "low",
"risk_rationale": "no risks detected in the diff",
"risk_scope": "source-or-external",
"tested": []string{"fakeagent: simulated test run"},
"testing_summary": "simulated tests passed",
"artifacts": []any{},
"title": "feat: fakeagent change",
"body": "## Summary\nfakeagent canned PR body",
},
Expand Down
8 changes: 5 additions & 3 deletions docs/src/content/docs/concepts/gate-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,16 @@ flowchart TD
admission --> daemon["Daemon"]
hook --> daemon
daemon --> worktree["Disposable worktree"]
worktree --> pipeline["intent -> rebase -> review -> test -> document -> lint -> push -> pr -> ci"]
worktree --> pipeline["fleet mode: intent -> rebase -> review -> test -> document -> lint -> certify -> push -> pr -> ci"]
pipeline --> target["Push target"]
daemon --> db["SQLite state"]
daemon --> ipc["IPC socket"]
ipc --> tui["TUI clients"]
ipc --> axi["AXI clients"]
```

In the default fleet-disabled path, Certify is skipped.

## What `no-mistakes init` does

When you run `no-mistakes init` in a repo:
Expand Down Expand Up @@ -57,7 +59,7 @@ That is a core design choice, not an implementation detail.
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`.
6. The pipeline runs in order: `intent -> rebase -> review -> test -> document -> lint -> certify -> 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.
Expand All @@ -72,7 +74,7 @@ That is a core design choice, not an implementation detail.
- **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.
- **Fixed pipeline** - the step order is opinionated and not configurable: `intent → rebase → review → test → document → lint → certify → 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
Expand Down
21 changes: 12 additions & 9 deletions docs/src/content/docs/concepts/pipeline.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
---
title: Pipeline
description: The nine steps that run on every gated push.
description: The fleet-mode steps that run on a gated push.
---

The pipeline runs a fixed, opinionated sequence of steps. Order is not configurable. What each step runs *is*.
Fleet mode runs a fixed, opinionated sequence of steps. Order is not configurable. What each step runs *is*. Without fleet mode, Certify is skipped.

```
intent → rebase → review → test → document → lint → push → pr → ci
intent → rebase → review → test → document → lint → certify → push → pr → ci
```

```mermaid
flowchart LR
intent["Intent"] --> rebase["Rebase"] --> review["Review"] --> test["Test"] --> document["Document"] --> lint["Lint"] --> push["Push"] --> pr["PR"] --> ci["CI"]
intent["Intent"] --> rebase["Rebase"] --> review["Review"] --> test["Test"] --> document["Document"] --> lint["Lint"] --> certify["Certify"] --> push["Push"] --> pr["PR"] --> ci["CI"]
review -. findings .-> action["Approve / fix / skip / abort"]
test -. findings .-> action
document -. findings .-> action
lint -. findings .-> action
certify -. findings .-> action
ci -. failures .-> action
```

Expand All @@ -31,7 +32,7 @@ The pipeline is opinionated so that "passed the gate" has a stable meaning:
- 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
## The ten steps

| # | Step | What it does | Default auto-fix limit |
|---|---|---|---|
Expand All @@ -41,9 +42,10 @@ The pipeline is opinionated so that "passed the gate" has a stable meaning:
| 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` |
| 7 | **Certify** | Fleet-only independent inspection of the finalized, clean candidate; findings gate delivery | `0` (non-fixing) |
| 8 | **Push** | Safely push the validated branch to the configured target | n/a |
| 9 | **PR** | Create or update the pull request | n/a |
| 10 | **CI** | Watch CI + mergeability, auto-fix failures | `3` |

## Why these steps, in this order

Expand All @@ -55,6 +57,7 @@ The pipeline is opinionated so that "passed the gate" has a stable meaning:
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.
- **Certify after lint in fleet mode** so formatting and intentional pending changes are finalized before the final read-only delivery check. Fleet reviewers run cold in an immutable shadow checkout with repository/user skills and plugin state removed; HOME, Codex SQLite state, and XDG state are sandbox-local, and raw model messages never enter persistent logs before bounded parsing and sanitization. The shadow controls normal instruction discovery and writes, but Codex read-only mode is not a host-filesystem confidentiality boundary; use a dedicated OS account or outer container for hostile source. In fleet mode, Push accepts only the exact certified commit and performs no source mutation; the complete effective fleet and post-review delivery contract is fingerprinted at run start so recovery cannot change models, reasoning, arguments, security paths, commands, policy, or the once-resolved absolute executable after a config edit. The legacy path skips Certify and retains Push formatting and review-approved descendant behavior.
- **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.
Expand Down Expand Up @@ -89,7 +92,7 @@ See [Configuration](/no-mistakes/guides/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.
- Skipping specific steps permanently - per-run skips are allowed, but the pipeline itself always has all ten.
- Adding new steps.

This is intentional. The pipeline is opinionated so that "passed the gate" means the same thing across repos.
2 changes: 1 addition & 1 deletion docs/src/content/docs/guides/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ Transient API and network failures are retried up to three times with exponentia
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.
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, fixes, lint detection and fixes, documentation checks and fixes, final certification, 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`.
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/guides/provider-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ If your upstream isn't GitHub, GitLab, Bitbucket Cloud, or Azure DevOps:
- 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.
Everything before push (rebase, review, test, document, lint, and the fleet-only final certification check) 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

Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ no-mistakes --skip test,lint

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`.
Valid step names are `intent`, `rebase`, `review`, `test`, `document`, `lint`, `certify`, `push`, `pr`, and `ci`.

## no-mistakes init

Expand Down
86 changes: 85 additions & 1 deletion docs/src/content/docs/reference/global-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,31 @@ agent_args_override:
- -c
- model_reasoning_effort="low"

# Optional Codex-only review fleet (disabled by default; global-only)
review_fleet:
enabled: false
reviewers:
test-adversary:
model: gpt-5.6-terra
reasoning_effort: xhigh
correctness:
model: gpt-5.6-terra
reasoning_effort: high
architecture:
model: gpt-5.6-terra
reasoning_effort: high
security:
model: gpt-5.6-terra
reasoning_effort: high
high_risk_paths: [internal/auth/**, internal/crypto/**]
escalated_reasoning_effort: xhigh
consolidator:
model: gpt-5.6-terra
reasoning_effort: high
certifier:
model: gpt-5.6-sol
reasoning_effort: xhigh

ci_timeout: "168h"

step_quiet_warning: "10m"
Expand Down Expand Up @@ -218,6 +243,65 @@ agent_args_override:

For Codex, `service_tier` and `model_reasoning_effort` tune different things: `service_tier` selects the speed or priority lane, while `model_reasoning_effort` selects reasoning depth. no-mistakes reloads global config while setting up each run, so edits made before `no-mistakes axi run` apply to that run. For repeatable profiles, use separately initialized `NM_HOME` directories; each has its own `config.yaml` and no-mistakes state.

### review_fleet

Optional, global-only Codex review fleet. It is disabled by default and a
repository's `.no-mistakes.yaml` cannot enable, disable, or modify it. v1
requires exactly these four reviewer roles: `test-adversary`, `correctness`,
`architecture`, and `security`, plus one `consolidator` and one `certifier`
profile. Every profile must name its own `model` and `reasoning_effort`.

| Field | Type | Description |
| --- | --- | --- |
| `review_fleet.enabled` | `bool` | Enable the fleet; default `false` |
| `review_fleet.reviewers` | `map[string]object` | Exactly the four fixed reviewer roles when enabled |
| `review_fleet.reviewers.<role>.model` | `string` | Explicit Codex model |
| `review_fleet.reviewers.<role>.reasoning_effort` | `string` | `low`, `medium`, `high`, `xhigh`, or `max` |
| `review_fleet.reviewers.security.high_risk_paths` | `string[]` | Bounded git-path globs that opt security review into escalation |
| `review_fleet.reviewers.security.escalated_reasoning_effort` | `string` | Optional stronger effort for an escalated security review |
| `review_fleet.consolidator` / `certifier` | `object` | Explicit Codex model and reasoning profile |

Models are limited to 128 bytes. Security accepts at most 32 high-risk paths,
each at most 256 bytes and 4,096 bytes in total. Invalid globs and any missing
required profile field reject the global config before a run starts.
`high_risk_paths` and `escalated_reasoning_effort` must be configured
together so a matched path always has a complete escalation profile.

Fleet invocations are always cold and add `--sandbox read-only`, `--ephemeral`,
`--skip-git-repo-check`,
`--ignore-user-config`, `-c project_doc_max_bytes=0`, `--ignore-rules`, and a
core-only shell environment policy. Each Review or Certify execution uses a
clean detached shadow checkout that excludes repository `.agents/skills` and
`.codex` state. It also receives an isolated `HOME`, XDG directories, and
`CODEX_HOME`; only a bounded regular-file copy of `auth.json` is admitted.
This shadow prevents normal discovery of excluded repository/user instruction
state; it is not a host-filesystem confidentiality boundary. Codex's
`read-only` sandbox prevents writes but may read other host paths that the
operating-system account can read. Run no-mistakes under a dedicated OS
account or an outer container when reviews must process untrusted source under
a strict read boundary.
Inherited Codex model, reasoning, sandbox, approval-bypass, session,
project-document, and ignore-rules flags are rejected because they could
defeat fleet isolation. The `service_tier` config override is the only
inherited Codex flag allowed. `high_risk_paths` uses the same git-path glob semantics as
`ignore_patterns`: slash-separated paths, basename matching for patterns
without a slash, and `/**` for a directory subtree. Matching uses the complete
changed-path set before repository `ignore_patterns` filtering; an ignored-only
diff still runs the fleet when it contains an operator-classified high-risk path.
The enabled/disabled fleet mode is persisted when a run starts. Recovery uses
that durable value plus a fingerprint of every profile, high-risk path,
generated safe argument, and the once-resolved absolute Codex executable used
for every invocation. The fingerprint also binds the complete resolved
delivery configuration, including commands, auto-fix and CI policy,
documentation/test settings, and the trusted `allow_repo_commands` decision.
A changed contract
fails recovery instead of weakening an already-started run. Push requires exact
equality with the certified commit even if the fleet is later disabled.
Raw reviewer, consolidator, and certifier messages are never streamed into
persistent logs; only bounded, sanitized findings and bounded lifecycle status
are retained. Each run also replaces ambient `HOME`, `CODEX_HOME`,
`CODEX_SQLITE_HOME`, and XDG state directories with sandbox-local paths.

### ci_timeout

How long the CI step monitors an open PR, including provider CI status and on GitHub, GitLab, or Azure DevOps PR mergeability, before giving up.
Expand Down Expand Up @@ -351,7 +435,7 @@ The template supports literal text and two Go-style placeholders:

| Variable | Value |
| --- | --- |
| `{{.Step}}` | Pipeline step name, such as `review`, `test`, `document`, or `lint` |
| `{{.Step}}` | Pipeline step name, such as `review`, `test`, `document`, `lint`, or `certify` |
| `{{.Summary}}` | Sanitized one-line summary returned by the fix agent, or the step's deterministic fallback summary |

The value must be a valid UTF-8 template that renders to a non-empty, single-line commit subject.
Expand Down
Loading
Loading