@journeykit/canon 0.36.0 → 0.38.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.
Files changed (118) hide show
  1. package/dist/skills/SKILL.src.md +35 -13
  2. package/dist/skills/reference/canon-gate.md +41 -1
  3. package/dist/skills/reference/canon-learn.md +7 -2
  4. package/dist/skills/reference/canon-review.md +15 -4
  5. package/dist/skills/reference/canon-storage.md +31 -5
  6. package/dist/skills/reference/canon-subject.md +5 -4
  7. package/dist/skills/reference/role-implementer.md +7 -4
  8. package/dist/skills/reference/role-orchestrator.md +20 -10
  9. package/dist/skills/reference/role-planner.md +1 -1
  10. package/dist/skills/reference/role-reviewer.md +5 -2
  11. package/man/canon-adapter-authorize.1 +2 -2
  12. package/man/canon-adapter-validate.1 +2 -2
  13. package/man/canon-adapter.1 +2 -2
  14. package/man/canon-artifacts-move.1 +2 -2
  15. package/man/canon-artifacts-prune.1 +75 -0
  16. package/man/canon-artifacts-store.1 +2 -2
  17. package/man/canon-artifacts-verify.1 +2 -2
  18. package/man/canon-artifacts.1 +5 -2
  19. package/man/canon-brief-approve.1 +6 -4
  20. package/man/canon-brief-check.1 +2 -2
  21. package/man/canon-brief-show.1 +2 -2
  22. package/man/canon-brief.1 +2 -2
  23. package/man/canon-change-new.1 +2 -2
  24. package/man/canon-change.1 +2 -2
  25. package/man/canon-completion.1 +2 -2
  26. package/man/canon-context-pack-add.1 +2 -2
  27. package/man/canon-context-pack-show.1 +2 -2
  28. package/man/canon-context-pack-verify.1 +2 -2
  29. package/man/canon-context-pack.1 +2 -2
  30. package/man/canon-context.1 +2 -2
  31. package/man/canon-dashboard.1 +2 -2
  32. package/man/canon-demo-init.1 +2 -2
  33. package/man/canon-demo-review.1 +2 -2
  34. package/man/canon-demo.1 +2 -2
  35. package/man/canon-dispatch-begin.1 +3 -3
  36. package/man/canon-dispatch-diff.1 +2 -2
  37. package/man/canon-dispatch-end.1 +2 -2
  38. package/man/canon-dispatch.1 +2 -2
  39. package/man/canon-divergence-accept.1 +3 -3
  40. package/man/canon-divergence-add.1 +3 -3
  41. package/man/canon-divergence-defer.1 +3 -3
  42. package/man/canon-divergence-list.1 +3 -3
  43. package/man/canon-divergence-resolve.1 +2 -2
  44. package/man/canon-divergence.1 +2 -2
  45. package/man/canon-evidence-add.1 +6 -6
  46. package/man/canon-evidence-approval-payload.1 +3 -3
  47. package/man/canon-evidence-audit.1 +6 -6
  48. package/man/canon-evidence.1 +2 -2
  49. package/man/canon-export.1 +4 -4
  50. package/man/canon-feature-new.1 +2 -2
  51. package/man/canon-feature.1 +2 -2
  52. package/man/canon-finding-add.1 +4 -4
  53. package/man/canon-finding-close.1 +6 -8
  54. package/man/canon-finding-list.1 +3 -3
  55. package/man/canon-finding.1 +2 -2
  56. package/man/canon-format.1 +2 -2
  57. package/man/canon-gate-check.1 +2 -2
  58. package/man/canon-gate-install-hooks.1 +2 -2
  59. package/man/canon-gate-promote.1 +2 -2
  60. package/man/canon-gate.1 +2 -2
  61. package/man/canon-ingest-plans.1 +2 -2
  62. package/man/canon-ingest-records.1 +2 -2
  63. package/man/canon-ingest-sessions.1 +2 -2
  64. package/man/canon-ingest.1 +2 -2
  65. package/man/canon-init.1 +28 -9
  66. package/man/canon-inventory-sync.1 +2 -2
  67. package/man/canon-inventory.1 +2 -2
  68. package/man/canon-ledger-compact.1 +2 -2
  69. package/man/canon-ledger.1 +2 -2
  70. package/man/canon-migrate.1 +2 -2
  71. package/man/canon-plugin-sync.1 +2 -2
  72. package/man/canon-plugin.1 +2 -2
  73. package/man/canon-policy-approve.1 +2 -2
  74. package/man/canon-policy-show.1 +2 -2
  75. package/man/canon-policy.1 +2 -2
  76. package/man/canon-prompt-add.1 +2 -2
  77. package/man/canon-prompt-show.1 +2 -2
  78. package/man/canon-prompt.1 +2 -2
  79. package/man/canon-purge.1 +3 -3
  80. package/man/canon-query.1 +3 -3
  81. package/man/canon-regime-show.1 +2 -2
  82. package/man/canon-regime.1 +2 -2
  83. package/man/canon-report-build.1 +2 -2
  84. package/man/canon-report-check.1 +2 -2
  85. package/man/canon-report-snapshot.1 +2 -2
  86. package/man/canon-report.1 +2 -2
  87. package/man/canon-retrieve.1 +2 -2
  88. package/man/canon-review-change.1 +3 -3
  89. package/man/canon-review-scenario.1 +3 -3
  90. package/man/canon-review.1 +2 -2
  91. package/man/canon-scenario-new.1 +2 -2
  92. package/man/canon-scenario.1 +2 -2
  93. package/man/canon-schema.1 +2 -2
  94. package/man/canon-search.1 +2 -2
  95. package/man/canon-selftest.1 +2 -2
  96. package/man/canon-skills-check.1 +22 -5
  97. package/man/canon-skills-doctor.1 +24 -7
  98. package/man/canon-skills-install.1 +22 -5
  99. package/man/canon-skills-show.1 +2 -2
  100. package/man/canon-skills.1 +3 -3
  101. package/man/canon-status.1 +2 -2
  102. package/man/canon-strategy-approval-payload.1 +3 -3
  103. package/man/canon-strategy-promote.1 +2 -2
  104. package/man/canon-strategy-rollback.1 +4 -4
  105. package/man/canon-strategy.1 +2 -2
  106. package/man/canon-subject-adopt.1 +2 -2
  107. package/man/canon-subject-move.1 +2 -2
  108. package/man/canon-subject-new.1 +2 -2
  109. package/man/canon-subject-show.1 +2 -2
  110. package/man/canon-subject-unadopt.1 +2 -2
  111. package/man/canon-subject.1 +2 -2
  112. package/man/canon-task-done.1 +2 -2
  113. package/man/canon-task.1 +2 -2
  114. package/man/canon-tier-age.1 +2 -2
  115. package/man/canon-tier.1 +2 -2
  116. package/man/canon-trace.1 +4 -4
  117. package/man/canon.1 +3 -3
  118. package/package.json +4 -4
