canon-ai 3.14.0 → 3.15.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,17 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [3.15.0] — 2026-10-27
8
+
9
+ ### Changed
10
+
11
+ - **Codex implementation runs at higher reasoning effort, and the full Codex model defaults to GPT-6.1 Sol.** Extra-small and small tasks now implement with the mini model at `xhigh` effort (was `medium`), and medium and large tasks at `max` (was `high`). Extra-large and delicate tasks stay on the full model at `high`, so `delicate` now means a stronger model rather than more effort. The full-model default moves from `gpt-6-sol` to `gpt-6.1-sol`; set `CODEX_MODEL_FULL=gpt-6-sol` to keep the old one. Effort has no environment override, so restoring the old effort settings means installing the previous release. `max` needs a Codex CLI and mini model that accept it; the pipeline guide names the verified pair and what to do if Codex rejects it.
12
+ - **QA defaults to Claude Haiku 5.5 instead of Sonnet.** The QA step runs `claude-haiku-5-5` at medium effort at every task size, including delicate tasks; spec, plan, and code review keep their models. QA no longer follows the light-tier model, so `CLAUDE_MODEL_LIGHT` stops reaching it: if you set only `CLAUDE_MODEL_LIGHT`, QA moves to Haiku, and if you also set `CLAUDE_MODEL`, QA uses that value. `CLAUDE_MODEL_QA` still wins over both. To keep your previous QA model, set `CLAUDE_MODEL_QA` to it (`sonnet` if you set nothing).
13
+
14
+ ### Fixed
15
+
16
+ - **`canon run --interactive` applies the selected reasoning effort.** Interactive Codex sessions used to ignore it and run at your Codex config's or the model's default effort, even though canon logged the selected value.
17
+
7
18
  ## [3.14.0] — 2026-10-25
8
19
 
9
20
  ### Added
package/README.md CHANGED
@@ -62,7 +62,7 @@ Canon is what happens when you treat those failure modes as engineering problems
62
62
  | Agent forgets a past mistake | **`docs/lessons-learned.md`** — distilled cross-task wisdom that promotes into permanent rules over time |
63
63
  | 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
64
  | 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 promotes the task to highest-effort tier and triggers extra review discipline |
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 |
66
66
 
67
67
  ## How it works
68
68
 
@@ -79,14 +79,14 @@ The orchestrator drives this. For each task:
79
79
  spec → spec_review → plan → implement → code_review → qa → human_review
