canon-ai 3.15.0 → 3.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,42 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [3.17.0] — 2026-11-02
8
+
9
+ ### Added
10
+
11
+ - **Claude-only provider mode.** Set `CANON_PROVIDER=claude` and every phase runs on the Claude CLI; Codex is not required. Each task pins its provider at creation (`canon task set <id> provider claude|mixed` switches it). Code review runs an anchored and a spec-blind Claude reviewer, and a failed implement or spec-review run keeps its session so the next `canon run` resumes it. Mixed-provider bundles are refused, and `codex` is not accepted as a provider yet.
12
+ - **Specs list their judgment calls, and the pipeline shows you which ones the agent made.** The spec template gains a `## Judgment Calls` table after Decision: each choice between defensible options, the strongest alternative, and who decided (`Human` or `Author`). `/canon-spec` argues the runner-up alongside its recommendation. `spec_review` blocks an unlisted call only when it can name a defensible alternative and the behavior that would differ. QA lists the `Author` rows in `done.md` and the PR body.
13
+ - **An opt-in Claude Code guard hook.** `canon init` installs `.claude/hooks/canon-guard.mjs`; canon never writes your Claude settings. Once registered, it refuses direct `status.json` edits, piping `canon run` or `canon watch`, polling the run log, and merging a task PR with `gh pr merge` by any method (squash, rebase, or merge commit), and names the canon command to use instead. `canon doctor` warns when the hook is installed but not fully registered.
14
+ - **Malformed Affected Files tables are rejected.** `canon task phase <id> spec done` lists every problem with its row and fix, and plan and implement auto-block on a malformed table before any agent runs (`--force` overrides with a warning).
15
+ - **`ship.merge_method` picks how `--ship` merges a task PR.** Set the key in the repo's `.canon/config.json` to `squash` (the default), `rebase`, or `merge`. Before changing anything locally, `--ship` checks that GitHub allows that method, and it stops and names the allowed methods if the repo does not.
16
+ - **QA records why each task needed rework.** `done.md` gains a `## Root Cause` section with one line per blocking review finding, reroute, or dropped AC, classed as `context-missing`, `context-conflicting`, `spec-gap`, `plan-error`, `execution`, or `unrequested-change` (or `None.`). Grep archived `done.md` files to see whether rework comes from your docs, your specs, or the agents. The task quality log is unchanged.
17
+
18
+ ### Changed
19
+
20
+ - **Role and vendor wording follows `CANON_PROVIDER`.** The README, CLI help, `canon doctor`, and the artifact templates name each role's holder: Codex in `mixed` (the default), Claude Code in `claude`.
21
+ - **Error and recovery messages no longer tell you to hand-edit `status.json` or run `gh pr merge --squash`.** They name the canon command instead.
22
+ - **`/canon-init` looks for any linter or formatter config.** Its codebase survey named only ESLint's config file; it now also covers oxlint, Biome, and similar tools.
23
+ - **The spec self-check covers three more items.** The spec template's quality checklist and the pipeline's spec prompt now also ask for replacement framing ("replace X with Y; X must not exist after"), Non-Goals backed by a scope AC, and grep-verified symbols, matching `/canon-spec`. `/canon-spec` now also says Validation Required needs a checked `[x]` entry.
24
+ - **The shipped skills and pipeline guide match current behavior.** `/canon-pipeline` covers `canon watch`, `canon stop`, and the `spec_gap` and `canon task accept` recovery paths. `/canon-changelog` finds archived tasks and canon's own commit subjects. `/canon-init` handles `TODO[canon]` markers and the versioning-policy entry. `/canon-inline-review` says what to do in `claude` mode. `docs/pipeline-orchestrator.md` documents `CANON_STOP_WAIT_MS`, `CANON_SKIP_PHASE_GATE`, `CANON_PATTERNS_MD_PATH`, and `canon upgrade`, `update` and `completion`.
25
+
26
+ ### Fixed
27
+
28
+ - **Tasks created with `canon task` resume agent sessions**, so an implement retry no longer starts cold.
29
+ - **QA recovers a `done.md` written only into the agent's final message.**
30
+ - **Fenced code examples and HTML-commented tables no longer count as spec scope.**
31
+ - **The `done.md` template no longer ships a bulleted `Acknowledged:` placeholder**, which the human-review gate never accepted, so copying it made `--ship` refuse.
32
+ - **`.canon/README.md` no longer says Codex network access is on by default.**
33
+ - **A failed merge in `--ship` no longer loses telemetry notes in your main checkout.** The notes `--ship` set aside are put back before the command exits.
34
+
35
+ ## [3.16.0] — 2026-10-28
36
+
37
+ ### Changed
38
+
39
+ - **Codex spec review for small tasks runs at `high` effort instead of `medium`.** Small (`S`) tasks now get the same spec-review effort as medium and large ones. In a replay of past specs, `high` caught more spec gaps that later forced a reroute and did not block more clean specs; a review takes about 20 seconds longer. Effort has no environment override, so restoring `medium` means installing the previous release.
40
+ - **Spec authoring and `/canon-spec-review` look for sibling implementations, not just callers.** The spec prompts and `/canon-spec` tell the author to search for every other place that implements the behavior being changed (a second listener or entry path, a parallel component, or a test or doc asserting the current behavior) before settling Affected Files. The `/canon-spec-review` factual lens now searches for them too and flags an unnamed one the change must reach as blocking.
41
+ - **`/canon-spec` now strongly recommends `/canon-spec-review` after every spec with logic to vet, before you approve it.** It was optional and pitched mainly at larger tasks. In full-send mode, `/canon-spec` now runs `/canon-spec-review` itself before launching: it applies every blocking finding, applies other findings at its own judgment, and stops to ask only when a fix would change the approved scope. The pipeline guide and README say the same.
42
+
7
43
  ## [3.15.0] — 2026-10-27