@@ -127,7 +127,11 @@ tree, or in a repo with no commits, a command that needs a commit refuses
127
127
  After a chore approval or a reopen, a scenario whose latest evidence was
128
128
  recorded on the current `codeTree` needs nothing new: a docs-only chore then
129
129
  needs its change-level review alone. What counts as code is `code.exclude` in
130
- `canon.yaml` (globs, default `docs/**` and `*.md`). When code did change,
130
+ `canon.yaml` (globs, default `docs/**` and `*.md`). A chore approved over the
131
+ code as it still is (the `(code tree <id>)` of its `Approved:` line is the
132
+ current tree) asks for no evidence at all, whatever tree the evidence is on, and
133
+ `status` says so; an approval with no recorded tree follows the rule above.
134
+ When code did change,
131
135
  `canon status`, `meta.next` and the refusal hint lead with one batch over
132
136
  every report, for example
133
137
  `canon evidence add --all-scenarios --report junit:a.xml --report junit:b.xml --role implementer`
@@ -156,7 +160,15 @@ an object-store tier, in which case `evidence add`, `review scenario`, `review c
156
160
  `canon artifacts verify` (`--full` re-hashes every blob) ask the store and
157
161
  refuse, never pass, when it cannot be reached. Moving an existing store with
158
162
  `canon artifacts move --tier <tier>` is the repo owner's decision, not a step
159
- of the loop.
163
+ of the loop. So is `canon artifacts prune`, which deletes the blobs no record
164
+ binds any more (the store only grows: a report written anew on every run adds a
165
+ blob per run). A blob stays while the latest evidence or a current review binds
166
+ it (what the gate and `artifacts verify` read), while a record not promoted yet
167
+ binds it, and, with `--keep-days N`, while any evidence or review of the last
168
+ `N` days binds it; the bare run previews the blobs it deletes and why the rest
169
+ stay, and `--commit --plan-digest` deletes. A deleted local blob stays in git
170
+ history (shrinking that history is the repo owner's call, not the command's); a
171
+ deleted object of an object-store tier is gone for good.
160
172
 
161
173
  ### Search and trace
162
174
 
@@ -211,8 +223,11 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
211
223
  your complete command set, every option of every leaf included. Run `canon schema <command> --json` only for a
212
224
  command it does not list, or after a `USAGE` refusal (read `error.field`
213
225
  and `error.expected` first). `canon schema --json` is the tree of every group and command
214
- with its `effect` and `x-canon.roles` (`--as <role>` lists one role's, and `x-canon.as` names it);
215
- its `options` define once the options that two or more commands share (`--repo`, `--as`, `--actor`, …)
226
+ with its `effect` and `x-canon.roles` (`--as <role>` lists one role's, and `x-canon.as` names it).
227
+ `x-canon.roles` is the string `all` for a command all four roles use, else an array of
228
+ role names (empty: only a human runs it), so read it as `roles == "all"` or a name in the array;
229
+ the root's `x-canon.rolesForm` says so once. The tree's
230
+ `options` define once the options that two or more commands share (`--repo`, `--as`, `--actor`, …)
216
231
  and a command names them. `canon schema <group> --json` lists a group's
217
232
  commands; `canon schema <command> --json` is the call surface of one command and nothing
218
233
  else: `options` (each name of a tree option, or an object with `valueType`, a typed
@@ -227,11 +242,18 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
227
242
  gives the JSON Schema of each report in `schemas`, `Input` (the schema of one `--input`
228
243
  document) and `rejects` (what each validator refuses, in order); `#/schemas/<Name>` in
229
244
  the command document resolves there. The first line of every `--help` points at it.
245
+ - An option of the same name takes the same value in every command that has it, and `canon schema` declares it once. An id
246
+ (`--project`, `--role`, `--domain`) is a kebab slug: lowercase letters and digits, single hyphens between them. A name
247
+ (`--actor`, `--approver`, `--relayed-via`) and a sentence (`--reason`, `--summary`, `--override-reason`) are one line of text:
248
+ the white space around it is trimmed (what is recorded, and what a signature is made of, is the trimmed text), and a value
249
+ that is empty once trimmed, or has a control character (a tab, an escape) or a line break inside it, is refused with the
250
+ command's own argument code. `--round` and `--limit` start at 1, and `--regime` is the four-part key `retrieve` and
251
+ `dispatch begin` both take. `finding close` takes `fixed`, `rejected` or `deferred`, never `open`.
230
252
  - Pass `--json` and read stdout as one document, nothing on stderr. Success is
231
253
  `{"ok":true,"data":…,"meta":…}`; failure is
232
254
  `{"ok":false,"error":{…},"meta":…}` (a check that fails keeps its report in
233
255
  `data`). `meta` carries `tool`, `toolVersion`, `contract` (`atip/1`),
234
- `contractVersion` (`1.4`), `schemaVersion`,
256
+ `contractVersion` (`1.5`), `schemaVersion`,
235
257
  `command`, and when present `next`, `warnings` (`[{code, message}]`) and
236
258
  `page`; a repeated write that changed nothing reports `data.unchanged: true`.
237
259
  Absent members are omitted, never `null` or `[]` (a value you sent empty comes back as `received: ""`).
@@ -305,9 +327,9 @@ leaves below take one object only.
305
327
 
306
328
  ### Preview, then `--commit`