80
80
  ```
81
81
 
82
- The human gates between `spec_review` and `plan` — they approve the spec before the pipeline advances to implementation. Within the chain: automatic loops on `changes_requested` verdicts, model/effort scaling by task size, optional git-worktree isolation, session resumption across phases, and auto-block on runaway loops. See `docs/pipeline-orchestrator.md` for the full mechanics.
82
+ The human gates between `spec_review` and `plan` — they approve the spec before the pipeline advances to implementation. Within the chain: automatic loops on `changes_requested` verdicts, model selection by task size, optional git-worktree isolation, session resumption across phases, and auto-block on runaway loops. See `docs/pipeline-orchestrator.md` for the full mechanics.
83
83
 
84
84
  The pipeline supports two tiers:
85
85
 
86
86
  - **Fast tier** (XS tasks): spec + plan in one Claude session, skip Codex spec review, human gate replaces it.
87
87
  - **Full tier** (S / M / L / XL / delicate tasks): every phase runs separately, Codex reviews specs before they reach the human.
88
88
 
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 Codex spec review and implementation; 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.
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.
90
90
 
91
91
  A single command runs a task end-to-end:
92
92
 
package/dist/cli/index.js CHANGED
@@ -1694,7 +1694,7 @@ function checkTemplates(cwd) {
1694
1694
  }
1695
1695
  function checkCanonVersion(cwd) {
1696
1696
  const versionPath = join(cwd, ".canon", "version");
1697
- const installedVersion = "3.14.0";
1697
+ const installedVersion = "3.15.0";
1698
1698
  if (!existsSync(versionPath)) {
1699
1699
  return { label: ".canon/version", status: "warn", detail: "missing \u2014 run `canon upgrade`" };
1700
1700
  }
@@ -2223,7 +2223,7 @@ function initCmd(args2) {
2223
2223
  }
2224
2224
  function writeCanonVersion(cwd) {
2225
2225
  const versionPath = join2(cwd, ".canon", "version");
2226
- const version = "3.14.0";
2226
+ const version = "3.15.0";
2227
2227
  mkdirSync(dirname2(versionPath), { recursive: true });
2228
2228
  writeFileSync(versionPath, version + "\n");
2229
2229
  }
@@ -3303,7 +3303,7 @@ function isInstalledSourcePath(sourcePath) {
3303
3303
  return sourcePath.includes("/node_modules/") || sourcePath.includes("\\node_modules\\") || sourcePath.includes("/_npx/") || sourcePath.includes("\\_npx\\");
3304
3304
  }
3305
3305
  function resolveCanonVersion(explicit) {
3306
- return explicit ?? "3.14.0" ?? "dev";
3306
+ return explicit ?? "3.15.0" ?? "dev";
3307
3307
  }
3308
3308
  function resolveOrchestratorCommit(repoRoot, upstreamCommit, runGitAt) {
3309
3309
  const ownToplevel = captureGitOutput(repoRoot, ["rev-parse", "--show-toplevel"], runGitAt);
@@ -5548,7 +5548,7 @@ function currentPinFromManifest(manifest) {
5548
5548
  return "unknown";
5549
5549
  }
5550
5550
  function bakedVersion() {
5551
- return "3.14.0";
5551
+ return "3.15.0";
5552
5552
  }
5553
5553
  function ownPackageName(pkgDir) {
5554
5554
  try {
@@ -6035,7 +6035,7 @@ function runUpgrade(cwd, pkgDir, options = {}) {
6035
6035
  cutoverWarnings.push(docsRefsCheckRel);
6036
6036
  }
6037
6037
  const versionPath = join5(cwd, ".canon", "version");
6038
- const newVersion = "3.14.0";
6038
+ const newVersion = "3.15.0";
6039
6039
  const currentVersion = existsSync5(versionPath) ? readFileSync4(versionPath, "utf8").trim() : null;
6040
6040
  if (currentVersion !== newVersion) {
6041
6041
  pending.push({ rel: ".canon/version", projectPath: versionPath, content: newVersion + "\n" });
@@ -6651,7 +6651,7 @@ Global:
6651
6651
  Run 'canon <command> --help' for details.`);
6652
6652
  }
6653
6653
  function printVersion() {
6654
- console.log("3.14.0");
6654
+ console.log("3.15.0");
6655
6655
  }