8
44
 
9
45
  ### Changed
package/README.md CHANGED
@@ -23,6 +23,8 @@ cd your-project
23
23
  canon init # scaffold canon into the repo
24
24
  ```
25
25
 
26
+ Codex CLI is needed for the default `mixed` provider and for `/canon-inline-review`. For Claude-only pipeline runs (`CANON_PROVIDER=claude`), `npm install -g @anthropic-ai/claude-code canon-ai` is enough. `/canon-inline-review` always runs `codex exec review`; without Codex, use Claude Code's built-in `/code-review` for inline work instead.
27
+
26
28
  Open Claude Code in `your-project` and run `/canon-init` to generate the `docs/` knowledge corpus, then:
27
29
 
28
30
  ```bash
@@ -34,7 +36,7 @@ Needs Node 24.x and git. See [Getting started](#getting-started) below for prere
34
36
 
35
37
  ## What this is
36
38
 
37
- Canon is an opinionated workflow framework for AI-driven software development. It encodes a hard-won discipline — accumulated over many shipped features and many post-mortems — into scripts, templates, and rules that two AI agents (an architect and an implementer) operate under, with a human as the final arbiter.
39
+ Canon is an opinionated workflow framework for AI-driven software development. It encodes a hard-won discipline — accumulated over many shipped features and many post-mortems — into scripts, templates, and rules carried out by pipeline roles, with a human as the final arbiter.
38
40
 
39
41
  The goal: make AI coding agents reliably ship correct, on-spec, well-reviewed work without constant babysitting. Not "the agents do everything" — **the agents do the right thing, and the human catches what they miss, and over time the rules absorb every miss so the next miss never happens**.
40
42
 
@@ -62,14 +64,23 @@ Canon is what happens when you treat those failure modes as engineering problems
62
64
  | Agent forgets a past mistake | **`docs/lessons-learned.md`** — distilled cross-task wisdom that promotes into permanent rules over time |
63
65
  | Reviews loop forever on the same disagreement | **Auto-block on runaway review loops** — per-size caps (see `pipeline-policy.ts`), escalation to human after the cap |
64
66
  | Spec drift between conversation and pipeline | **File-based handoff protocol** — every artifact lives in `tasks/<id>/`, no copy-pasting |
65
- | Sensitive surfaces (auth, payments) get refactored on theoretical grounds | **`delicate: true` flag** that moves Codex spec review and implementation to the full model and triggers extra review discipline |
67
+ | Sensitive surfaces (auth, payments) get refactored on theoretical grounds | **`delicate: true` flag** that moves spec review and implementation to the XL cells (the full Codex model in mixed mode) and triggers extra review discipline |
66
68
 
67
69
  ## How it works
68
70
 
69
- Canon orchestrates two AI coding CLIs:
71
+ Canon runs work through these pipeline roles:
72
+
73
+ - **Author / architect** writes specs and plans.
74
+ - **Spec reviewer** reviews specs on full-tier tasks.
75
+ - **Implementer** writes code and handoff reports.
76
+ - **Code reviewer** is a foreman over independent lenses.
77
+ - **QA** writes the completion summary.
78
+
79
+ ### Roles and providers
80
+
81
+ **Providers.** `CANON_PROVIDER` picks who holds the roles. In `mixed` (the default), Claude Code is the author, planner, code reviewer and QA, and Codex CLI is the spec reviewer, implementer and the orchestrator's cold code-review lens. In `claude`, every role runs on Claude Code and code review uses two Claude lenses (anchored and cold). Codex-only mode is not supported. A task's provider is pinned when it is created; switch an existing task with `canon task set <id> provider <mixed|claude>`. See [`docs/pipeline-orchestrator.md`](docs/pipeline-orchestrator.md#provider-selection) for the mechanics.
70
82
 
71
- - **Claude Code** (Anthropic) plays the **architect**: writes specs, reviews code, writes QA summaries.
72
- - **Codex CLI** (OpenAI) plays the **implementer**: reviews specs (full-tier tasks), writes code, writes handoff reports.
83
+ Mixed mode gets review independence from a second model family; Claude mode gets it from separate sessions and spec-blind review lenses.
73
84
 
74
85
  A **human** is the product owner: approves specs, runs final behavioral tests, ships.
75
86
 
@@ -83,10 +94,10 @@ The human gates between `spec_review` and `plan` — they approve the spec befor
83
94
 
84
95
  The pipeline supports two tiers:
85
96
 
86
- - **Fast tier** (XS tasks): spec + plan in one Claude session, skip Codex spec review, human gate replaces it.
87
- - **Full tier** (S / M / L / XL / delicate tasks): every phase runs separately, Codex reviews specs before they reach the human.
97
+ - **Fast tier** (XS tasks): spec + plan in one Claude session; skip the `spec_review` phase, and the human gate replaces it.
98
+ - **Full tier** (S / M / L / XL / delicate tasks): every phase runs separately, and the spec reviewer checks specs before they reach the human.
88
99
 
89
- `delicate: true` (set in `status.json` at task creation) promotes any task to full tier and upgrades the model and effort for spec, plan, and code review, plus moves Codex spec review and implementation to the full model; QA and the cold-Codex review lens stay on their regular cells. Use it for sensitive surfaces — auth, payments, persistent storage, anything where a regression has unbounded blast radius.
100
+ `delicate: true` promotes any task to full tier and upgrades the model and effort for spec, plan, and code review, plus moves spec review and implementation to their XL cells (in mixed mode, the full Codex model); QA and, in mixed mode, the cold-Codex review lens stay on their regular cells. Set it with `canon task set <task-id> delicate true`. Use it for sensitive surfaces — auth, payments, persistent storage, anything where a regression has unbounded blast radius.
90
101
 
91
102
  A single command runs a task end-to-end:
92
103
 
@@ -94,7 +105,7 @@ A single command runs a task end-to-end:
94
105
  canon run <task-id>
95
106
  ```
96
107
 
97
- `--step --expect <phase>` runs one phase with a phase-mismatch guard. `--pr` pushes and opens a draft PR at `human_review`. `--ship` runs *after* PR approval — it squash-merges the PR, deletes the branch, tears down the worktree, archives the task, and pulls the base branch (don't merge the PR manually first). `--reroute` resets a task once implementation has begun: current phase `code_review`, `qa`, or `human_review` (any status or verdict), or `implement` when implement is in progress or blocked, code review is blocked, or code review already ran in the current loop (a review round or a pre-flight rejection). In a bundle, a sibling at implement pending with no current-loop activity is admitted alongside a task that qualifies when both belong to the same non-empty task branch. Full-tier tasks (S/M/L/XL or delicate) re-enter at `spec_review`, fast-tier tasks (XS) re-enter at `implement`. `--full-send` skips the spec gate and auto-opens a draft PR on clean QA. `--dry-run` prints planned phases without spawning agents.
108
+ `--step --expect <phase>` runs one phase with a phase-mismatch guard. `--pr` pushes and opens a draft PR at `human_review`. `--ship` runs *after* PR approval — it merges the PR with the configured method (squash by default; see `ship.merge_method`), deletes the branch, tears down the worktree, archives the task, and pulls the base branch (don't merge the PR manually first). `--reroute` resets a task once implementation has begun: current phase `code_review`, `qa`, or `human_review` (any status or verdict), or `implement` when implement is in progress or blocked, code review is blocked, or code review already ran in the current loop (a review round or a pre-flight rejection). In a bundle, a sibling at implement pending with no current-loop activity is admitted alongside a task that qualifies when both belong to the same non-empty task branch. Full-tier tasks (S/M/L/XL or delicate) re-enter at `spec_review`, fast-tier tasks (XS) re-enter at `implement`. `--full-send` skips the spec gate and auto-opens a draft PR on clean QA. `--dry-run` prints planned phases without spawning agents.
98
109
 
99
110
  Multiple task IDs in one invocation activates **bundle mode** — `canon run id1 id2 id3` runs all tasks together per phase under a single review loop with one commit history and one PR. Any full-tier task in the bundle promotes the entire bundle to full tier.
100
111
 
@@ -105,8 +116,8 @@ Multiple task IDs in one invocation activates **bundle mode** — `canon run id1
105
116
  - **Node 24.x**
106
117
  - **git**
107
118
  - **Claude Code (≥ 2.1.72)** — `npm install -g @anthropic-ai/claude-code`
108
- - **Codex CLI** — `npm install -g @openai/codex`
109
- - **gh** (optional, for `--pr` / `--push`) — `brew install gh && gh auth login`
119
+ - **Codex CLI** (required for the default `mixed` provider and for `/canon-inline-review` under either provider; `CANON_PROVIDER=claude` pipeline runs don't need it, and Claude Code's `/code-review` covers inline review without it) — `npm install -g @openai/codex`
120
+ - **gh** (needed for `--pr`, `--push` and `--ship`; not for plain `canon run`) — `brew install gh && gh auth login`
110
121
 
111
122
  ### Install
112
123
 
@@ -161,7 +172,7 @@ The other installed skills (auto-trigger on natural-language phrases — see eac
161
172
  | Skill | When it fires |
162
173
  |---|---|
163
174
  | `/canon-spec` | Authoring a new task — "let's add X", "start a task for…" |
164
- | `/canon-spec-review` | Pre-flighting a spec before invoking the pipeline |
175
+ | `/canon-spec-review` | Pre-flighting a spec before invoking the pipeline; strongly recommended after authoring any spec with logic to vet |
165
176
  | `/canon-inline-review` | Independent cross-review of inline or below-pipeline changes before commit or PR |
166
177
  | `/canon-sweep` | Triaging `docs/lessons-learned.md` — promote, keep, or prune, human-approved |
167
178
  | `/canon-pipeline` | Driving an existing task forward (`canon run`, `--pr`, `--ship`, recovery) |
@@ -178,7 +189,7 @@ canon task new my-first-feature "Short description"
178
189
  canon run my-first-feature
179
190
  ```
180
191
 
181
- Run `canon doctor` after install to verify your environment — it checks Node/git/Claude Code/Codex versions, codex project trust, allowlist coverage, and that any local Claude settings file is gitignored.
192
+ Run `canon doctor` after install to verify your environment — it checks Node/git/Claude Code versions, allowlist coverage, and that any local Claude settings file is gitignored, plus Codex CLI presence and codex project trust when `CANON_PROVIDER` is `mixed`, empty, or unset. Doctor checks that environment setting, not providers pinned on existing tasks, so mixed-pinned tasks still need Codex.
182
193
 
183
194
  ### Discovery nudge (recommended)
184
195
 
@@ -192,7 +203,7 @@ Start with `/canon-spec` rather than implementing directly.
192
203
 
193
204
  ### Independent review for inline work
194
205
 
195
- For below-pipeline changes or trivial inline work, do not self-review. Use `/canon-inline-review` for an independent cross-review before committing, or `codex review` if you are not running canon.
206
+ For below-pipeline changes or trivial inline work, do not self-review. Use `/canon-inline-review` for an independent cross-review before committing, or `codex review` if you are not running canon. Without Codex (for example, `CANON_PROVIDER=claude` with no Codex CLI installed), run Claude Code's built-in `/code-review` in a fresh session instead; it is a separate Claude session, not a second model family.
196
207
 
197
208
  ### Skip the permission prompts (optional)
198
209
 
@@ -257,38 +268,90 @@ Canon drives a lot of `git`, `gh`, `codex`, and `npm` invocations, plus short sh
257
268
 
258
269
  Claude Code creates `settings.json` on first use — check what's already there before pasting. For a personal "full send" allowlist that doesn't get committed, use your local Claude Code settings file (and make sure it is gitignored — `canon doctor` will warn you if it isn't).
259
270
 
271
+ ### Guard hooks (recommended)
272
+
273
+ `canon init` installs `.claude/hooks/canon-guard.mjs`, and `canon upgrade` keeps it current. Canon never writes `.claude/settings.json` or `.claude/settings.local.json`, so registering the hook is optional. When registered, it redirects Claude away from three pipeline bypasses:
274
+
275
+ - Direct edits to `tasks/<id>/status.json`: use the matching `canon task phase`, `canon task set`, `canon task accept`, or `canon task reset-*` command; if none covers the change, give the human the exact edit.
276
+ - Piping `canon run` or `canon watch`, or polling `.canon-run.log`: run `canon run <id>` bare, then `canon watch <id>` without a pipe.
277
+ - Any `gh pr merge` on a `task/*` PR (squash, rebase, or merge commit): use `canon run <id> --ship`, naming every task of a bundle (the hook lists the tasks whose `status.json` records that branch). `--ship` uses the project's configured method (`ship.merge_method`, squash by default). To merge by rebase or merge commit, edit `.canon/config.json` to set `ship.merge_method` to `rebase` or `merge`; the hook's deny message says so.
278
+
279
+ To register it, merge this block into the existing `hooks` key in `.claude/settings.json`:
280
+
281
+ ```json
282
+ {
283
+ "hooks": {
284
+ "PreToolUse": [
285
+ {
286
+ "matcher": "Bash|Edit|Write|MultiEdit",
287
+ "hooks": [
288
+ {
289
+ "type": "command",
290
+ "command": "test -f \"$CLAUDE_PROJECT_DIR/.claude/hooks/canon-guard.mjs\" && node \"$CLAUDE_PROJECT_DIR/.claude/hooks/canon-guard.mjs\" || true",
291
+ "timeout": 10
292
+ }
293
+ ]
294
+ }
295
+ ]
296
+ }
297
+ }
298
+ ```
299
+
300
+ `canon doctor` warns until the script is present and registered for all four tools. The shell rules apply only to Claude Code's Bash tool. Sessions using the PowerShell tool (the Windows default) get only the Edit/Write/MultiEdit `status.json` rule, and Codex sessions are not covered. This is a guardrail against habit, not a security boundary.
301
+
260
302
  ### Trust model
261
303
 
262
- Pipeline sessions are headless, so nobody is at the keyboard to answer a permission prompt. Know what that means before you run `canon run` on a repo you care about. Everything below describes the default headless runs; `--interactive` opens ordinary Claude Code and Codex sessions under your own permission settings instead.
304
+ Pipeline sessions are headless, so nobody is at the keyboard to answer a permission prompt. Know what that means before you run `canon run` on a repo you care about. Everything below describes the default headless runs; `--interactive` opens ordinary Claude Code sessions, plus Codex sessions for Codex-held roles in mixed mode, under your own permission settings instead.
263
305
 
264
- - **Claude Code sessions run with `--dangerously-skip-permissions`.** Every tool call is auto-approved. This is required today because a headless session cannot answer prompts, and your project's validation commands (test suites, builds, linters) cannot be allowlisted in advance. A session can run anything your user account can run.
265
- - **Fresh headless Codex runs use `--sandbox workspace-write`.** Codex's OS-level sandbox confines those runs' writes to the directory canon launches them in: the task worktree once one exists, otherwise the main checkout (a task's first spec review runs before its worktree is created, and `worktree: false` tasks never get one). Network is off unless your Codex config enables it. The flag is not passed on session resumes, on the `codex exec review` code-review lens, or in interactive Codex sessions, which follow your own Codex sandbox settings.
306
+ - **Claude Code sessions run with `--dangerously-skip-permissions`.** Every tool call is auto-approved. This is required today because a headless session cannot answer prompts, and your project's validation commands (test suites, builds, linters) cannot be allowlisted in advance. Without additional confinement, a session can run anything your user account can run. In `claude` mode spec review and implementation also run as Claude sessions under `--dangerously-skip-permissions`, with no OS-level write confinement unless you opt into the Claude sandbox below.
307
+ - **In mixed mode, fresh headless Codex runs use `--sandbox workspace-write`.** Codex's OS-level sandbox confines those runs' writes to the directory canon launches them in, plus temporary directories such as `/tmp` and `$TMPDIR`: the task worktree once one exists, otherwise the main checkout (a task's first spec review runs before its worktree is created, and `worktree: false` tasks never get one). Network is off unless your Codex config enables it. The flag is not passed on session resumes, on the `codex exec review` code-review lens, or in interactive Codex sessions, which follow your own Codex sandbox settings.
266
308
  - **Worktrees separate branch state by convention, not by enforcement.** Each task, or each bundle when you pass several task ids together, gets its own worktree and branch, and the pipeline's dirty-tree gates inspect the active worktree at phase boundaries. But Claude sessions are also given the main checkout via `--add-dir` and run with permissions skipped, so nothing stops a session from writing there, and an unrelated file dropped into the main checkout is not something those gates look for; tasks with `worktree: false` run in the main checkout outright. Validation commands run with your normal privileges.
267
309
  - **Budget caps bound cost, not access.** Each headless Claude phase runs with `--max-budget-usd`; hitting the cap stops the session. It does not narrow what the session may do beforehand, and interactive sessions (`--interactive`) run uncapped.
268
- - **Your code goes to the model providers.** Each agent phase sends prompts and repository context to the provider running it, Anthropic for Claude phases and OpenAI for Codex phases, with `code_review` using both, all through the Claude Code and Codex CLIs under whatever data terms your accounts have. Treat a `canon run` like any other agent session in that respect.
269
- - **Git side effects need a flag.** The pipeline never pushes, opens PRs, merges, or publishes on its own. `--pr` pushes the task branch and opens a draft PR, stopping at `human_review`. `--ship` squash-merges that PR; it checks the task's phase, not whether anyone approved, so PR approval is your prerequisite (or your branch protection's), not something canon enforces. `--full-send` skips the human spec gate and opens the draft PR on clean QA, still stopping before merge. `--pr`, `--push` and full-send first push canon's own unpushed scaffold and telemetry commits on the base, creating it on origin if missing when every local-only commit is canon-safe or already published. Other unpushed base commits block unless `--allow-divergent-base` is set; that escape does not apply to a missing remote base. On a `delicate` task, `--full-send` refuses without `--force`.
310
+ - **Your code goes to the model providers.** Each agent phase sends prompts and repository context to the provider running it. In mixed mode that is Anthropic for Claude phases and OpenAI for Codex phases, with mixed-mode `code_review` using both. In `claude` mode prompts and repository context go only to Anthropic; the exception is `/canon-inline-review`, which, if you use it, sends the diff to OpenAI. These sessions use the relevant CLIs under whatever data terms your accounts have. Treat a `canon run` like any other agent session in that respect.
311
+ - **Git side effects need a flag.** The pipeline never pushes, opens PRs, merges, or publishes on its own. `--pr` pushes the task branch and opens a draft PR, stopping at `human_review`. `--ship` merges that PR with the configured method (squash by default; see `ship.merge_method`); it checks the task's phase, not whether anyone approved, so PR approval is your prerequisite (or your branch protection's), not something canon enforces. `--full-send` skips the human spec gate and opens the draft PR on clean QA, still stopping before merge. `--pr`, `--push` and full-send first push canon's own unpushed scaffold and telemetry commits on the base, creating it on origin if missing when every local-only commit is canon-safe or already published. Other unpushed base commits block unless `--allow-divergent-base` is set; that escape does not apply to a missing remote base. On a `delicate` task, `--full-send` refuses without `--force`.
270
312
 
271
- Run canon on repositories where you would be comfortable running your test suite unattended. If that is not your situation, keep it to a machine or container scoped for the purpose. Replacing the blanket permission skip with a narrower confinement is on the roadmap; the constraint to solve is that adopter validation commands legitimately need network and system access the sandbox would block. Security reports go through [SECURITY.md](SECURITY.md).
313
+ #### Optional: Claude Code sandbox
314
+
315
+ This is opt-in; canon neither scaffolds nor requires it. Merge this setting into `.claude/settings.json`:
316
+
317
+ ```json
318
+ {
319
+ "sandbox": {
320
+ "enabled": true,
321
+ "autoAllowBashIfSandboxed": true,
322
+ "allowUnsandboxedCommands": false,
323
+ "excludedCommands": []
324
+ }
325
+ }
326
+ ```
327
+
328
+ Add validation commands that need system paths and must run unsandboxed to `excludedCommands`. Under canon's headless flags, as observed on Claude Code 2.1.312, the sandbox confines Bash subprocesses only: Bash writes outside the working directory and temp directory were blocked, but Claude's built-in file edit tools are not covered. Network is not confined in canon's headless runs because `--dangerously-skip-permissions` auto-approves the sandbox's network prompts, even when `network.allowedDomains` is set. Without `allowUnsandboxedCommands: false`, a session can step outside the sandbox through the `dangerouslyDisableSandbox` escape hatch and be auto-approved. The probe ran in a plain repository; canon also gives headless Claude sessions the main checkout via `--add-dir`, and whether sandboxed Bash may write there, or whether git in a linked worktree still works, was not tested. Behavior may change between Claude Code releases.
329
+
330
+ Run canon on repositories where you would be comfortable running your test suite unattended. If that is not your situation, keep it to a machine or container scoped for the purpose. An opt-in Claude sandbox for shell commands exists above. A verified default that replaces the blanket permission skip is still on the roadmap; the constraint to solve is that adopter validation commands legitimately need network and system access a sandbox may block. Security reports go through [SECURITY.md](SECURITY.md).
272
331
 
273
332
  ### Key commands
274
333
 
275
334
  | Command | What it does |
276
335
  |---|---|
277
336
  | `canon init` | Install canon into the current repo. Refuses symlinks at destination files or parent directories; replace them with regular files/directories first. |
278
- | `canon doctor` | Verify environment and canon setup — Node/git versions, Claude Code (≥ 2.1.72) and Codex CLI presence, codex project trust, recommended-permission coverage in `.claude/settings.json`, and that any local settings file is gitignored. |
337
+ | `canon doctor` | Verify environment and canon setup — Node/git versions, Claude Code (≥ 2.1.72), Codex CLI presence and codex project trust (when `CANON_PROVIDER` is `mixed`, empty, or unset), recommended-permission coverage, guard-hook registration, and that any local settings file is gitignored. |
279
338
  | `canon completion <shell>` | Print a completion script for bash, zsh, fish, or tcsh; see Shell completion. |
280
339
  | `canon task new <id> "Title"` | Scaffold a new task from templates |
281
340
  | `canon task list` | Show all tasks and their pipeline phase |
282
341
  | `canon task phase <id> <phase> <status>` | Advance a task phase manually |
283
- | `canon task accept <id...> implement [--force]` | Accept a manually-committed `implement` phase outside the pipeline (e.g. after a manual recovery commit). `implement` is the only supported phase today — for other phases use `canon task phase`. |
342
+ | `canon task accept <id...> <phase> [--reason "<text>"] [--force]` | Accept a manually-committed `implement` phase outside the pipeline (e.g. after a manual recovery commit), or sanction a `spec_review` / `code_review` verdict with an audit reason (`--reason` is required for those two). `--force` bypasses the missing-verdict and dirty-tree guards. |
343
+ | `canon task set <id> <field> <value>` | Set task metadata (`title`, `task_size`, `delicate`, `worktree`, `base_branch`, `human_spec_gate`, `provider`). |
344
+ | `canon task reset-spec-review <id>` / `canon task reset-code-review <id>` | Reset an auto-blocked review loop. |
345
+ | `canon task post-merge-sync [<branch>]` | Reconcile the local branch after a PR merge. |
284
346
  | `canon run <id>` | Run the full pipeline for a task. Auto-detaches into its own session when stdout is not a TTY (so harness/process-group kills don't take it down); opt out with `CANON_NO_DETACH=1`. |
285
347
  | `canon run <id> --step --expect <phase>` | Run one phase then stop, with a phase-mismatch guard |
286
348
  | `canon run <id> --pr` | Push branch and open a draft PR (at `human_review`) |
287
349
  | `canon run <id> --push` | Push branch only, no PR |
288
350
  | `canon run <id> --reroute` | Reset a task once implementation has begun: current phase `code_review`, `qa`, or `human_review` (any status or verdict), or `implement` when implement is in progress or blocked, code review is blocked, or code review already ran in the current loop (a review round or a pre-flight rejection). In a bundle, a sibling at implement pending with no current-loop activity is admitted alongside a task that qualifies when both belong to the same non-empty task branch. Requires the next amendment section (`## Amendment`, then `## Amendment Round N`) appended to `spec.md` first; full-tier re-enters at `spec_review`, fast-tier at `implement`. |
289
351
  | `canon run <id> --full-send` | Skip the spec gate and auto-open a draft PR after clean QA |
290
- | `canon run <id> --ship` | After PR approval: squash-merge, delete branch, tear down worktree, archive the task, pull base branch. Don't merge the PR manually first. |
352
+ | `canon run <id> --ship` | After PR approval: merge with the configured method (squash by default; see `ship.merge_method`), delete branch, tear down worktree, archive the task, pull base branch. Don't merge the PR manually first. |
291
353
  | `canon run <id> --dry-run` | Print each planned phase and exit without spawning any agent |
354
+ | `canon watch <id> [--until <phase>] [--timeout <dur>] [--follow]` | Block on a detached run until it settles, then print one summary line (exit 0 healthy stop, 3 auto-block, 4 death, 5 timeout). |
292
355
  | `canon stop <id>` | Stop a detached canon run (SIGTERM → SIGKILL after 10s). Waits up to 30s — override via `CANON_STOP_WAIT_MS` — for the orchestrator's first heartbeat to verify the PID before signaling. |
293
356
  | `canon upgrade` | Sync vendored canon-owned files to match the installed version. It does not touch adopter-owned `AGENTS.md` or `CLAUDE.md`. Refuses to overwrite canon-owned targets that are locally modified, untracked but present, or whose git state cannot be verified unless `--force` is set. Symlinks at destination files or parent directories are refused even with `--force`; replace them with regular files/directories first. Use `--check` (or `--dry-run`) to preview, `--no-stage` to skip the auto-`git add`. |
294
357
  | `canon update` | Update the canon-ai package itself. Targets the install's own root (never the invocation directory) and installs the latest final release from npm by default. `--channel main` / `--ref <ref\|sha>` install a pinned GitHub development commit instead. Writes `provenance.json` in `.canon` after a successful install — recorded for future tooling, nothing reads it yet. |
@@ -353,6 +416,20 @@ Malformed config stops runs, including reroute and ship, and fails the docs-fres
353
416
  check in `canon doctor`; unknown keys warn. Telemetry files and task-artifact paths
354
417
  cannot be configured. Without a config, the default protected set applies.
355
418
 
419
+ ### Configuring the merge method
420
+
421
+ Set `ship.merge_method` to `"squash"`, `"rebase"`, or `"merge"` in the same
422
+ adopter-owned `.canon/config.json`. It defaults to `"squash"`. When an open task
423
+ PR will be merged, `--ship` checks that GitHub allows the configured method
424
+ before changing local state; the check is skipped when there is no open PR, such
425
+ as after an external merge.
426
+
427
+ ```json
428
+ {
429
+ "ship": { "merge_method": "rebase" }
430
+ }
431
+ ```
432
+
356
433
  ## Architecture: two layers
357
434
 
358
435
  Canon is two products:
@@ -376,14 +453,14 @@ Drop this into any repo and you have:
376
453
 
377
454
  ✅ **Built and working:**
378
455
 
379
- - `canon` CLI — `init`, `doctor`, `run`, `stop`, `task`, `update`, `upgrade`
456
+ - `canon` CLI — `init`, `doctor`, `run`, `watch`, `stop`, `task`, `update`, `upgrade`, `completion`
380
457
  - Full pipeline orchestrator with phase routing, worktree isolation, session resumption, auto-block, bundle mode, `--reroute`, `--ship`. Bundled into `dist/orchestrator/run-task.js` and invoked via `canon run`.
381
458
  - Pure routing policy module (tier/sizing/model/effort matrix), table-tested.
382
- - `canon task` lifecycle CLI (new / list / status / phase / accept / reset-spec-review / post-merge-sync), in-process TS.
459
+ - `canon task` lifecycle CLI (new / list / status / phase / accept / set / reset-spec-review / reset-code-review / post-merge-sync), in-process TS.
383
460
  - `.canon/templates/` — artifact templates (status, spec, spec-review, plan, handoff, review, done, notes)
384
461
  - Agent rules and per-agent guidance delivered just-in-time via per-phase prompt templates (`src/orchestrator/prompts/templates/`) and the `/canon-*` skills; adopters generate their own `AGENTS.md` / `CLAUDE.md` with the built-in `/init`
385
462
  - `docs/` — knowledge corpus templates with detailed scaffolding
386
- - `.claude/settings.json` — Claude Code permissions + SessionStart hook
463
+ - `.claude/hooks/canon-guard.mjs` — Claude Code guard hook (registration is recommend-only; canon never writes `.claude/settings.json`)
387
464
  - Claude Code skills installed by `canon init`: `/canon-init` (knowledge-corpus bootstrap), `/canon-spec` (new task authoring), `/canon-spec-review` (pre-flight a spec), `/canon-inline-review` (independent cross-review of below-pipeline work), `/canon-pipeline` (drive an existing task), `/canon-status` (in-flight task map), `/canon-changelog` (release notes for versioned projects), `/canon-sweep` (triage the lessons-learned buffer)
388
465
  - Unit-test suite covering the policy module, orchestrator extractors, and validation parsers (`npm test`)
389
466
 
@@ -403,7 +480,7 @@ Drop this into any repo and you have:
403
480
 
404
481
  ❌ **Not in scope for MVP:**
405
482
 
406
- - Adapters for other agentic CLIs (Gemini CLI, Aider, etc.) — assumed Claude Code + Codex CLI
483
+ - Adapters for other agentic CLIs (Gemini CLI, Aider, etc.) — assumed Claude Code, plus Codex CLI in mixed mode
407
484
  - Pre-built docs-check / external-API-citation tooling (project-specific)
408
485
  - Per-language project bootstrappers (Python / Rust / Go variants)
409
486