307
329
 
308
- The five commands that delete or rewrite existing data (`canon purge`,
330
+ The six commands that delete or rewrite existing data (`canon purge`,
309
331
  `canon tier age`, `canon ledger compact`, `canon artifacts move`,
310
- `canon migrate`) act in two steps. The bare run previews: it writes nothing,
332
+ `canon artifacts prune`, `canon migrate`) act in two steps. The bare run previews: it writes nothing,
311
333
  exits 0 and prints the effects and a `planDigest`. Read the effects, then act
312
334
  with `--commit --plan-digest <planDigest>`. It refuses (`PLAN_STALE`) when
313
335
  the plan differs from the one you previewed, so run the preview again. Appends
@@ -342,15 +364,15 @@ and `canon context` warn when the repo holds 0.27-era state and put
342
364
  ```bash
343
365
  # canon.yaml, starter policy (--policy light|standard|strict, default strict; see canon-policy), AGENTS.md block, commented plans examples
344
366
  canon init
345
- # harnesses for the canon skill; without it init takes the detected .claude/.codex/.omp/.pi (it never asks)
346
- canon init --providers=claude,codex
367
+ # harnesses for the canon skill, one --harness each (--no-harness for none); without them init takes the detected .claude/.codex/.omp/.pi (it never asks)
368
+ canon init --harness claude --harness codex
347
369
  # follows canon.yaml skills.providers (else the install lock's, else the detected ones; none detected installs nothing); prunes projected files the bundle no longer ships when their bytes match the lock, keeps a modified one and reports `kept:`
348
370
  canon skills install
349
- # any subset or none; rewrites skills.providers
350
- canon skills install --providers=claude,codex,omp,pi
371
+ # any subset; rewrites skills.providers (--no-harness records none)
372
+ canon skills install --harness claude --harness codex --harness omp --harness pi
351
373
  # read-only drift check; exit 1 (SKILLS_CHECK_FAILED) names each orphan, a projected file the bundle no longer ships
352
374
  canon skills check
353
- # diagnostics, incl. a stray canon projection for an unselected provider and a projection a formatter rewrote, and `orphan:` lines for projected files the bundle no longer ships; never deletes user files
375
+ # diagnostics, incl. a stray canon projection for an unselected harness and a projection a formatter rewrote, and `orphan:` lines for projected files the bundle no longer ships; never deletes user files
354
376
  canon skills doctor
355
377
  ```
356
378
 
@@ -361,7 +383,7 @@ Claude gets `.claude/skills/canon/`, Codex `.agents/skills/canon/`, OMP
361
383
  `.omp/skills/canon/`, Pi `.pi/skills/canon/` (the retrieve script is a sidecar,
362
384
  not an installed hook). `check` reports a stub written by another canon
363
385
  version; `install` rewrites it. The harness list lives in `canon.yaml` as
364
- `skills: { providers: [...] }`; change it with `canon skills install --providers=<list>`,
386
+ `skills: { providers: [...] }`; change it with `canon skills install --harness <name>` once for each name (or `--no-harness`),
365
387
  never by assuming a default.
366
388
 
367
389
  `install` and `doctor` end with `owned-paths:`, the globs of every path
@@ -255,6 +255,43 @@ review of the chore itself (`canon review change <slug>`) before
255
255
  `--to shipped`; a changed verdict or case set stales that scenario's
256
256
  review as before (and a new `divergence accept`, where the gap remains).
257
257
 
258
+ A chore's approval records the code tree of the work tree at that moment, as
259
+ `(code tree <id>)` in its `Approved:` line (outside the brief digest; none
260
+ outside git or with no commit). While that tree is the current code tree the
261
+ chore changed no code since it was approved, so it asks for no evidence at
262
+ all, whatever tree each scenario's latest evidence is on, and `status` says so
263
+ on its line; its change-level review is still asked, and it must be a review of
264
+ this code (the review records the code tree it saw): a brief edited after the
265
+ approval needs a new review, and so does a review of other code, as when the
266
+ same brief is approved again over code that came after the review. An approval
267
+ with no recorded tree (written before 0.37) follows the rule above.
268
+
269
+ A policy may narrow what a chore asks for with `code_scopes` (0.38): a key is
270
+ a scenario id's area (`core`) or surface (`app.bulkread`), the value a list of
271
+ path patterns written like `code.exclude`; the surface key wins over the area
272
+ key, and a scenario with neither has no scope. For a scenario with a scope the
273
+ chore compares the code tree of its latest evidence with the tree now, and asks
274
+ for new evidence only when a changed path (added, modified, deleted, a rename
275
+ by its old and its new path) matches the scope; the refusal names the first
276
+ three such paths and how many there are. No scope, no recorded tree, or an old
277
+ tree that cannot be computed (the commit is gone, the evidence was recorded over
278
+ uncommitted code) keep the rule above. The scopes stand only while the policy
279
+ is the one a human approved: an agent cannot widen them (an edit after the
280
+ approval fails closed, and so does a change that a brief approval would have
281
+ approved implicitly), and `status` and
282
+ `gate check` warn, never refuse, about a pattern that matches no file or a key
283
+ that matches no scenario. A shared file (lock file, build setting, fixture)
284
+ belongs in the scope of every scenario that depends on it.
285
+ A key none of whose patterns matches a file of the current code tree declares no
286
+ scope (a misspelt `Core/**` never exempts; matching is byte-exact), and an empty
287
+ list is malformed, so that scenario follows the rule above; both are warned.
288
+ `canon brief approve` records the policy approval in its own call except when
289
+ the policy's `code_scopes` differs from the last approved policy's: then it
290
+ approves the brief only, leaves the policy approval stale (the gate fails closed
291
+ until a human reads the scopes and runs `canon policy approve`) and names the
292
+ changed keys, so an agent cannot widen the scopes by asking for a brief's
293
+ approval.
294
+
258
295
  ### Audit records (`canon evidence audit`)
259
296
 
260
297
  canon never generates or runs an audit. An external evaluator does, and
