@journeykit/canon 0.33.0 → 0.35.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/dist/skills/SKILL.src.md +44 -23
- package/dist/skills/reference/canon-artifact-ingest.md +6 -3
- package/dist/skills/reference/canon-authoring.md +8 -5
- package/dist/skills/reference/canon-context.md +8 -5
- package/dist/skills/reference/canon-fmt.md +2 -1
- package/dist/skills/reference/canon-gate.md +12 -8
- package/dist/skills/reference/canon-inventory.md +13 -10
- package/dist/skills/reference/canon-plan-import.md +6 -3
- package/dist/skills/reference/canon-plugins.md +12 -6
- package/dist/skills/reference/canon-report-dashboard.md +6 -3
- package/dist/skills/reference/canon-review.md +2 -2
- package/dist/skills/reference/canon-session-ingest.md +12 -6
- package/dist/skills/reference/canon-storage.md +48 -16
- package/dist/skills/reference/canon-subject.md +27 -18
- package/dist/skills/reference/role-implementer.md +58 -58
- package/dist/skills/reference/role-orchestrator.md +128 -123
- package/dist/skills/reference/role-planner.md +44 -44
- package/dist/skills/reference/role-reviewer.md +46 -46
- package/man/canon-adapter-authorize.1 +3 -3
- package/man/canon-adapter-validate.1 +3 -3
- package/man/canon-adapter.1 +3 -3
- package/man/canon-artifacts-move.1 +3 -3
- package/man/canon-artifacts-store.1 +3 -3
- package/man/canon-artifacts-verify.1 +3 -3
- package/man/canon-artifacts.1 +3 -3
- package/man/canon-brief-approve.1 +3 -3
- package/man/canon-brief-check.1 +3 -3
- package/man/canon-brief-show.1 +3 -3
- package/man/canon-brief.1 +3 -3
- package/man/canon-change-new.1 +3 -3
- package/man/canon-change.1 +3 -3
- package/man/canon-completion.1 +3 -3
- package/man/canon-context-pack-add.1 +3 -3
- package/man/canon-context-pack-show.1 +3 -3
- package/man/canon-context-pack-verify.1 +3 -3
- package/man/canon-context-pack.1 +3 -3
- package/man/canon-context.1 +4 -4
- package/man/canon-dashboard.1 +3 -3
- package/man/canon-demo-init.1 +3 -3
- package/man/canon-demo-review.1 +3 -3
- package/man/canon-demo.1 +3 -3
- package/man/canon-dispatch-begin.1 +3 -3
- package/man/canon-dispatch-diff.1 +3 -3
- package/man/canon-dispatch-end.1 +3 -3
- package/man/canon-dispatch.1 +3 -3
- package/man/canon-divergence-accept.1 +3 -3
- package/man/canon-divergence-add.1 +3 -3
- package/man/canon-divergence-defer.1 +3 -3
- package/man/canon-divergence-list.1 +6 -6
- package/man/canon-divergence-resolve.1 +3 -3
- package/man/canon-divergence.1 +3 -3
- package/man/canon-evidence-add.1 +3 -3
- package/man/canon-evidence-approval-payload.1 +3 -3
- package/man/canon-evidence-audit.1 +3 -3
- package/man/canon-evidence.1 +3 -3
- package/man/canon-export.1 +6 -6
- package/man/canon-feature-new.1 +3 -3
- package/man/canon-feature.1 +3 -3
- package/man/canon-finding-add.1 +4 -4
- package/man/canon-finding-close.1 +3 -3
- package/man/canon-finding-list.1 +6 -6
- package/man/canon-finding.1 +3 -3
- package/man/canon-format.1 +3 -3
- package/man/canon-gate-check.1 +3 -3
- package/man/canon-gate-install-hooks.1 +3 -3
- package/man/canon-gate-promote.1 +3 -3
- package/man/canon-gate.1 +3 -3
- package/man/canon-ingest-plans.1 +3 -3
- package/man/canon-ingest-records.1 +3 -3
- package/man/canon-ingest-sessions.1 +3 -3
- package/man/canon-ingest.1 +3 -3
- package/man/canon-init.1 +9 -9
- package/man/canon-inventory-sync.1 +3 -3
- package/man/canon-inventory.1 +3 -3
- package/man/canon-ledger-compact.1 +3 -3
- package/man/canon-ledger.1 +3 -3
- package/man/canon-migrate.1 +3 -3
- package/man/canon-plugin-sync.1 +3 -3
- package/man/canon-plugin.1 +3 -3
- package/man/canon-policy-approve.1 +3 -3
- package/man/canon-policy-show.1 +3 -3
- package/man/canon-policy.1 +3 -3
- package/man/canon-prompt-add.1 +3 -3
- package/man/canon-prompt-show.1 +3 -3
- package/man/canon-prompt.1 +3 -3
- package/man/canon-purge.1 +3 -3
- package/man/canon-query.1 +6 -6
- package/man/canon-regime-show.1 +3 -3
- package/man/canon-regime.1 +3 -3
- package/man/canon-report-build.1 +3 -3
- package/man/canon-report-check.1 +3 -3
- package/man/canon-report-snapshot.1 +3 -3
- package/man/canon-report.1 +3 -3
- package/man/canon-retrieve.1 +4 -4
- package/man/canon-review-change.1 +3 -3
- package/man/canon-review-scenario.1 +3 -3
- package/man/canon-review.1 +3 -3
- package/man/canon-scenario-new.1 +3 -3
- package/man/canon-scenario.1 +3 -3
- package/man/canon-schema.1 +14 -6
- package/man/canon-search.1 +3 -3
- package/man/canon-selftest.1 +3 -3
- package/man/canon-skills-check.1 +3 -3
- package/man/canon-skills-doctor.1 +3 -3
- package/man/canon-skills-install.1 +3 -3
- package/man/canon-skills-show.1 +6 -6
- package/man/canon-skills.1 +3 -3
- package/man/canon-status.1 +4 -4
- package/man/canon-strategy-approval-payload.1 +3 -3
- package/man/canon-strategy-promote.1 +3 -3
- package/man/canon-strategy-rollback.1 +3 -3
- package/man/canon-strategy.1 +3 -3
- package/man/canon-subject-adopt.1 +3 -3
- package/man/canon-subject-move.1 +3 -3
- package/man/canon-subject-new.1 +4 -4
- package/man/canon-subject-show.1 +3 -3
- package/man/canon-subject-unadopt.1 +3 -3
- package/man/canon-subject.1 +3 -3
- package/man/canon-task-done.1 +3 -3
- package/man/canon-task.1 +3 -3
- package/man/canon-tier-age.1 +3 -3
- package/man/canon-tier.1 +3 -3
- package/man/canon-trace.1 +3 -3
- package/man/canon.1 +3 -3
- package/package.json +4 -4
package/dist/skills/SKILL.src.md
CHANGED
|
@@ -210,22 +210,36 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
210
210
|
- Your role guide's **Commands** block (`canon skills show role-<role>`) is
|
|
211
211
|
your complete command set, every option of every leaf included. Run `canon schema <command> --json` only for a
|
|
212
212
|
command it does not list, or after a `USAGE` refusal (read `error.field`
|
|
213
|
-
and `error.expected` first). `canon schema`
|
|
213
|
+
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); `canon schema <group> --json` lists a group's
|
|
215
|
+
commands; `canon schema <command> --json` is one command in full: `options` (each with
|
|
216
|
+
`valueType`, a typed `default`, `possibleValues`, `env`, `flagOnly`), `errors`, `outputs`
|
|
217
|
+
with the JSON Schema of each report in `schemas`, `input` (the schema of one `--input`
|
|
218
|
+
document and a complete `example`) and `examples`. The first line of every `--help`
|
|
219
|
+
points at it.
|
|
214
220
|
- Pass `--json` and read stdout as one document, nothing on stderr. Success is
|
|
215
221
|
`{"ok":true,"data":…,"meta":…}`; failure is
|
|
216
222
|
`{"ok":false,"error":{…},"meta":…}` (a check that fails keeps its report in
|
|
217
|
-
`data`). `meta` carries `tool`, `toolVersion`, `contract` (`atip/1`),
|
|
223
|
+
`data`). `meta` carries `tool`, `toolVersion`, `contract` (`atip/1`),
|
|
224
|
+
`contractVersion` (`1.2`), `schemaVersion`,
|
|
218
225
|
`command`, and when present `next`, `warnings` (`[{code, message}]`) and
|
|
219
226
|
`page`; a repeated write that changed nothing reports `data.unchanged: true`.
|
|
220
|
-
Absent members are omitted, never `null` or `[]
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
227
|
+
Absent members are omitted, never `null` or `[]` (a value you sent empty comes back as `received: ""`).
|
|
228
|
+
Read the members you know and ignore the ones you do not: a later canon
|
|
229
|
+
adds members, and a value of a closed set you have not seen (a `severity`, an
|
|
230
|
+
`outcome`, a `reason`) is one item to leave out, never a reason to reject the document. A paged list puts
|
|
231
|
+
`meta.page.nextCursor` in the first entry of the call's `meta.next` as `--cursor=<nextCursor>`
|
|
232
|
+
(run that entry as it is); no `nextCursor` means no more.
|
|
233
|
+
On failure branch on `error.code`, and on `error.reason` where the code has
|
|
234
|
+
reasons (`INPUT_INVALID` says `NOT_JSON`, `UNKNOWN_KEY`, `STDIN_TTY`, … so you
|
|
235
|
+
know whether to fix the JSON or the shell); fix the option `error.field` names
|
|
224
236
|
using the `error.expected` values (`field` is an option name, or a JSON
|
|
225
|
-
pointer such as `/
|
|
226
|
-
follow `error.hint`:
|
|
227
|
-
|
|
228
|
-
`canon schema --
|
|
237
|
+
pointer such as `/2/scenario` into an `--input` document, `/<index>/<key>` in a batch), and
|
|
238
|
+
follow `error.hint`: it is one runnable command line that starts with `canon`, the
|
|
239
|
+
same with `<PLACEHOLDER>`s you fill in, or one sentence. The codes
|
|
240
|
+
are stable; `canon schema --errors --json` lists them with their reasons and
|
|
241
|
+
`canon schema --error <CODE>` explains one. A warning code (`meta.warnings`) is in
|
|
242
|
+
`canon schema --warnings --json`; `canon schema --warning <CODE>` explains one.
|
|
229
243
|
- **Exit codes:** only 0, 1 and 2 exist: 0 ok; 1 the command ran and its answer
|
|
230
244
|
is negative or incomplete (a failed check, a violation, `unverifiable` when
|
|
231
245
|
nothing was examined, a partly failed batch); 2 refused to run (usage,
|
|
@@ -244,8 +258,8 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
244
258
|
has blockers; the approval step appears only when the brief is clean and
|
|
245
259
|
unapproved.
|
|
246
260
|
- Page long lists with `--limit <n>` and `--cursor <nextCursor>` (`--all`
|
|
247
|
-
for everything), and
|
|
248
|
-
`query`, `finding list`, `divergence list`, `context`).
|
|
261
|
+
for everything); a cursor holds only for the call that issued it, so change nothing but `--limit`, `--all`, `--fields` and `--json`, and keep `CANON_ROLE` as it was (`CURSOR_INVALID` with `error.reason` `ARGUMENTS_CHANGED` otherwise; `FOREIGN` for a cursor of another command or another canon version: start again from the first page). `--limit`, `--cursor`, `--all` and `--fields` are flags: an `--input` document key of that name is `INPUT_INVALID` with `reason` `FLAG_ONLY_KEY`. Project fields with `--fields a,b`
|
|
262
|
+
(`status`, `export`, `query`, `finding list`, `divergence list`, `context`): the paths `canon schema <command> --json` lists under `outputs[].fields`, spelled as the answer spells them; `meta.fields` lists what was kept.
|
|
249
263
|
- `--override-reason <text>` is the only way to proceed past a waivable
|
|
250
264
|
refusal; it is recorded, echoed in `data.overrides[]` and listed by `status`
|
|
251
265
|
for the human. There is no `--force`. `brief approve`, `policy approve`,
|
|
@@ -263,11 +277,12 @@ the positional arguments. An object is one invocation; a JSON array (or NDJSON
|
|
|
263
277
|
from a file or stdin) is a batch, run in order and answered with
|
|
264
278
|
`data.items[]` (`index`, `status` of `written`, `unchanged`, `failed` or
|
|
265
279
|
`skipped`, and that element's `data` or `error`). A batch is validated whole
|
|
266
|
-
before anything is written: an invalid element writes nothing and exits 2
|
|
267
|
-
`error.field` pointing at
|
|
268
|
-
|
|
269
|
-
`
|
|
270
|
-
`
|
|
280
|
+
before anything is written, and that check reads no state: an invalid element writes nothing and exits 2 with
|
|
281
|
+
its own code, `error.field` pointing at `/<i>/<key>` and no `data`. An element that fails when it runs (the object
|
|
282
|
+
it names does not exist) stops the batch: exit 1, `BATCH_INCOMPLETE`, `error.field` exactly `/<i>`, the element
|
|
283
|
+
`failed` with its own `error` (no `data`), the later ones `skipped`, and the earlier ones done (not undone). Re-running the same batch reports the finished elements
|
|
284
|
+
`unchanged`. A typo in a key is refused (`INPUT_INVALID`, `field` naming the key), never dropped; a document with several problems reports them all, the first as the error and every one in `error.details` in the order the document wrote its keys, and a value outside a closed set is `INPUT_INVALID` too (`reason` `INVALID_VALUE`, `field` the key), not `USAGE`. Every non-empty line of an NDJSON file is a document (a `#` line is not a comment). Integers compare by number: `1`, `"1"` and `--round +1` are one value, and `"+1"`, `"0x1"` and `1.0` in a document are `INVALID_VALUE`.
|
|
285
|
+
`canon schema <command> --json` shows the leaf's `input`: the schema of one document and a complete `example`.
|
|
271
286
|
|
|
272
287
|
```text
|
|
273
288
|
canon scenario new --input '[{"operands":["auth.login.01"],"title":"Logs in","case":"happy"},{"operands":["auth.login.02"],"title":"Wrong password","case":"failure"}]'
|
|
@@ -315,12 +330,18 @@ and `canon context` warn when the repo holds 0.27-era state and put
|
|
|
315
330
|
## Setup and provider projection
|
|
316
331
|
|
|
317
332
|
```bash
|
|
318
|
-
|
|
319
|
-
canon init
|
|
320
|
-
|
|
321
|
-
canon
|
|
322
|
-
canon skills
|
|
323
|
-
canon skills
|
|
333
|
+
# canon.yaml, starter policy (--policy light|standard|strict, default strict; see canon-policy), AGENTS.md block, commented plans examples
|
|
334
|
+
canon init
|
|
335
|
+
# harnesses for the canon skill; without it init takes the detected .claude/.codex/.omp/.pi (it never asks)
|
|
336
|
+
canon init --providers=claude,codex
|
|
337
|
+
# 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:`
|
|
338
|
+
canon skills install
|
|
339
|
+
# any subset or none; rewrites skills.providers
|
|
340
|
+
canon skills install --providers=claude,codex,omp,pi
|
|
341
|
+
# read-only drift check; exit 1 (SKILLS_DRIFT) names each orphan, a projected file the bundle no longer ships
|
|
342
|
+
canon skills check
|
|
343
|
+
# 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
|
|
344
|
+
canon skills doctor
|
|
324
345
|
```
|
|
325
346
|
|
|
326
347
|
`install` writes, per selected harness, a short `SKILL.md` stub (this file's
|
|
@@ -9,9 +9,12 @@ verdicts, and writes idempotently.
|
|
|
9
9
|
## `canon ingest records [--repo <dir>] [--watch]`
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
|
|
13
|
-
canon ingest records
|
|
14
|
-
|
|
12
|
+
# one pass over the repo's artifacts
|
|
13
|
+
canon ingest records
|
|
14
|
+
# a specific repo
|
|
15
|
+
canon ingest records --repo ../svc
|
|
16
|
+
# poll loop
|
|
17
|
+
canon ingest records --watch
|
|
15
18
|
```
|
|
16
19
|
|
|
17
20
|
Source roots resolve from `canon.yaml`'s `artifacts.sources` config
|
|
@@ -92,11 +92,14 @@ a scoped gate.
|
|
|
92
92
|
## The commands — and the one thing you never type
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
|
|
95
|
+
# once per surface
|
|
96
|
+
canon feature new checkout.cart --title "Cart"
|
|
97
|
+
# once per behavior
|
|
96
98
|
canon scenario new checkout.cart.01 --title "Adding an item raises the count" \
|
|
97
|
-
--subject checkout-core --lane behavior --case happy
|
|
99
|
+
--subject checkout-core --lane behavior --case happy
|
|
100
|
+
# and its failure path
|
|
98
101
|
canon scenario new checkout.cart.04 --title "Adding an out-of-stock item is refused" \
|
|
99
|
-
--subject checkout-core --lane behavior --case failure
|
|
102
|
+
--subject checkout-core --lane behavior --case failure
|
|
100
103
|
```
|
|
101
104
|
|
|
102
105
|
There is no format or sync step after these: the scaffold writes a
|
|
@@ -111,8 +114,8 @@ Fix it and the next command indexes the files (see `canon-inventory`).
|
|
|
111
114
|
Many scenarios at once: `--input` takes inline JSON, a file or `-`. An
|
|
112
115
|
array (or NDJSON) is a batch, validated whole before anything is written;
|
|
113
116
|
each element holds `operands` (the scenario tag) and the other options as
|
|
114
|
-
camelCase keys. `canon schema scenario new --json` shows the
|
|
115
|
-
and
|
|
117
|
+
camelCase keys. `canon schema scenario new --json` shows `input`: the schema of one document
|
|
118
|
+
and a complete `example`. There is no `--from`.
|
|
116
119
|
|
|
117
120
|
```text
|
|
118
121
|
canon scenario new --input '[{"operands":["checkout.cart.01"],"title":"Adding an item raises the count","subject":"checkout-core","lane":"behavior","case":"happy"},{"operands":["checkout.cart.04"],"title":"Adding an out-of-stock item is refused","subject":"checkout-core","lane":"behavior","case":"failure"}]'
|
|
@@ -13,9 +13,12 @@ deterministic authoring surface.
|
|
|
13
13
|
## `canon context [--repo <dir>] [--json]`
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
|
-
|
|
17
|
-
canon context
|
|
18
|
-
|
|
16
|
+
# compact human outline (prompt-injectable)
|
|
17
|
+
canon context
|
|
18
|
+
# the full machine-readable surface
|
|
19
|
+
canon context --json
|
|
20
|
+
# resolve a specific repo's surface
|
|
21
|
+
canon context --repo ../other
|
|
19
22
|
```
|
|
20
23
|
|
|
21
24
|
The outline opens with a short header, then a blank line, then the
|
|
@@ -34,8 +37,8 @@ authored; `canon status` (see `canon-subject`) says where the repo stands
|
|
|
34
37
|
and what to run next. `--json` prints the `{ok, data, meta}` envelope: the
|
|
35
38
|
header adds no field, and `policy.spec_coverage`/`policy.diagnostics`
|
|
36
39
|
already carry the same fact. `--fields <list>` keeps only the named
|
|
37
|
-
top-level fields (`kinds`, `enums`, `policy`, `review`, …); an unknown name is
|
|
38
|
-
`USAGE` (exit 2; `field` is `--fields`, `expected` lists the selectable fields).
|
|
40
|
+
top-level fields (`kinds`, `enums`, `policy`, `review`, …), spelled as the report spells them; an unknown name is
|
|
41
|
+
`USAGE` (exit 2; `field` is `--fields`, `expected` lists the selectable fields), and `meta.fields` lists the kept ones.
|
|
39
42
|
|
|
40
43
|
On a repository that still holds 0.27 canon state, `canon context` warns
|
|
41
44
|
and puts `canon migrate --json` first in `meta.next`: run `canon migrate`
|
|
@@ -9,7 +9,8 @@ rewrites or mutates the corpus — it only validates and reports.
|
|
|
9
9
|
## Running
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
|
|
12
|
+
# e.g. a consumer repo's spec/
|
|
13
|
+
canon format spec
|
|
13
14
|
```
|
|
14
15
|
|
|
15
16
|
With no operand, `canon format` validates every `specs.roots[]` entry of
|
|
@@ -42,8 +42,10 @@ corpus and runs them, printing every violation grouped by failure class.
|
|
|
42
42
|
when `--release` is passed.
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
|
-
|
|
46
|
-
canon gate check --repo .
|
|
45
|
+
# ordinary evaluation
|
|
46
|
+
canon gate check --repo .
|
|
47
|
+
# + trust-below-required
|
|
48
|
+
canon gate check --repo . --release
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
Exit `0` clean, `1` gate-red (any violation), `2` usage/load failure
|
|
@@ -314,8 +316,8 @@ check `canon status` and the ship guard use; see
|
|
|
314
316
|
`--task`:
|
|
315
317
|
|
|
316
318
|
```stderr
|
|
317
|
-
canon evidence add: unreviewed-promotion demo-subject — evidence for world.demo.01: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line, so the human has not answered it; once they do, record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
|
|
318
|
-
canon evidence add: refused — stop and get the human's answer to the brief: nothing is built or attested for a subject before its brief is approved. Show it (`canon brief show --body`), ask with the harness question tool, and on their explicit approval record it with `canon brief approve --approver <their name> --note "<their words>" --relayed-via <the question tool> --actor <your actor id> --digest <change>=<the digest shown>` (or they approve on `canon dashboard`); never unset your role to run it; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
|
|
319
|
+
stderr: canon evidence add: unreviewed-promotion demo-subject — evidence for world.demo.01: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line, so the human has not answered it; once they do, record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
|
|
320
|
+
stderr: canon evidence add: refused — stop and get the human's answer to the brief: nothing is built or attested for a subject before its brief is approved. Show it (`canon brief show --body`), ask with the harness question tool, and on their explicit approval record it with `canon brief approve --approver <their name> --note "<their words>" --relayed-via <the question tool> --actor <your actor id> --digest <change>=<the digest shown>` (or they approve on `canon dashboard`); never unset your role to run it; to attest anyway, pass --override-reason <text>, which is recorded on the evidence record
|
|
319
321
|
```
|
|
320
322
|
|
|
321
323
|
For a change from an external plan with no canon brief yet, the first
|
|
@@ -534,7 +536,7 @@ or `-`; an array (or NDJSON) is a batch, validated element by element before
|
|
|
534
536
|
the first write (a refusal writes nothing, exit 2). Keys are the option
|
|
535
537
|
names in camelCase plus `operands`: one object per scenario, with
|
|
536
538
|
`scenario`, `class`, `ref` and `role`. `canon schema evidence add --json`
|
|
537
|
-
shows the
|
|
539
|
+
shows `input`: the schema of one document and a complete `example`. Each element reports `written`,
|
|
538
540
|
`unchanged` or `failed` in `data.items[]`.
|
|
539
541
|
|
|
540
542
|
`--rev <rev>` names the commit the evidence ran against (default `HEAD`).
|
|
@@ -553,7 +555,7 @@ current pinned review saw, `canon evidence add` prints one line per
|
|
|
553
555
|
review it makes stale (its verdict or checks differ from what the review saw), with the command that re-pins it:
|
|
554
556
|
|
|
555
557
|
```stderr
|
|
556
|
-
canon evidence add: review by `reviewer-2` of cart.add.01 is now stale (this record's verdict or checks differ from what it saw); re-pin it: canon review scenario cart.add.01 --project root --actor reviewer-2 --role reviewer --original-spec-ref specs/kind=feature/area=cart/add.feature
|
|
558
|
+
stderr: canon evidence add: review by `reviewer-2` of cart.add.01 is now stale (this record's verdict or checks differ from what it saw); re-pin it: canon review scenario cart.add.01 --project root --actor reviewer-2 --role reviewer --original-spec-ref specs/kind=feature/area=cart/add.feature
|
|
557
559
|
```
|
|
558
560
|
|
|
559
561
|
The decision is the gate's own (the same stale-review rule `canon gate
|
|
@@ -737,8 +739,10 @@ prints the plan (target path + assigned `run_seq` per candidate) without
|
|
|
737
739
|
writing or deleting.
|
|
738
740
|
|
|
739
741
|
```bash
|
|
740
|
-
|
|
741
|
-
canon gate promote --repo .
|
|
742
|
+
# land every staged candidate
|
|
743
|
+
canon gate promote --repo .
|
|
744
|
+
# preview only
|
|
745
|
+
canon gate promote --repo . --dry-run
|
|
742
746
|
```
|
|
743
747
|
|
|
744
748
|
Which writes need this step: `evidence add`, `finding add` and `finding
|
|
@@ -14,7 +14,7 @@ same code this command runs, scoped to the changed files, and say so in one
|
|
|
14
14
|
stderr line:
|
|
15
15
|
|
|
16
16
|
```stderr
|
|
17
|
-
canon artifacts store: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
|
|
17
|
+
stderr: canon artifacts store: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
|
|
18
18
|
```
|
|
19
19
|
|
|
20
20
|
`canon status` and `canon gate check` are read commands and write nothing:
|
|
@@ -76,14 +76,14 @@ author .feature corpus (canon scenario new)
|
|
|
76
76
|
scenario index # refreshed by the writers; `canon inventory sync` rebuilds it
|
|
77
77
|
│
|
|
78
78
|
▼
|
|
79
|
-
canon review scenario # attests a review — see canon-inventory downstream / canon-gate
|
|
80
|
-
canon divergence add|resolve|defer|accept|list # tracks/resolves a divergence
|
|
81
|
-
canon gate check [--release] # trust-ladder / staleness / coverage — see canon-gate
|
|
79
|
+
review: canon review scenario # attests a review — see canon-inventory downstream / canon-gate
|
|
80
|
+
diverge: canon divergence add|resolve|defer|accept|list # tracks/resolves a divergence
|
|
81
|
+
gate: canon gate check [--release] # trust-ladder / staleness / coverage — see canon-gate
|
|
82
82
|
│
|
|
83
83
|
▼
|
|
84
|
-
canon ingest records # with artifacts.native_records: true in canon.yaml —
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
ingest: canon ingest records # with artifacts.native_records: true in canon.yaml —
|
|
85
|
+
# feeds review/divergence verdicts into the flywheel
|
|
86
|
+
# (see canon-artifact-ingest)
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
Every stage after the index joins on the SAME `(project_id, scenario_id)`
|
|
@@ -92,9 +92,12 @@ pair it materializes — one identity scheme, no second one.
|
|
|
92
92
|
## `canon inventory sync [--repo <dir>] [--spec-root <dir>]`
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
|
|
96
|
-
canon inventory sync
|
|
97
|
-
|
|
95
|
+
# every canon.yaml specs.roots[] entry
|
|
96
|
+
canon inventory sync
|
|
97
|
+
# a specific repo
|
|
98
|
+
canon inventory sync --repo ../svc
|
|
99
|
+
# ad hoc: ignore canon.yaml entirely
|
|
100
|
+
canon inventory sync --spec-root ./specs
|
|
98
101
|
```
|
|
99
102
|
|
|
100
103
|
Per configured root, in order:
|
|
@@ -64,9 +64,12 @@ canon ingest plans --dialect openspec --plan-source ../other-repo
|
|
|
64
64
|
## 2. Run the import
|
|
65
65
|
|
|
66
66
|
```bash
|
|
67
|
-
|
|
68
|
-
canon ingest plans
|
|
69
|
-
|
|
67
|
+
# .canon/changes/ + every configured source
|
|
68
|
+
canon ingest plans
|
|
69
|
+
# machine-readable outcome
|
|
70
|
+
canon ingest plans --json
|
|
71
|
+
# a specific repo root
|
|
72
|
+
canon ingest plans --repo ../svc
|
|
70
73
|
```
|
|
71
74
|
|
|
72
75
|
Per source the summary reports `changes_parsed`/`tasks_parsed`,
|
|
@@ -49,9 +49,12 @@ overlays:
|
|
|
49
49
|
Drive it through the sync command (never hand-write records):
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
|
|
53
|
-
canon plugin sync porting
|
|
54
|
-
|
|
52
|
+
# every canon.yaml specs.roots[] entry
|
|
53
|
+
canon plugin sync porting
|
|
54
|
+
# a specific repo
|
|
55
|
+
canon plugin sync porting --repo ../svc
|
|
56
|
+
# ad hoc: ignore canon.yaml
|
|
57
|
+
canon plugin sync porting --spec-root ./specs
|
|
55
58
|
```
|
|
56
59
|
|
|
57
60
|
`canon plugin sync <plugin-id>` resolves the manifest, then for each
|
|
@@ -70,9 +73,12 @@ error; the next step (3) reads the overlay back.
|
|
|
70
73
|
## 3. Project a read
|
|
71
74
|
|
|
72
75
|
```bash
|
|
73
|
-
|
|
74
|
-
canon query --kind scenario --plugin porting
|
|
75
|
-
|
|
76
|
+
# human table, projected fields appended
|
|
77
|
+
canon query --kind scenario --plugin porting
|
|
78
|
+
# merged record bodies
|
|
79
|
+
canon query --kind scenario --plugin porting --json
|
|
80
|
+
# no --plugin: byte-identical to the core view
|
|
81
|
+
canon query --kind scenario
|
|
76
82
|
```
|
|
77
83
|
|
|
78
84
|
`--plugin <id>` folds the plugin's overlay records (latest-by-
|
|
@@ -40,7 +40,8 @@ Renders the current ten-panel report to `<repo>/.canon/REPORT.md`.
|
|
|
40
40
|
subcommand uses — omit it (or pass `.`) to run from any subdirectory.
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
|
|
43
|
+
# writes .canon/REPORT.md
|
|
44
|
+
canon report build
|
|
44
45
|
canon report build --repo /path/to/repo
|
|
45
46
|
```
|
|
46
47
|
|
|
@@ -67,7 +68,8 @@ committed `.canon/REPORT.md`:
|
|
|
67
68
|
`canon report build`).
|
|
68
69
|
|
|
69
70
|
```bash
|
|
70
|
-
|
|
71
|
+
# wire into CI exactly like canon format / canon gate check
|
|
72
|
+
canon report check
|
|
71
73
|
```
|
|
72
74
|
|
|
73
75
|
Wire it as a CI step or pre-push hook the same way `canon gate
|
|
@@ -126,7 +128,8 @@ canon report snapshot /tmp/canon-snap
|
|
|
126
128
|
Serves the dashboard web app locally, pointed at a real snapshot:
|
|
127
129
|
|
|
128
130
|
```bash
|
|
129
|
-
|
|
131
|
+
# regenerates a fresh snapshot every run, serves it
|
|
132
|
+
canon dashboard
|
|
130
133
|
canon dashboard --snapshot /tmp/canon-snap --port 8080
|
|
131
134
|
```
|
|
132
135
|
|
|
@@ -121,7 +121,7 @@ Outside git, or in a repository with no commit, the write is refused with
|
|
|
121
121
|
Many findings at once: `--input` takes inline JSON, a file or `-`; an array
|
|
122
122
|
(or NDJSON) is a batch validated before any write. Keys are the option
|
|
123
123
|
names in camelCase (`change`, `actor`, `resolutionRev`); `canon schema
|
|
124
|
-
finding add --json` shows the
|
|
124
|
+
finding add --json` shows `input`: the schema of one document and a complete `example`. An identical
|
|
125
125
|
repeat is `unchanged` (`data.unchanged`) and writes nothing; a different
|
|
126
126
|
finding under an occupied key is `FINDING_SEQ_OCCUPIED`.
|
|
127
127
|
|
|
@@ -468,7 +468,7 @@ With `require_review` present, `canon subject move <id> --to <state>`
|
|
|
468
468
|
prints on stderr which review checks it ran or skipped:
|
|
469
469
|
|
|
470
470
|
```stderr
|
|
471
|
-
canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
|
|
471
|
+
stderr: canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
|
|
472
472
|
ran unreviewed-promotion — every owned scenario needs a signed review, current with the spec and evidence it pinned, by an actor, and from a session, other than its evidence's
|
|
473
473
|
ran open-blocker — 1 adopted change(s) checked for open blocker findings
|
|
474
474
|
```
|
|
@@ -18,11 +18,16 @@ concurrency outgrows sqlite's single-writer mode.
|
|
|
18
18
|
## `canon ingest sessions [--watch] [--interval-secs N] [--home <dir>] [--full] [--all-workspaces]`
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
|
-
|
|
22
|
-
canon ingest sessions
|
|
23
|
-
|
|
24
|
-
canon ingest sessions --
|
|
25
|
-
|
|
21
|
+
# one pass over this project's sources
|
|
22
|
+
canon ingest sessions
|
|
23
|
+
# poll every 30s (see --interval-secs)
|
|
24
|
+
canon ingest sessions --watch
|
|
25
|
+
# ignore the watermark; re-parse every in-scope file
|
|
26
|
+
canon ingest sessions --full
|
|
27
|
+
# machine-wide scan
|
|
28
|
+
canon ingest sessions --all-workspaces
|
|
29
|
+
# override the scan-root home ($HOME)
|
|
30
|
+
canon ingest sessions --home /custom
|
|
26
31
|
```
|
|
27
32
|
|
|
28
33
|
**Done when:** the run summary (below) ends with `malformed records … : 0`
|
|
@@ -175,7 +180,8 @@ These events interleave with `token_usage` events in one deterministic
|
|
|
175
180
|
order (directive-before-token on a timestamp tie). Query them with:
|
|
176
181
|
|
|
177
182
|
```bash
|
|
178
|
-
|
|
183
|
+
# filter detail.label == "user_directive"
|
|
184
|
+
canon query --kind event
|
|
179
185
|
```
|
|
180
186
|
|
|
181
187
|
## Reading the run summary
|
|
@@ -104,10 +104,12 @@ canon query --kind handoff --since 2026-06-01T00:00:00Z
|
|
|
104
104
|
canon query --kind trajectory --json
|
|
105
105
|
|
|
106
106
|
# Page a long result and keep only the fields you need; `meta` carries
|
|
107
|
-
# `page` = {returned, total, nextCursor}; a present `nextCursor` means more, and
|
|
108
|
-
# `meta.next` repeats the call with `--cursor
|
|
107
|
+
# `page` = {returned, total, nextCursor} and `fields` = the paths kept; a present `nextCursor` means more, and
|
|
108
|
+
# `meta.next` repeats the call's explicit arguments with `--cursor=<nextCursor>` (`--all` returns everything). A cursor is bound to the
|
|
109
|
+
# call that issued it, `CANON_ROLE` included: change only `--limit`, `--all`, `--fields` or `--json`; any other change is `CURSOR_INVALID`
|
|
110
|
+
# (`error.reason` `ARGUMENTS_CHANGED`; `FOREIGN` for a cursor an older canon issued: start from the first page). A field path is the record's own key, written as it is.
|
|
109
111
|
canon query --kind trajectory --json --limit 50 --fields at,kind
|
|
110
|
-
canon query --kind trajectory --json --limit 50 --cursor <nextCursor>
|
|
112
|
+
canon query --kind trajectory --json --limit 50 --fields at,kind --cursor <nextCursor>
|
|
111
113
|
```
|
|
112
114
|
|
|
113
115
|
## The ledger is latest-only; the archive holds history
|
|
@@ -120,9 +122,12 @@ file names, tracked in git. `status`, the gate, the guards and `canon query`
|
|
|
120
122
|
read the ledger only.
|
|
121
123
|
|
|
122
124
|
```bash
|
|
123
|
-
|
|
124
|
-
canon
|
|
125
|
-
|
|
125
|
+
# every version, archive included
|
|
126
|
+
canon query --kind evidence --history
|
|
127
|
+
# preview; writes nothing
|
|
128
|
+
canon ledger compact
|
|
129
|
+
# pre-0.23 ledger or interrupted move; idempotent; `canon migrate` runs it
|
|
130
|
+
canon ledger compact --commit --plan-digest "$PLAN_DIGEST"
|
|
126
131
|
```
|
|
127
132
|
|
|
128
133
|
A crash between the write and the move leaves a readable ledger that the next
|
|
@@ -285,10 +290,10 @@ skills:
|
|
|
285
290
|
providers: [claude, codex] # any of claude, codex, omp, pi; [] for none
|
|
286
291
|
```
|
|
287
292
|
|
|
288
|
-
`canon init` writes it
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
293
|
+
`canon init` writes it and never asks: `--providers a,b` (or `none`) is the
|
|
294
|
+
answer; without it init takes the harnesses whose
|
|
295
|
+
`.claude`, `.codex`, `.omp` or `.pi` directory exists, and with none detected
|
|
296
|
+
it writes only a commented example
|
|
292
297
|
and installs nothing. `.agents` alone never selects Codex. `canon skills
|
|
293
298
|
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_DRIFT`) naming each orphan and `doctor` prints `orphan:` lines; `canon skills install
|
|
294
299
|
--providers=<list>` rewrites it in place. Without the section they use the
|
|
@@ -309,17 +314,22 @@ or when the index holds a scenario of a spec root that no `.feature` file
|
|
|
309
314
|
of it declares any more.
|
|
310
315
|
|
|
311
316
|
The commands that write records (`canon subject move`, `canon review
|
|
312
|
-
scenario`, `canon evidence add` and `canon artifacts store`) rebuild a stale index on disk
|
|
317
|
+
scenario`, `canon evidence add` and `canon artifacts store`) rebuild a stale index on disk, once nothing
|
|
318
|
+
refuses the call (a refused call writes nothing, whatever the index; until then they read the index as the
|
|
319
|
+
refresh would leave it, in memory): they
|
|
313
320
|
run `canon inventory sync`'s code on the changed files (validation still
|
|
314
|
-
covers the whole root) and print one stderr line
|
|
321
|
+
covers the whole root) and print one stderr line (in JSON mode the line is a `meta.warnings` entry,
|
|
322
|
+
never a line on stderr):
|
|
315
323
|
|
|
316
324
|
```stderr
|
|
317
|
-
canon artifacts store: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
|
|
325
|
+
stderr: canon artifacts store: refreshed the scenario index from 1 changed feature file(s) (.canon/specs/kind=feature/area=cart/add.feature): 1 record(s) written
|
|
318
326
|
```
|
|
319
327
|
|
|
320
328
|
The commands that only read (`canon gate check`, `canon status`) write
|
|
321
329
|
nothing: they grade a stale index as the refresh would leave it, built in
|
|
322
|
-
memory, and print no refresh line. `canon
|
|
330
|
+
memory, and print no refresh line. `canon subject show` is the one read
|
|
331
|
+
command that declares the refresh, as a cache effect (its `effectNote`), after the subject is found.
|
|
332
|
+
`canon query --kind scenario` and the
|
|
323
333
|
report panels read the index on disk as it is.
|
|
324
334
|
|
|
325
335
|
A deleted scenario is not erased: `canon inventory sync` — and a writer's
|
|
@@ -330,7 +340,7 @@ a live generation that supersedes the tombstone. A root that fails to
|
|
|
330
340
|
sync writes no tombstone either.
|
|
331
341
|
|
|
332
342
|
```stderr
|
|
333
|
-
canon artifacts store: refreshed the scenario index from 1 scenario(s) no longer in any feature file (cart.pay.01): 1 record(s) written
|
|
343
|
+
stderr: canon artifacts store: refreshed the scenario index from 1 scenario(s) no longer in any feature file (cart.pay.01): 1 record(s) written
|
|
334
344
|
```
|
|
335
345
|
|
|
336
346
|
`canon inventory sync` and every refresh hold an OS file lock on
|
|
@@ -348,7 +358,7 @@ the `verifying → shipped` guard refuses, and `canon status` lists only
|
|
|
348
358
|
`canon inventory sync`:
|
|
349
359
|
|
|
350
360
|
```stderr
|
|
351
|
-
canon artifacts store: found the scenario index stale for 1 changed feature file(s) (…): 0 record(s) written; NOT refreshed: root `root` (2 format violation(s), 0 sync error(s)) — `canon inventory sync` lists them
|
|
361
|
+
stderr: canon artifacts store: found the scenario index stale for 1 changed feature file(s) (…): 0 record(s) written; NOT refreshed: root `root` (2 format violation(s), 0 sync error(s)) — `canon inventory sync` lists them
|
|
352
362
|
```
|
|
353
363
|
|
|
354
364
|
Nothing is written in a directory without `canon.yaml`. `canon inventory
|
|
@@ -368,6 +378,26 @@ released when its holder exits, however it exits, so it never goes stale;
|
|
|
368
378
|
a writer gives up after 30 s with a message naming the file and saying to
|
|
369
379
|
retry (the command exits `2` and writes no record).
|
|
370
380
|
|
|
381
|
+
## The repository write lock
|
|
382
|
+
|
|
383
|
+
A committed destructive command (`canon purge`, `canon tier age`, `canon ledger
|
|
384
|
+
compact`, `canon artifacts move`, `canon migrate`) recomputes its plan, checks
|
|
385
|
+
its digest and then makes the effects, and nothing may change the plan in
|
|
386
|
+
between. It holds an OS file lock on `.canon/repo-write.lock` for the whole
|
|
387
|
+
span, from before it recomputes the plan to after its last effect; a preview
|
|
388
|
+
holds nothing. Every other command that writes what a plan reads (ledger
|
|
389
|
+
appends, the artifact store, briefs, specs, hooks, skill files, `canon.yaml`)
|
|
390
|
+
holds the same lock while it writes, so it waits for a commit and a commit
|
|
391
|
+
waits for it; reads, `--dry-run` runs and previews hold nothing. The lock is
|
|
392
|
+
the outermost one: it is taken before the scenario-index lock and the
|
|
393
|
+
artifact-store lock. It is released when its holder exits, however it exits,
|
|
394
|
+
so a killed commit never leaves it held, and the file is removed only by a
|
|
395
|
+
call that made it to take the lock and then ended refused (a refusal leaves
|
|
396
|
+
no file and no `.git/info/exclude` line behind). A
|
|
397
|
+
command that waited 30 s for it starts nothing: it exits `2` with
|
|
398
|
+
`REPO_WRITE_BUSY` (retryable; run it again in a moment). The first
|
|
399
|
+
call that needs the lock makes the file, in any repository.
|
|
400
|
+
|
|
371
401
|
## What `canon init` keeps out of git
|
|
372
402
|
|
|
373
403
|
A fresh `canon init` writes these lines to `.gitignore` (each under a
|
|
@@ -382,6 +412,8 @@ comment, only the missing ones):
|
|
|
382
412
|
- `.canon/scenario-index.lock` — the lock serializing index rebuilds.
|
|
383
413
|
- `.canon/artifact-store.lock` — the lock serializing artifact store
|
|
384
414
|
writes.
|
|
415
|
+
- `.canon/repo-write.lock` — the lock a committed destructive command and
|
|
416
|
+
every writer of what its plan reads hold.
|
|
385
417
|
- `.canon/dashboard-snapshot/` — the snapshot `canon dashboard`
|
|
386
418
|
regenerates on every run.
|
|
387
419
|
- `.canon/learn/` and `.canon/r2/` — local learn scratch and the local
|