6656
6656
  switch (command) {
6657
6657
  case "doctor":
@@ -482,7 +482,7 @@ var WORKTREES_ROOT = process.env.CANON_WORKTREES_ROOT ? path2.resolve(REPO_ROOT,
482
482
  var STALL_TIMEOUT_MS = Number(process.env.PIPELINE_STALL_TIMEOUT_MS) || 10 * 60 * 1e3;
483
483
  var STALL_KILL_GRACE_MS = 3e3;
484
484
  var LEGACY_FALLBACK_ENV_VARS = [
485
- { old: "CLAUDE_MODEL", replacement: "CLAUDE_MODEL_LIGHT / CLAUDE_MODEL_STRONG (still honored as a fallback for every Claude phase, including qa)" },
485
+ { old: "CLAUDE_MODEL", replacement: "CLAUDE_MODEL_LIGHT / CLAUDE_MODEL_STRONG, and CLAUDE_MODEL_QA to keep a legacy model on qa (still honored as a fallback for every Claude phase, including qa)" },
486
486
  { old: "CODEX_MODEL_DEFAULT", replacement: "CODEX_MODEL_MINI (still honored as fallback)" },
487
487
  { old: "CODEX_MODEL_DELICATE", replacement: "CODEX_MODEL_FULL (still honored as fallback)" }
488
488
  ];
@@ -2178,10 +2178,10 @@ function codexMatrix(config3) {
2178
2178
  XL: { model: config3.codexModelFull, effort: "high" }
2179
2179
  },
2180
2180
  implement: {
2181
- XS: { model: config3.codexModelMini, effort: "medium" },
2182
- S: { model: config3.codexModelMini, effort: "medium" },
2183
- M: { model: config3.codexModelMini, effort: "high" },
2184
- L: { model: config3.codexModelMini, effort: "high" },
2181
+ XS: { model: config3.codexModelMini, effort: "xhigh" },
2182
+ S: { model: config3.codexModelMini, effort: "xhigh" },
2183
+ M: { model: config3.codexModelMini, effort: "max" },
2184
+ L: { model: config3.codexModelMini, effort: "max" },
2185
2185
  XL: { model: config3.codexModelFull, effort: "high" }
2186
2186
  },
2187
2187
  code_review: {
@@ -2193,6 +2193,7 @@ function codexMatrix(config3) {
2193
2193
  }
2194
2194
  };
2195
2195
  }
2196
+ var QA_DEFAULT_MODEL = "claude-haiku-5-5";
2196
2197
  var CLAUDE_CELLS = {
2197
2198
  spec: {
2198
2199
  XS: { tier: "light", effort: "medium" },
@@ -2216,11 +2217,11 @@ var CLAUDE_CELLS = {
2216
2217
  XL: { tier: "strong", effort: "high" }
2217
2218
  },
2218
2219
  qa: {
2219
- XS: { tier: "light", effort: "medium" },
2220
- S: { tier: "light", effort: "medium" },
2221
- M: { tier: "light", effort: "medium" },
2222
- L: { tier: "light", effort: "medium" },
2223
- XL: { tier: "light", effort: "medium" }
2220
+ XS: { tier: "qa", effort: "medium" },
2221
+ S: { tier: "qa", effort: "medium" },
2222
+ M: { tier: "qa", effort: "medium" },
2223
+ L: { tier: "qa", effort: "medium" },
2224
+ XL: { tier: "qa", effort: "medium" }
2224
2225
  }
2225
2226
  };
2226
2227
  function claudePinFor(phase, size, config3) {
@@ -2239,6 +2240,7 @@ function resolveClaudeModel(phase, size, config3) {
2239
2240
  const pin = claudePinFor(phase, size, config3);
2240
2241
  if (pin !== null) return pin;
2241
2242
  const tier = CLAUDE_CELLS[phase][size].tier;
2243
+ if (tier === "qa") return config3.claudeModelLegacy ?? QA_DEFAULT_MODEL;
2242
2244
  const tierModel = tier === "light" ? config3.claudeModelLight : config3.claudeModelStrong;
2243
2245
  if (tierModel !== null) return tierModel;
2244
2246
  if (config3.claudeModelLegacy !== null) return config3.claudeModelLegacy;
@@ -2295,7 +2297,7 @@ var config2 = {
2295
2297
  claudeModelStrong: process.env.CLAUDE_MODEL_STRONG || null,
2296
2298
  claudeModelLegacy: process.env.CLAUDE_MODEL ?? null,
2297
2299
  codexModelMini: process.env.CODEX_MODEL_MINI ?? process.env.CODEX_MODEL_DEFAULT ?? "gpt-6-luna",
2298
- codexModelFull: process.env.CODEX_MODEL_FULL ?? process.env.CODEX_MODEL_DELICATE ?? "gpt-6-sol",
2300
+ codexModelFull: process.env.CODEX_MODEL_FULL ?? process.env.CODEX_MODEL_DELICATE ?? "gpt-6.1-sol",
2299
2301
  maxReviewLoops: parseMaxReviewLoops(process.env.MAX_REVIEW_LOOPS),
2300
2302
  claudeBudget: process.env.CLAUDE_BUDGET ?? null
2301
2303
  };
@@ -2814,7 +2816,7 @@ ${renderedPrompt}`;
2814
2816
  }
2815
2817
 
2816
2818
  // src/orchestrator/agents/codex.ts
2817
- var VALID_CODEX_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"];
2819
+ var VALID_CODEX_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
2818
2820
  function invalidCodexEffortMessage(effort) {
2819
2821
  if (VALID_CODEX_EFFORTS.includes(effort)) return null;
2820
2822
  return `Invalid Codex reasoning effort "${effort}" \u2014 canon resolved this value for the current phase/size and passes it via \`-c model_reasoning_effort=${effort}\`, but the Codex CLI only accepts: ${VALID_CODEX_EFFORTS.join("|")}. Effort is not configurable \u2014 canon resolves it from a fixed phase/size matrix, so this is a bug in canon rather than in your setup. Editing model_reasoning_effort in ~/.codex/config.toml will not help: the per-invocation override supersedes it. Please report this along with the task size and phase.`;
@@ -2832,6 +2834,7 @@ ${renderedPrompt}`;
2832
2834
  let status = "ok";
2833
2835
  let tokens;
2834
2836
  let sessionId = null;
2837
+ const effortFlag = ["-c", `model_reasoning_effort=${effort}`];
2835
2838
  try {
2836
2839
  if (interactive) {
2837
2840
  console.log("");
@@ -2839,7 +2842,7 @@ ${renderedPrompt}`;
2839
2842
  console.log("Prompt loaded. You're in the driver's seat.");
2840
2843
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2841
2844
  console.log("");
2842
- runCommandOrDie("codex", ["-m", model, "-C", cwd, effectivePrompt], { cwd });
2845
+ runCommandOrDie("codex", ["-m", model, ...effortFlag, "-C", cwd, effectivePrompt], { cwd });
2843
2846
  return {
2844
2847
  exitCode: 0,
2845
2848
  signal: null,
@@ -2850,7 +2853,6 @@ ${renderedPrompt}`;
2850
2853
  sessionId: null
2851
2854
  };
2852
2855
  }
2853
- const effortFlag = ["-c", `model_reasoning_effort=${effort}`];
2854
2856
  const sandboxFlags = resumeId ? [] : ["--sandbox", "workspace-write"];
2855
2857
  const args = resumeId ? ["exec", "resume", resumeId, "--json", ...effortFlag, effectivePrompt, "-m", model] : ["exec", "--json", ...effortFlag, ...sandboxFlags, effectivePrompt, "-m", model, "-C", cwd];
2856
2858
  const displayChunks = [];
@@ -5845,7 +5847,7 @@ function isInstalledSourcePath(sourcePath) {
5845
5847
  return sourcePath.includes("/node_modules/") || sourcePath.includes("\\node_modules\\") || sourcePath.includes("/_npx/") || sourcePath.includes("\\_npx\\");
5846
5848
  }
5847
5849
  function resolveCanonVersion(explicit) {
5848
- return explicit ?? "3.14.0" ?? "dev";
5850
+ return explicit ?? "3.15.0" ?? "dev";
5849
5851
  }
5850
5852
  function resolveOrchestratorCommit(repoRoot, upstreamCommit, runGitAt) {
5851
5853
  const ownToplevel = captureGitOutput(repoRoot, ["rev-parse", "--show-toplevel"], runGitAt);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canon-ai",
3
- "version": "3.14.0",
3
+ "version": "3.15.0",
4
4
  "type": "module",
5
5
  "description": "A spec-first, multi-agent AI coding pipeline you drop into any repo. The law your agents work under.",
6
6
  "engines": {
@@ -209,38 +209,38 @@ Set in `status.json` at task creation:
209
209
 
210
210
  Canon's recommended starting policy for when to scope a task as `delicate: true`: *require evidence of real production impact, not theoretical correctness.*
211
211
 
212
- A `delicate` task carries meaningful regression risk on a security-sensitive surface and runs at the most expensive model+effort tier. "It's technically wrong" is not sufficient justification on its own — a hardening pass on auth/payments/storage that no user has ever hit can take significant pipeline time, introduce regression risk, and produce zero customer-visible value. Before scoping any task as `delicate: true`, require at least one confirmed production incident or a concrete upcoming flow that depends on the fix. Note the incident in the spec's *Problem* section.
212
+ A `delicate` task carries meaningful regression risk on a security-sensitive surface and promotes Codex spec review and implementation to the full model, alongside stronger Claude review. "It's technically wrong" is not sufficient justification on its own — a hardening pass on auth/payments/storage that no user has ever hit can take significant pipeline time, introduce regression risk, and produce zero customer-visible value. Before scoping any task as `delicate: true`, require at least one confirmed production incident or a concrete upcoming flow that depends on the fix. Note the incident in the spec's *Problem* section.
213
213
 
214
214
  This is a default — your project can adopt a stricter or looser bar in `docs/decisions.md` if it has different risk tolerance (e.g., a medical-data project with regulatory exposure may want proactive hardening).
215
215
 
216
216
  ## Codex Model/Effort Matrix
217
217
 
218
- Codex model and effort scale with task size:
218
+ Codex model and effort come from a fixed phase × size matrix:
219
219
 
220
220
  | Phase | XS | S | M | L | XL / delicate |
221
221
  |---|---|---|---|---|---|
222
222
  | `spec_review` | — (skipped) | mini / medium | mini / high | mini / high | full / high |
223
- | `implement` | mini / medium | mini / medium | mini / high | mini / high | full / high |
223
+ | `implement` | mini / xhigh | mini / xhigh | mini / max | mini / max | full / high |
224
224
  | `code_review` (cold lens) | mini / high | mini / high | mini / high | mini / high | mini / high |
225
225
 
226
- Codex is tuned for token efficiency — the mini model handles most phases; the full model only comes out for XL or delicate work. XL/delicate implement runs at `high`, not `xhigh`: reasoning models have shown overthinking at `xhigh` with open-ended tool access — cost and latency without a quality gain. Raise via env only if your own evaluation shows under-reasoning.
226
+ Codex is tuned for token efficiency — the mini model handles most phases; the full model only comes out for XL or delicate work. Effort comes only from this matrix; there is no Codex effort environment override. M/L implement runs use Luna at `max`, while XL/delicate runs use Sol at `high`: delicate work already gets the stronger model, and Sol at `xhigh` costs about 1.5–2× Sol at `high`. Re-evaluating the full model's effort curve remains a separate follow-up.
227
227
 
228
- The cold-Codex `code_review` lens is the exception to size scaling: as a mandatory hard-fail gate, it runs at flat `high` effort and stays on the mini model at every size, including XL/delicate.
228
+ The cold-Codex `code_review` lens is deliberately flat: as a mandatory hard-fail gate, it runs at `high` effort and stays on the mini model at every size, including XL/delicate.
229
229
 
230
230
  `spec_review` runs at `high` from M upward. Task-history analysis found M's excess code_review iterations weren't an implement-quality gap (non-rerouted M and L tasks ran at nearly identical iteration counts) but a reroute-severity gap, with M's lighter spec_review effort the leading hypothesis. M and L also differ on loop cap and budget, so this isn't a proven sole cause; if you retune the matrix, re-measure your own M vs. L reroute rate.
231
231
 
232
232
  ## Claude Model/Effort Matrix
233
233
 
234
- Claude model and effort scale with effective task size. The light tier defaults to `sonnet`, and the strong tier defaults to `opus`:
234
+ Claude model and effort scale with effective task size. The light tier defaults to `sonnet`, the strong tier defaults to `opus`, and `qa` uses its own default model, `claude-haiku-5-5`:
235
235
 
236
236
  | Phase | XS | S | M | L | XL / delicate |
237
237
  |---|---|---|---|---|---|
238
238
  | `spec` | sonnet / medium | sonnet / medium | opus / medium | opus / medium | opus / high |
239
239
  | `plan` | sonnet / medium | sonnet / medium | opus / medium | opus / medium | opus / high |
240
240
  | `code_review` | sonnet / medium | sonnet / medium | opus / medium | opus / medium | opus / high |
241
- | `qa` | sonnet / medium | sonnet / medium | sonnet / medium | sonnet / medium | sonnet / medium |
241
+ | `qa` | claude-haiku-5-5 / medium | claude-haiku-5-5 / medium | claude-haiku-5-5 / medium | claude-haiku-5-5 / medium | claude-haiku-5-5 / medium |
242
242
 
243
- `spec`, `plan`, and `code_review` move to the strong tier at M, where sustained judgment matters; only XL/delicate raises effort to `high`. `qa` writes completion artifacts and cannot block or reroute a task, so it stays light/medium at every size. No Claude cell runs above `high`.
243
+ `spec`, `plan`, and `code_review` move to the strong tier at M, where sustained judgment matters; only XL/delicate raises effort to `high`. QA writes completion artifacts and cannot block or reroute a task, so it uses its own default model rather than the light tier. The operator reports an uncontrolled field sample of about 37 tasks across canon-ai and an adopter with no QA failures, budget-cap hits, or retries; the 20 canon-ai `claude-haiku-5-5` QA invocation rows are all `ok` and took 44–214 seconds. Set `CLAUDE_MODEL_QA=sonnet` to restore the previous QA model. No Claude cell runs above `high`.
244
244
 
245
245
  ## Claude Budget Matrix
246
246
 
@@ -255,18 +255,18 @@ Claude phase budgets scale with task size. `spec`/`plan`/`qa` are single-pass Cl
255
255
 
256
256
  ## Environment Variables
257
257
 
258
- Claude uses the light tier for XS/S spec, plan, and code review and for QA at every size. M and above use the strong tier for spec, plan, and code review. A phase pin changes only the model; effort comes from the matrix.
258
+ Claude uses the light tier for XS/S spec, plan, and code review only. QA uses its own default model. M and above use the strong tier for spec, plan, and code review. A phase pin changes only the model; effort comes from the matrix.
259
259
 
260
260
  | Variable | Default | Purpose |
261
261
  |---|---|---|
262
- | `CLAUDE_MODEL_LIGHT` | `sonnet` | Model for light-tier cells: XS/S `spec`/`plan`/`code_review`, and `qa` at every size, unless a phase pin applies. |
262
+ | `CLAUDE_MODEL_LIGHT` | `sonnet` | Model for light-tier cells: XS/S `spec`/`plan`/`code_review`, unless a phase pin applies. |
263
263
  | `CLAUDE_MODEL_STRONG` | `opus` | Model for strong-tier cells: M and above `spec`/`plan`/`code_review`, unless a phase pin applies. |
264
264
  | `CLAUDE_MODEL_SPEC` | _(unset)_ | Pins the `spec` model at every size, replacing the model only; effort still comes from the matrix. |
265
265
  | `CLAUDE_MODEL_PLAN` | _(unset)_ | Pins the `plan` model at every size where a separate plan phase runs (XS fast tier combines spec and plan under the `spec` cell), replacing the model only; effort still comes from the matrix. |
266
266
  | `CLAUDE_MODEL_REVIEW` | _(unset)_ | Pins the `code_review` model for XS/S/M/L only, replacing the model only; effort still comes from the matrix. Does not reach XL/delicate. |
267
267
  | `CLAUDE_MODEL_REVIEW_LARGE` | _(unset)_ | Pins the `code_review` model for XL/delicate only, replacing the model only; effort still comes from the matrix. `_LARGE` means task size, not model tier. Does not reach XS–L. |
268
- | `CLAUDE_MODEL_QA` | _(unset)_ | Pins the `qa` model at every size, replacing the model only; effort still comes from the matrix. |
269
- | `CLAUDE_MODEL` | _(unset; deprecated)_ | Legacy catch-all model for every Claude phase, including `qa`, only where no phase pin or light/strong tier variable is set. Phase pin → tier variable → this fallback → tier default. |
268
+ | `CLAUDE_MODEL_QA` | _(unset; QA default is `claude-haiku-5-5`)_ | Pins the `qa` model at every size, replacing the model only; effort still comes from the matrix. This is QA's only override besides legacy `CLAUDE_MODEL`. Set it to `sonnet` (or the previous light-tier model) to restore the pre-change QA model. |
269
+ | `CLAUDE_MODEL` | _(unset; deprecated)_ | Legacy catch-all model for every Claude phase, including `qa`, only where no phase pin or tier variable applies. Phase pin → tier variable (tiered cells only) → this fallback → default (`sonnet` light, `opus` strong, `claude-haiku-5-5` for `qa`). For QA, this fallback applies when `CLAUDE_MODEL_QA` is unset. |
270
270
  | `CLAUDE_BUDGET` | _(phase- and size-aware)_ | Max spend per Claude phase (USD). Unset → resolved from the Claude Budget Matrix above (phase × size). Set → flat cap applied uniformly across every phase and size (e.g. `CLAUDE_BUDGET=15.00` overrides every phase to $15). |
271
271
  | `CANON_PROJECT_NAME` | _(reads `package.json` "name" or "your project")_ | Name injected into agent prompts. |
272
272
  | `CANON_WORKTREES_ROOT` | .canon/worktrees | Where task worktrees are created. When overridden, the orchestrator warns if the path isn't in `.claude/settings*.json` `additionalDirectories`. |
@@ -279,9 +279,15 @@ Codex model overrides:
279
279
  | Variable | Default | Purpose |
280
280
  |---|---|---|
281
281
  | `CODEX_MODEL_MINI` | `gpt-6-luna` | Codex model for XS/S/M/L non-delicate phases. |
282
- | `CODEX_MODEL_FULL` | `gpt-6-sol` | Codex model for XL or delicate phases. |
282
+ | `CODEX_MODEL_FULL` | `gpt-6.1-sol` | Codex model for XL or delicate phases. |
283
283
  | `MAX_REVIEW_LOOPS` | _size-aware_ | Max `spec_review` and `code_review` iterations before auto-block. Unset → 3 for XS/S/M, 5 for L/XL. |
284
284
 
285
+ M/L implementation uses `max`, which requires a Codex CLI and mini model
286
+ that accept that effort. This was verified only with Codex CLI 0.164.0 and
287
+ `gpt-6-luna`. If an M/L implement call fails on `max`, upgrade the Codex CLI,
288
+ point `CODEX_MODEL_MINI` at a model that accepts `max` (or unset it), or
289
+ install the previous canon release. There is no effort environment override.
290
+
285
291
  These are canon's shipped defaults at the time of release and may lag
286
292
  behind what your local `codex` CLI accepts. **Verify they resolve on your
287
293
  install before relying on the pipeline** — a stale identifier produces a