@@ -588,7 +625,10 @@ git-tracked, no credentials). With an object-store tier, `evidence add`,
588
625
  `canon artifacts verify [--full]` ask the store (a HEAD per digest; `--full`
589
626
  downloads and re-hashes) and refuse, never pass, when it cannot be reached.
590
627
  `canon artifacts move --tier <tier>` (a preview; `--commit --plan-digest` acts) moves an existing local
591
- store; it is the repo owner's decision. See `canon-storage`.
628
+ store; it is the repo owner's decision. `canon artifacts prune` (a preview;
629
+ `--commit --plan-digest` acts) deletes the blobs no record binds any more and
630
+ leaves what `gate check` and `artifacts verify` read, so their answers do not
631
+ change; it is the repo owner's decision too. See `canon-storage`.
592
632
 
593
633
  `canon gate check` re-checks every file bound to a LATEST evidence record
594
634
  (the latest per task and per `(project_id, scenario_id)`):
@@ -52,7 +52,11 @@ The production activation path is a signed, paired-evaluation workflow:
52
52
  `meta.next` names the human signing step. The `data` contains the evaluation digest, RFC3339 `approved_at`,
53
53
  subject `strategy:<strategy_id>`, namespace
54
54
  `canon-learning-approval-v1`, and `payload_hex`. `approval-payload` never
55
- reads a private key and never sets `verified`.
55
+ reads a private key and never sets `verified`. `--approval-at` is an RFC 3339
56
+ date-time (`2026-10-02T12:00:00Z`; a date alone, white space around it and a
57
+ one-digit month are refused): canon never stamps it, so fix it once and give
58
+ the same value to the signature and to the record. The bytes hold the instant
59
+ as UTC to the nanosecond, so one instant written `Z` or `+09:00` is one payload.
56
60
  6. Decode `payload_hex` to the exact canonical JSON bytes. The signed object
57
61
  is:
58
62
 
@@ -190,7 +194,8 @@ canon strategy rollback <strategy_id> --reason "<reason>" --actor alice \
190
194
 
191
195
  `--signature-file` is an armored SSH detached signature over the
192
196
  `canon-learning-approval-v1` payload bound to
193
- `strategy:<id>:rollback:<sha256(reason)>`, actor, and `--approval-at`.
197
+ `strategy:<id>:rollback:<sha256(reason)>`, actor, and `--approval-at` (the same
198
+ RFC 3339 date-time that was signed; another instant fails the signature).
194
199
  `actor` MUST be listed in policy-pinned `approval.allowed_signers`; verification
195
200
  uses that file and `ssh-keygen -Y verify`. Successful rollback writes durable
196
201
  provenance, sets lifecycle `rolled_back`, and records the optional contradicting
@@ -88,6 +88,15 @@ on the closing version, shown by `finding list` as `[reason: …]` and carried
88
88
  in the JSON. Give the reason when you reject or defer: it is the only record
89
89
  of why the finding was not fixed.
90
90
 
91
+ Closing `rejected` or `deferred` overturns the judgement of whoever raised
92
+ the finding, so it is the reviewer's: a call that declares another role
93
+ (`--as` or `CANON_ROLE`: planner, implementer, orchestrator) is refused
94
+ with `FINDING_ROLE_DENIED`, nothing is written and the finding stays open.
95
+ `fixed` is closed by every role. The closing version records the role the
96
+ call declared (`--role` is accepted only when it names that role, or when
97
+ none is declared) and no role when none was; `finding list` names who
98
+ closed each closed finding and under which role (`closedBy`, `closedRole`).
99
+
91
100
  `--scenario` (repeatable, each a scenario the index knows; refused with
92
101
  `SCENARIO_NOT_FOUND` otherwise) names the scenarios the finding is
93
102
  about. After a `fixed` close, fresh evidence for those scenarios alone
@@ -155,7 +164,7 @@ text in the summary, not a field.
155
164
 
156
165
  | Disposition | Meaning |
157
166
  |---|---|
158
- | `open` | Raised and not yet dealt with. The default on `finding add`; `finding close --disposition open` reopens. |
167
+ | `open` | Raised and not yet dealt with. The default on `finding add`; `finding close` refuses it (a defect that came back is a new finding). |
159
168
  | `fixed` | Fixed by a commit. Carries `--resolution-rev <rev>` (default `HEAD`) naming a commit this repo holds; only `fixed` may carry one. |
160
169
  | `rejected` | The reviewer's point was considered and declined. Needs `--reason`. |
161
170
  | `deferred` | Accepted, but postponed to later work. Needs `--reason`. |
@@ -164,8 +173,10 @@ text in the summary, not a field.
164
173
 
165
174
  Every reader takes the **latest version per natural key**
166
175
  `(change_id, round, seq)` — the same fold the report's finding panel
167
- uses. A blocker raised `open` and later closed `fixed` counts as fixed; a
168
- fixed finding reopened with `--disposition open` counts as open again.
176
+ uses. A blocker raised `open` and later closed `fixed` counts as fixed.
177
+ A finding is not reopened: `finding close` takes `fixed`, `rejected` or
178
+ `deferred` and refuses `--disposition open`; a defect that came back is a new
179
+ `finding add` (the next `--seq`).
169
180
 
170
181
  ## `canon review scenario`
171
182
 
@@ -446,7 +457,7 @@ subject's `change_ids` (`canon subject adopt`). The subject string is
446
457
  `<change_id>#<round>.<seq>`:
447
458
 
448
459
  ```
449
- open-blocker c-demo#1.1 — open blocker finding by `reviewer-2` on change `c-demo` (subject `demo-subject`): unbounded subprocess wait; fix it and `canon finding close <change> --round <n> --seq <n> --disposition fixed`, or close it as rejected or deferred
460
+ open-blocker c-demo#1.1 — open blocker finding by `reviewer-2` on change `c-demo` (subject `demo-subject`): unbounded subprocess wait; fix it and `canon finding close <change> --round <n> --seq <n> --disposition fixed`, or have a reviewer close it as rejected or deferred
450
461
  ```
451
462
 
452
463
  Findings on changes no in-scope subject has adopted do not block.
@@ -172,6 +172,32 @@ uploads, reads back and verifies every local blob, then writes the
172
172
  `.canon/artifacts/`; commit the removals, `.gitignore` and `canon.yaml`. It is
173
173
  resumable and a second run finds nothing to do.
174
174
 
175
+ The store only grows: a report written anew on every run adds a blob per run.
176
+ `canon artifacts prune [--keep-days N]` (a preview; `--commit --plan-digest
177
+ <digest>` acts) deletes the blobs no record binds. It keeps a blob for every
178
+ reason that holds, and the preview names them: `latest-evidence` (the latest
179
+ evidence per task and per `(project_id, scenario_id)` binds it, what the gate and
180
+ `artifacts verify` read), `current-review` (a review still in effect binds it),
181
+ `staged` (a record not promoted yet binds it) and `within-keep-days` (with
182
+ `--keep-days N`, evidence or a review of the last `N` days, in the ledger or its
183
+ archive, binds it). Everything else in the configured store goes: the local
184
+ directory, or the objects of the tier `artifact_store:` names by the same rule
185
+ (a copy left in the local directory of such a repo is judged by it too). The
186
+ preview counts the blobs and bytes that go and stay, lists the blobs to delete
187
+ a page at a time (`--limit`, `--cursor`, `--all`) and offers no `--commit` when
188
+ there is nothing to delete. The plan digest covers the blobs to delete, the
189
+ blobs to keep with their reasons and every record read, so evidence added since
190
+ the preview is `PLAN_STALE` and nothing is deleted. A repo whose records,
191
+ staging area or archive cannot be read in full is refused: a blob is never
192
+ deleted on a guess. After a prune, `artifacts verify` and `gate check` answer as
193
+ they did. A deleted local blob leaves the working tree: commit the removal. It
194
+ stays in git history, and shrinking that history is the repo owner's call, not
195
+ the command's. A deleted object of a tier cannot be undone, and the preview says
196
+ so with the object count. A delete that fails stops the run: with nothing deleted yet
197
+ it is `ARTIFACTS_STORE_FAILED` (an object) or `WRITE_FAILED` (a local file); after
198
+ some, `ARTIFACTS_PRUNE_INCOMPLETE` names what was deleted, and a new preview
199
+ lists what remains.
200
+
175
201
  ## What `canon report build` does and doesn't read
176
202
 
177
203
  canon exposes layered `stg_`/`int_`/`mart_` query views; `canon report build`
@@ -192,7 +218,7 @@ section listing them and emits a matching stderr `WARN`.
192
218
 
193
219
  ## Retention, export, and access audit
194
220
 
195
- `canon purge --kind <kind> --before <RFC3339> [--commit --plan-digest <planDigest>] [--repo <dir>] [--json]`
221
+ `canon purge --kind <kind> --before <RFC3339 date or date-time> [--commit --plan-digest <planDigest>] [--repo <dir>] [--json]`
196
222
  is the canonical data-lifecycle boundary: the bare run previews: it prints the removal set and
197
223
  its `planDigest` and deletes nothing; `--commit --plan-digest <planDigest>` deletes only if
198
224
  the plan recomputed now has the same digest (`PLAN_STALE`, exit 2, when the
@@ -220,7 +246,7 @@ human's review and `--commit --plan-digest`), and an export's page state (`total
220
246
  file and answers with `data: { output, kind, recordCount }`; `--dry-run`
221
247
  answers with what it would write and writes nothing.
222
248
 
223
- `canon export --kind <kind> [--before <RFC3339>] [--after <RFC3339>]
249
+ `canon export --kind <kind> [--before <RFC3339 date or date-time>] [--after <RFC3339 date or date-time>]
224
250
  [--output <file>] [--json] [--limit <n> | --all] [--cursor <c>]` emits a versioned manifest containing source scope,
225
251
  counts, digests, and redacted metadata. It does not authorize backend access;
226
252
  credentials remain an operator prerequisite. New output files are mode
@@ -290,13 +316,13 @@ skills:
290
316
  providers: [claude, codex] # any of claude, codex, omp, pi; [] for none
291
317
  ```
292
318
 
293
- `canon init` writes it and never asks: `--providers a,b` (or `none`) is the
319
+ `canon init` writes it and never asks: `--harness a --harness b` (or `--no-harness`) is the
294
320
  answer; without it init takes the harnesses whose
295
321
  `.claude`, `.codex`, `.omp` or `.pi` directory exists, and with none detected
296
322
  it writes only a commented example
297
323
  and installs nothing. `.agents` alone never selects Codex. `canon skills
298
324
  install|check|doctor` follow the section; `install` prunes projected files the bundle no longer ships when their bytes match the lock (a modified one stays, reported as `kept:`), `check` exits 1 (`SKILLS_CHECK_FAILED`) naming each orphan and `doctor` prints `orphan:` lines; `canon skills install
299
- --providers=<list>` rewrites it in place. Without the section they use the
325
+ --harness <name>` (once for each name) or `--no-harness` rewrites it in place. Without the section they use the
300
326
  install lock's providers, then the detected ones; nothing undetected is ever
301
327
  added. A present section that is not this shape, or names another harness,
302
328
  fails those commands (exit `1`), and `canon init --check` reports
@@ -381,7 +407,7 @@ retry (the command exits `2` and writes no record).
381
407
  ## The repository write lock
382
408
 
383
409
  A committed destructive command (`canon purge`, `canon tier age`, `canon ledger
384
- compact`, `canon artifacts move`, `canon migrate`) recomputes its plan, checks
410
+ compact`, `canon artifacts move`, `canon artifacts prune`, `canon migrate`) recomputes its plan, checks
385
411
  its digest and then makes the effects, and nothing may change the plan in
386
412
  between. It holds an OS file lock on `.canon/repo-write.lock` for the whole
387
413
  span, from before it recomputes the plan to after its last effect; a preview
@@ -547,8 +547,9 @@ warn, and a command that writes and judges it is refused
547
547
  `reason`), one rule in one section, reason required; add `match` to waive
548
548
  only the findings whose matched text contains it. Listed in the output.
549
549
  - **`approve`** records the human's answer: it writes
550
- `Approved: <who> <when> — "<words>" (brief sha256:<digest>)` into the
551
- brief and records the policy approval in the same call. It refuses
550
+ `Approved: <who> <when> — "<words>" (code tree <id>) (brief sha256:<digest>)`
551
+ into the brief (the code tree, 0.37, is the work tree's as it is now and is
552
+ left out outside git or with no commit) and records the policy approval in the same call. It refuses
552
553
  (exit 2) while the check has structure blockers. Edit the brief
553
554
  afterwards and every reader says `BRIEF_APPROVAL_STALE` until a
554
555
  human answers again and `approve` runs again. Run it only from the
@@ -617,8 +618,8 @@ uses, so status and the gate cannot disagree about a gap:
617
618
  something after it, and sits outside HTML comments (`<!-- … -->`,
618
619
  multi-line included) and fenced code blocks (```` ``` ```` or `~~~`).
619
620
  `canon brief approve` writes it from the human's answer, as
620
- `Approved: <who> <when> — "<the human's words>" (brief sha256:<digest>)`,
621
- the digest covering the brief without its `Approved:` lines. A brief
621
+ `Approved: <who> <when> — "<the human's words>" (code tree <id>) (brief sha256:<digest>)`,
622
+ the digest covering the brief without its `Approved:` lines (the tree marker is outside it; a line without one is read as before). A brief
622
623
  edited after that reads `brief: not approved (<brief> changed after its
623
624
  approval (BRIEF_APPROVAL_STALE))` and names the re-approval
624
625
  command: the changed brief needs a new human answer. A line with no
@@ -107,7 +107,7 @@ canon evidence approval-payload --scenario auth.login.01 --project root --approv
107
107
  ```
108
108
  ```text
109
109
  # Record an external evaluator's re-audit of one scenario (class `audit`; the verdict follows --audit-result; canon never runs the evaluator)
110
- usage: canon evidence audit <SCENARIO_ID> --ref <TEXT> --evaluator <ID> --evaluator-version <TEXT> --evaluator-digest <DIGEST> --audit-result <confirmed|refuted|indeterminate> [--project <PROJECT_ID>] [--summary <TEXT>] [--command-result <TEXT> (with --summary)] [--run <RUN_ID>] [--actor <ACTOR_ID>] [--role <ROLE>] [--session <SESSION_ID>] [--rev <REV>] [--artifact <PATH>]* [--report <FORMAT:PATH>]* [--report-case <NAME> (with --report)]* [--max-artifact-mib <N>] [--override-reason <TEXT>] [--promote | --no-promote] [--input]
110
+ usage: canon evidence audit <SCENARIO_ID> --ref <TEXT> --evaluator <EVALUATOR_ID> --evaluator-version <TEXT> --evaluator-digest <DIGEST> --audit-result <confirmed|refuted|indeterminate> [--project <PROJECT_ID>] [--summary <TEXT>] [--command-result <TEXT> (with --summary)] [--run <RUN_ID>] [--actor <ACTOR_ID>] [--role <ROLE>] [--session <SESSION_ID>] [--rev <REV>] [--artifact <PATH>]* [--report <FORMAT:PATH>]* [--report-case <NAME> (with --report)]* [--max-artifact-mib <N>] [--override-reason <TEXT>] [--promote | --no-promote] [--input]
111
111
  ```
112
112
  ```bash
113
113
  canon evidence audit auth.login.01 --ref audit-report.json --evaluator eval-1 --evaluator-version 2.1 --evaluator-digest 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef --audit-result confirmed --role implementer --json
@@ -212,7 +212,7 @@ canon task done add-login#1 --json
212
212
  ```
213
213
  ```text
214
214
  # Follow a finding's review loop in time order: review, finding, fix, re-review, evidence
215
- usage: canon trace <ID>
215
+ usage: canon trace <TRACE_ID>
216
216
  ```
217
217
  ```bash
218
218
  canon trace add-login_1_1 --json
@@ -306,7 +306,8 @@ canon evidence add --input '[{"scenario":"auth.login.01","class":"test-run","ref
306
306
  re-checks them, so the working-tree report may be gitignored. Run
307
307
  `canon artifacts verify` to ask the store yourself; it refuses, never
308
308
  passes, when an object store cannot be reached. Moving an existing store
309
- (`canon artifacts move --tier`) is the repo owner's call: do not run it.
309
+ (`canon artifacts move --tier`) and deleting the blobs no record binds
310
+ (`canon artifacts prune`) are the repo owner's call: do not run them.
310
311
  For a scenario about what users see, let the test report carry its
311
312
  screenshots: Playwright's JUnit reporter attaches, per test case, what a
312
313
  test attaches (`testInfo.attach(name, {path})`, or `screenshot: 'on'`), and
@@ -342,7 +343,9 @@ canon evidence add --input '[{"scenario":"auth.login.01","class":"test-run","ref
342
343
  latest evidence was recorded on a different `codeTree` than the current
343
344
  code (`code.exclude` in `canon.yaml` decides what is not code; the default
344
345
  is `docs/**` and `*.md`). A docs-only chore needs its change-level review
345
- alone. When code did change, the shipping refusal, `status` and
346
+ alone, and so does a chore whose approval recorded the code tree that is
347
+ still the current one (`(code tree <id>)` in its `Approved:` line; `status`
348
+ says so): it asks for no evidence at all. When code did change, the shipping refusal, `status` and
346
349
  `meta.next` lead with one command over every report, with the real paths
347
350
  (`--project <id>` is added only with several spec roots):
348
351
  `canon evidence add --all-scenarios --report junit:a.xml --report junit:b.xml --role implementer`.
@@ -44,6 +44,14 @@ usage: canon artifacts move --tier <TIER> [--commit --plan-digest <PLAN_DIGEST>]
44
44
  canon artifacts move --tier cold --json
45
45
  ```
46
46
  ```text
47
+ # Delete the artifact blobs no record binds any more (the bare run previews; --commit --plan-digest deletes)
48
+ usage: canon artifacts prune [--keep-days <N>] [--limit <N> | --all] [--cursor <CURSOR>] [--commit --plan-digest <PLAN_DIGEST>] [--input]
49
+ # a bare run previews and prints planDigest; `--commit --plan-digest <PLAN_DIGEST>` with that digest acts
50
+ ```
51
+ ```bash
52
+ canon artifacts prune --keep-days 30 --json
53
+ ```
54
+ ```text
47
55
  # Store the bound files of existing evidence records and current reviews in the artifact store (.canon/artifacts/sha256/)
48
56
  usage: canon artifacts store [--max-artifact-mib <N>] [--dry-run] [--input]
49
57
  ```
@@ -115,7 +123,7 @@ canon demo review --json
115
123
  ```
116
124
  ```text
117
125
  # Mint a Run manifest with retrieved guidance and context/policy lineage
118
- usage: canon dispatch begin --regime <KEY> [--role <ROLE>] [--actor <ACTOR_ID>] [--session <SESSION_ID>] [--provider <NAME>] [--model <NAME>] [--skill <ID>] [--skill-digest <DIGEST> (with --skill)] [--manifest <FILE>] [--prompt-bundle <NAME@VERSION>] [--task <TASK_ID>] [--parent-run <RUN_ID>] [--input]
126
+ usage: canon dispatch begin --regime <KEY> [--role <ROLE>] [--actor <ACTOR_ID>] [--session <SESSION_ID>] [--provider <NAME>] [--model <NAME>] [--skill <SKILL_ID>] [--skill-digest <DIGEST> (with --skill)] [--manifest <FILE>] [--prompt-bundle <NAME@VERSION>] [--task <TASK_ID>] [--parent-run <RUN_ID>] [--input]
119
127
  ```
120
128
  ```bash
121
129
  canon dispatch begin --regime implementer/my-repo/api/abcdef012345 --role implementer --json
@@ -206,7 +214,7 @@ canon ingest sessions --json
206
214
  ```
207
215
  ```text
208
216
  # Set up canon in a repo (canon.yaml, a starter policy, the AGENTS.md block, a plans home)
209
- usage: canon init [--check] [--no-agents-md | --check] [--policy <light|standard|strict> | --check | --no-policy] [--providers <LIST> | --check] [--language <TAG> | --check] [--dry-run | --check] [--input]
217
+ usage: canon init [--check] [--no-agents-md | --check] [--policy <light|standard|strict> | --check | --no-policy] [--harness <claude|codex|omp|pi> | --check | --no-harness]* [--language <TAG> | --check] [--dry-run | --check] [--input]
210
218
  ```
211
219
  ```bash
212
220
  canon init --json
@@ -335,21 +343,21 @@ canon selftest --suite trust-spine-gate --json
335
343
  ```
336
344
  ```text
337
345
  # Check canonical projections without writing; exit 1 on drift, a legacy remnant, or a lock another canon version wrote
338
- usage: canon skills check [--skills-source <DIR>] [--providers <LIST>]
346
+ usage: canon skills check [--skills-source <DIR>] [--harness <claude|codex|omp|pi> | --no-harness]*
339
347
  ```
340
348
  ```bash
341
349
  canon skills check --json
342
350
  ```
343
351
  ```text
344
- # Print diagnostics for canonical projections, the install lock's canon version, legacy remnants, canon projections for a provider that is not selected, and other skills whose description claims build work; reports only, never edits
345
- usage: canon skills doctor [--skills-source <DIR>] [--providers <LIST>]
352
+ # Print diagnostics for canonical projections, the install lock's canon version, legacy remnants, canon projections for a harness that is not selected, and other skills whose description claims build work; reports only, never edits
353
+ usage: canon skills doctor [--skills-source <DIR>] [--harness <claude|codex|omp|pi> | --no-harness]*
346
354
  ```
347
355
  ```bash
348
356
  canon skills doctor --json
349
357
  ```
350
358
  ```text
351
359
  # Install the canonical `canon` bundle or legacy developer skills
352
- usage: canon skills install [--skills-source <DIR>] [--providers <LIST>] [--dry-run] [--input]
360
+ usage: canon skills install [--skills-source <DIR>] [--harness <claude|codex|omp|pi> | --no-harness]* [--dry-run] [--input]
353
361
  ```
354
362
  ```bash
355
363
  canon skills install --json
@@ -384,7 +392,7 @@ canon strategy promote 01ARZ3NDEKTSV4RRFFQ69G5FAV --json
384
392
  ```
385
393
  ```text
386
394
  # Disable an active strategy with durable rollback provenance
387
- usage: canon strategy rollback <STRATEGY_ID> --reason <TEXT> --actor <ACTOR_ID> --signature-file <FILE> --approval-at <TIMESTAMP> [--contradicting-trajectory <ID>] [--input]
395
+ usage: canon strategy rollback <STRATEGY_ID> --reason <TEXT> --actor <ACTOR_ID> --signature-file <FILE> --approval-at <TIMESTAMP> [--contradicting-trajectory <TRAJECTORY_ID>] [--input]
388
396
  ```
389
397
  ```bash
390
398
  canon strategy rollback 01ARZ3NDEKTSV4RRFFQ69G5FAV --reason "regressed in production" --actor alice --signature-file approval.sig --approval-at 2030-01-01T00:00:00Z --json
@@ -434,7 +442,7 @@ canon tier age --json
434
442
  ```
435
443
  ```text
436
444
  # Follow a finding's review loop in time order: review, finding, fix, re-review, evidence
437
- usage: canon trace <ID>
445
+ usage: canon trace <TRACE_ID>
438
446
  ```
439
447
  ```bash
440
448
  canon trace add-login_1_1 --json
@@ -631,7 +639,7 @@ read that changed since is `PLAN_STALE` too, and `meta.next[0]` is the preview
631
639
  to run again. A commit holds the repository write lock for its whole run:
632
640
  another command that writes waits for it, and one that waited 30 seconds
633
641
  answers `REPO_LOCK_UNAVAILABLE` (exit 2, retryable): run it again. A document passed
634
- with `--input` never carries `--commit` or `--plan-digest`, and these five
642
+ with `--input` never carries `--commit` or `--plan-digest`, and these six
635
643
  leaves take one object only (`INPUT_INVALID`).
636
644
 
637
645
  ```bash
@@ -641,7 +649,9 @@ canon ledger compact
641
649
  ```
642
650
 
643
651
  `canon artifacts move --tier <tier>` moves the local artifact store to an
644
- object store and removes the local blobs, and `purge` deletes records. They
652
+ object store and removes the local blobs, `canon artifacts prune` deletes the
653
+ blobs no record binds any more (a deleted local blob stays in git history; a
654
+ deleted object of a tier is gone for good), and `purge` deletes records. They
645
655
  are the repo owner's decisions, not steps of the loop: run the preview, give
646
656
  the human the effects, and run the commit only on their answer. If the repo is
647
657
  large, the store is slow or the human has not asked for it, do not run it.
@@ -165,7 +165,7 @@ canon subject unadopt demo --change add-login --json
165
165
  ```
166
166
  ```text
167
167
  # Follow a finding's review loop in time order: review, finding, fix, re-review, evidence
168
- usage: canon trace <ID>
168
+ usage: canon trace <TRACE_ID>
169
169
  ```
170
170
  ```bash
171
171
  canon trace add-login_1_1 --json
@@ -87,7 +87,7 @@ canon finding add --change add-login --round 1 --seq 2 --severity should-fix --i
87
87
  ```
88
88
  ```text
89
89
  # Move an already-committed finding's disposition
90
- usage: canon finding close <CHANGE_ID> --round <N> --seq <N> --disposition <open|fixed|rejected|deferred> [--resolution-rev <REV>] [--reason <TEXT>] [--actor <ACTOR_ID>] [--role <ROLE>] [--session <SESSION_ID>] [--promote | --no-promote] [--input]
90
+ usage: canon finding close <CHANGE_ID> --round <N> --seq <N> --disposition <fixed|rejected|deferred> [--resolution-rev <REV>] [--reason <TEXT>] [--actor <ACTOR_ID>] [--role <ROLE>] [--session <SESSION_ID>] [--promote | --no-promote] [--input]
91
91
  ```
92
92
  ```bash
93
93
  canon finding close add-login --round 1 --seq 1 --disposition rejected --reason "works as designed" --json
@@ -171,7 +171,7 @@ canon status --json
171
171
  ```
172
172
  ```text
173
173
  # Follow a finding's review loop in time order: review, finding, fix, re-review, evidence
174
- usage: canon trace <ID>
174
+ usage: canon trace <TRACE_ID>
175
175
  ```
176
176
  ```bash
177
177
  canon trace add-login_1_1 --json
@@ -325,6 +325,9 @@ covered for the ship guard and stays listed as `accepted-divergence` in
325
325
  (`FINDING_REASON_REQUIRED`), and `finding list` shows it as
326
326
  `[reason: …]` so the next reader sees why it was not fixed. Closing a
327
327
  finding that already has that disposition is `unchanged`.
328
+ Only you close a finding `rejected` or `deferred`: another role is refused
329
+ (`FINDING_ROLE_DENIED`), so declare `--as reviewer`; the close records
330
+ that role.
328
331
  - Sign off in one batch with `review scenario <ids>`, all or nothing. It writes
329
332
  directly; nothing to promote. canon stores and re-checks attached bytes
330
333
  and never compares images.
@@ -1,6 +1,6 @@
1
1
  .ie \n(.g .ds Aq \(aq
2
2
  .el .ds Aq '
3
- .TH canon-adapter-authorize 1 "authorize 0.36.0"
3
+ .TH canon-adapter-authorize 1 "authorize 0.38.0"
4
4
  .SH NAME
5
5
  canon\-adapter\-authorize \- Authorize declared capabilities against repository policy (preflight only)
6
6
  .SH SYNOPSIS
@@ -41,4 +41,4 @@ Print help
41
41
  \fB\-V\fR, \fB\-\-version\fR
42
42
  Print version
43
43
  .SH VERSION
44
- v0.36.0
44
+ v0.38.0
@@ -1,6 +1,6 @@
1
1
  .ie \n(.g .ds Aq \(aq
2
2
  .el .ds Aq '
3
- .TH canon-adapter-validate 1 "validate 0.36.0"
3
+ .TH canon-adapter-validate 1 "validate 0.38.0"
4
4
  .SH NAME
5
5
  canon\-adapter\-validate \- Read and validate one provider\-neutral response envelope
6
6
  .SH SYNOPSIS
@@ -41,4 +41,4 @@ Print help
41
41
  \fB\-V\fR, \fB\-\-version\fR
42
42
  Print version
43
43
  .SH VERSION
44
- v0.36.0
44
+ v0.38.0
@@ -1,6 +1,6 @@
1
1
  .ie \n(.g .ds Aq \(aq
2
2
  .el .ds Aq '
3
- .TH canon-adapter 1 "adapter 0.36.0"
3
+ .TH canon-adapter 1 "adapter 0.38.0"
4
4
  .SH NAME
5
5
  canon\-adapter \- Validate a provider\-neutral adapter response without executing a provider
6
6
  .SH SYNOPSIS
@@ -43,4 +43,4 @@ Examples:
43
43
  canon adapter validate \-\-response response.json
44
44
  canon adapter validate \-\-response response.json \-\-repo . \-\-json
45
45
  .SH VERSION
46
- v0.36.0
46
+ v0.38.0
@@ -1,6 +1,6 @@
1
1
  .ie \n(.g .ds Aq \(aq
2
2
  .el .ds Aq '
3
- .TH canon-artifacts-move 1 "move 0.36.0"
3
+ .TH canon-artifacts-move 1 "move 0.38.0"
4
4
  .SH NAME
5
5
  canon\-artifacts\-move \- Move the local artifact blobs to an object\-store tier, verify them, and remove the local copies
6
6
  .SH SYNOPSIS
@@ -60,4 +60,4 @@ The bare run previews: it lists every upload and removal and prints a planDigest
60
60
 
61
61
  Idempotent and resumable: a run stopped anywhere leaves a repo the gate still passes, and the next run finishes; a second run finds nothing to do. A blob whose bytes do not match its name is never moved. Moving back to local is refused; `\-\-tier local` on a local repo is a no\-op.
62
62
  .SH VERSION
63
- v0.36.0
63
+ v0.38.0