@journeykit/canon 0.34.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 +22 -15
- package/dist/skills/reference/canon-artifact-ingest.md +6 -3
- package/dist/skills/reference/canon-authoring.md +6 -3
- package/dist/skills/reference/canon-context.md +6 -3
- package/dist/skills/reference/canon-fmt.md +2 -1
- package/dist/skills/reference/canon-gate.md +11 -7
- 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 +1 -1
- package/dist/skills/reference/canon-session-ingest.md +12 -6
- package/dist/skills/reference/canon-storage.md +46 -16
- package/dist/skills/reference/canon-subject.md +26 -17
- package/dist/skills/reference/role-implementer.md +29 -29
- package/dist/skills/reference/role-orchestrator.md +68 -63
- package/dist/skills/reference/role-planner.md +22 -22
- package/dist/skills/reference/role-reviewer.md +23 -23
- package/man/canon-adapter-authorize.1 +2 -2
- package/man/canon-adapter-validate.1 +2 -2
- package/man/canon-adapter.1 +2 -2
- package/man/canon-artifacts-move.1 +2 -2
- package/man/canon-artifacts-store.1 +2 -2
- package/man/canon-artifacts-verify.1 +2 -2
- package/man/canon-artifacts.1 +2 -2
- package/man/canon-brief-approve.1 +2 -2
- package/man/canon-brief-check.1 +2 -2
- package/man/canon-brief-show.1 +2 -2
- package/man/canon-brief.1 +2 -2
- package/man/canon-change-new.1 +2 -2
- package/man/canon-change.1 +2 -2
- package/man/canon-completion.1 +2 -2
- package/man/canon-context-pack-add.1 +2 -2
- package/man/canon-context-pack-show.1 +2 -2
- package/man/canon-context-pack-verify.1 +2 -2
- package/man/canon-context-pack.1 +2 -2
- package/man/canon-context.1 +2 -2
- package/man/canon-dashboard.1 +2 -2
- package/man/canon-demo-init.1 +2 -2
- package/man/canon-demo-review.1 +2 -2
- package/man/canon-demo.1 +2 -2
- package/man/canon-dispatch-begin.1 +2 -2
- package/man/canon-dispatch-diff.1 +2 -2
- package/man/canon-dispatch-end.1 +2 -2
- package/man/canon-dispatch.1 +2 -2
- package/man/canon-divergence-accept.1 +2 -2
- package/man/canon-divergence-add.1 +2 -2
- package/man/canon-divergence-defer.1 +2 -2
- package/man/canon-divergence-list.1 +2 -2
- package/man/canon-divergence-resolve.1 +2 -2
- package/man/canon-divergence.1 +2 -2
- package/man/canon-evidence-add.1 +2 -2
- package/man/canon-evidence-approval-payload.1 +2 -2
- package/man/canon-evidence-audit.1 +2 -2
- package/man/canon-evidence.1 +2 -2
- package/man/canon-export.1 +2 -2
- package/man/canon-feature-new.1 +2 -2
- package/man/canon-feature.1 +2 -2
- package/man/canon-finding-add.1 +2 -2
- package/man/canon-finding-close.1 +2 -2
- package/man/canon-finding-list.1 +2 -2
- package/man/canon-finding.1 +2 -2
- package/man/canon-format.1 +2 -2
- package/man/canon-gate-check.1 +2 -2
- package/man/canon-gate-install-hooks.1 +2 -2
- package/man/canon-gate-promote.1 +2 -2
- package/man/canon-gate.1 +2 -2
- package/man/canon-ingest-plans.1 +2 -2
- package/man/canon-ingest-records.1 +2 -2
- package/man/canon-ingest-sessions.1 +2 -2
- package/man/canon-ingest.1 +2 -2
- package/man/canon-init.1 +7 -7
- package/man/canon-inventory-sync.1 +2 -2
- package/man/canon-inventory.1 +2 -2
- package/man/canon-ledger-compact.1 +2 -2
- package/man/canon-ledger.1 +2 -2
- package/man/canon-migrate.1 +2 -2
- package/man/canon-plugin-sync.1 +2 -2
- package/man/canon-plugin.1 +2 -2
- package/man/canon-policy-approve.1 +2 -2
- package/man/canon-policy-show.1 +2 -2
- package/man/canon-policy.1 +2 -2
- package/man/canon-prompt-add.1 +2 -2
- package/man/canon-prompt-show.1 +2 -2
- package/man/canon-prompt.1 +2 -2
- package/man/canon-purge.1 +2 -2
- package/man/canon-query.1 +2 -2
- package/man/canon-regime-show.1 +2 -2
- package/man/canon-regime.1 +2 -2
- package/man/canon-report-build.1 +2 -2
- package/man/canon-report-check.1 +2 -2
- package/man/canon-report-snapshot.1 +2 -2
- package/man/canon-report.1 +2 -2
- package/man/canon-retrieve.1 +2 -2
- package/man/canon-review-change.1 +2 -2
- package/man/canon-review-scenario.1 +2 -2
- package/man/canon-review.1 +2 -2
- package/man/canon-scenario-new.1 +2 -2
- package/man/canon-scenario.1 +2 -2
- package/man/canon-schema.1 +2 -2
- package/man/canon-search.1 +2 -2
- package/man/canon-selftest.1 +2 -2
- package/man/canon-skills-check.1 +2 -2
- package/man/canon-skills-doctor.1 +2 -2
- package/man/canon-skills-install.1 +2 -2
- package/man/canon-skills-show.1 +5 -5
- package/man/canon-skills.1 +2 -2
- package/man/canon-status.1 +2 -2
- package/man/canon-strategy-approval-payload.1 +2 -2
- package/man/canon-strategy-promote.1 +2 -2
- package/man/canon-strategy-rollback.1 +2 -2
- package/man/canon-strategy.1 +2 -2
- package/man/canon-subject-adopt.1 +2 -2
- package/man/canon-subject-move.1 +2 -2
- package/man/canon-subject-new.1 +2 -2
- package/man/canon-subject-show.1 +2 -2
- package/man/canon-subject-unadopt.1 +2 -2
- package/man/canon-subject.1 +2 -2
- package/man/canon-task-done.1 +2 -2
- package/man/canon-task.1 +2 -2
- package/man/canon-tier-age.1 +2 -2
- package/man/canon-tier.1 +2 -2
- package/man/canon-trace.1 +2 -2
- package/man/canon.1 +2 -2
- package/package.json +4 -4
package/dist/skills/SKILL.src.md
CHANGED
|
@@ -221,20 +221,20 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
221
221
|
`{"ok":true,"data":…,"meta":…}`; failure is
|
|
222
222
|
`{"ok":false,"error":{…},"meta":…}` (a check that fails keeps its report in
|
|
223
223
|
`data`). `meta` carries `tool`, `toolVersion`, `contract` (`atip/1`),
|
|
224
|
-
`contractVersion` (`1.
|
|
224
|
+
`contractVersion` (`1.2`), `schemaVersion`,
|
|
225
225
|
`command`, and when present `next`, `warnings` (`[{code, message}]`) and
|
|
226
226
|
`page`; a repeated write that changed nothing reports `data.unchanged: true`.
|
|
227
227
|
Absent members are omitted, never `null` or `[]` (a value you sent empty comes back as `received: ""`).
|
|
228
228
|
Read the members you know and ignore the ones you do not: a later canon
|
|
229
229
|
adds members, and a value of a closed set you have not seen (a `severity`, an
|
|
230
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`
|
|
232
|
-
no `nextCursor` means no more.
|
|
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
233
|
On failure branch on `error.code`, and on `error.reason` where the code has
|
|
234
234
|
reasons (`INPUT_INVALID` says `NOT_JSON`, `UNKNOWN_KEY`, `STDIN_TTY`, … so you
|
|
235
235
|
know whether to fix the JSON or the shell); fix the option `error.field` names
|
|
236
236
|
using the `error.expected` values (`field` is an option name, or a JSON
|
|
237
|
-
pointer such as `/
|
|
237
|
+
pointer such as `/2/scenario` into an `--input` document, `/<index>/<key>` in a batch), and
|
|
238
238
|
follow `error.hint`: it is one runnable command line that starts with `canon`, the
|
|
239
239
|
same with `<PLACEHOLDER>`s you fill in, or one sentence. The codes
|
|
240
240
|
are stable; `canon schema --errors --json` lists them with their reasons and
|
|
@@ -258,7 +258,7 @@ A role is guidance, not enforcement: `--role` on `evidence add` and
|
|
|
258
258
|
has blockers; the approval step appears only when the brief is clean and
|
|
259
259
|
unapproved.
|
|
260
260
|
- Page long lists with `--limit <n>` and `--cursor <nextCursor>` (`--all`
|
|
261
|
-
for everything); a cursor holds only for the call that issued it, so change nothing but `--limit`, `--all` and `--
|
|
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
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.
|
|
263
263
|
- `--override-reason <text>` is the only way to proceed past a waivable
|
|
264
264
|
refusal; it is recorded, echoed in `data.overrides[]` and listed by `status`
|
|
@@ -277,10 +277,11 @@ the positional arguments. An object is one invocation; a JSON array (or NDJSON
|
|
|
277
277
|
from a file or stdin) is a batch, run in order and answered with
|
|
278
278
|
`data.items[]` (`index`, `status` of `written`, `unchanged`, `failed` or
|
|
279
279
|
`skipped`, and that element's `data` or `error`). A batch is validated whole
|
|
280
|
-
before anything is written: an invalid element writes nothing and exits 2
|
|
281
|
-
`error.field` pointing at
|
|
282
|
-
|
|
283
|
-
`
|
|
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`.
|
|
284
285
|
`canon schema <command> --json` shows the leaf's `input`: the schema of one document and a complete `example`.
|
|
285
286
|
|
|
286
287
|
```text
|
|
@@ -329,12 +330,18 @@ and `canon context` warn when the repo holds 0.27-era state and put
|
|
|
329
330
|
## Setup and provider projection
|
|
330
331
|
|
|
331
332
|
```bash
|
|
332
|
-
|
|
333
|
-
canon init
|
|
334
|
-
|
|
335
|
-
canon
|
|
336
|
-
canon skills
|
|
337
|
-
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
|
|
338
345
|
```
|
|
339
346
|
|
|
340
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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
|
|
@@ -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
|
|
@@ -105,9 +105,9 @@ canon query --kind trajectory --json
|
|
|
105
105
|
|
|
106
106
|
# Page a long result and keep only the fields you need; `meta` carries
|
|
107
107
|
# `page` = {returned, total, nextCursor} and `fields` = the paths kept; a present `nextCursor` means more, and
|
|
108
|
-
# `meta.next` repeats the call with `--cursor
|
|
109
|
-
# call that issued it: change only `--limit`, `--all` or `--
|
|
110
|
-
# (`error.reason` `ARGUMENTS_CHANGED`). A field path is the record's own key, written as it is.
|
|
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.
|
|
111
111
|
canon query --kind trajectory --json --limit 50 --fields at,kind
|
|
112
112
|
canon query --kind trajectory --json --limit 50 --fields at,kind --cursor <nextCursor>
|
|
113
113
|
```
|
|
@@ -122,9 +122,12 @@ file names, tracked in git. `status`, the gate, the guards and `canon query`
|
|
|
122
122
|
read the ledger only.
|
|
123
123
|
|
|
124
124
|
```bash
|
|
125
|
-
|
|
126
|
-
canon
|
|
127
|
-
|
|
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"
|
|
128
131
|
```
|
|
129
132
|
|
|
130
133
|
A crash between the write and the move leaves a readable ledger that the next
|
|
@@ -287,10 +290,10 @@ skills:
|
|
|
287
290
|
providers: [claude, codex] # any of claude, codex, omp, pi; [] for none
|
|
288
291
|
```
|
|
289
292
|
|
|
290
|
-
`canon init` writes it
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
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
|
|
294
297
|
and installs nothing. `.agents` alone never selects Codex. `canon skills
|
|
295
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
|
|
296
299
|
--providers=<list>` rewrites it in place. Without the section they use the
|
|
@@ -311,17 +314,22 @@ or when the index holds a scenario of a spec root that no `.feature` file
|
|
|
311
314
|
of it declares any more.
|
|
312
315
|
|
|
313
316
|
The commands that write records (`canon subject move`, `canon review
|
|
314
|
-
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
|
|
315
320
|
run `canon inventory sync`'s code on the changed files (validation still
|
|
316
|
-
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):
|
|
317
323
|
|
|
318
324
|
```stderr
|
|
319
|
-
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
|
|
320
326
|
```
|
|
321
327
|
|
|
322
328
|
The commands that only read (`canon gate check`, `canon status`) write
|
|
323
329
|
nothing: they grade a stale index as the refresh would leave it, built in
|
|
324
|
-
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
|
|
325
333
|
report panels read the index on disk as it is.
|
|
326
334
|
|
|
327
335
|
A deleted scenario is not erased: `canon inventory sync` — and a writer's
|
|
@@ -332,7 +340,7 @@ a live generation that supersedes the tombstone. A root that fails to
|
|
|
332
340
|
sync writes no tombstone either.
|
|
333
341
|
|
|
334
342
|
```stderr
|
|
335
|
-
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
|
|
336
344
|
```
|
|
337
345
|
|
|
338
346
|
`canon inventory sync` and every refresh hold an OS file lock on
|
|
@@ -350,7 +358,7 @@ the `verifying → shipped` guard refuses, and `canon status` lists only
|
|
|
350
358
|
`canon inventory sync`:
|
|
351
359
|
|
|
352
360
|
```stderr
|
|
353
|
-
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
|
|
354
362
|
```
|
|
355
363
|
|
|
356
364
|
Nothing is written in a directory without `canon.yaml`. `canon inventory
|
|
@@ -370,6 +378,26 @@ released when its holder exits, however it exits, so it never goes stale;
|
|
|
370
378
|
a writer gives up after 30 s with a message naming the file and saying to
|
|
371
379
|
retry (the command exits `2` and writes no record).
|
|
372
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
|
+
|
|
373
401
|
## What `canon init` keeps out of git
|
|
374
402
|
|
|
375
403
|
A fresh `canon init` writes these lines to `.gitignore` (each under a
|
|
@@ -384,6 +412,8 @@ comment, only the missing ones):
|
|
|
384
412
|
- `.canon/scenario-index.lock` — the lock serializing index rebuilds.
|
|
385
413
|
- `.canon/artifact-store.lock` — the lock serializing artifact store
|
|
386
414
|
writes.
|
|
415
|
+
- `.canon/repo-write.lock` — the lock a committed destructive command and
|
|
416
|
+
every writer of what its plan reads hold.
|
|
387
417
|
- `.canon/dashboard-snapshot/` — the snapshot `canon dashboard`
|
|
388
418
|
regenerates on every run.
|
|
389
419
|
- `.canon/learn/` and `.canon/r2/` — local learn scratch and the local
|
|
@@ -40,7 +40,8 @@ Write (or update) the Subject before touching anything else, so every
|
|
|
40
40
|
downstream artifact has a `subject_id` to pin to.
|
|
41
41
|
|
|
42
42
|
```bash
|
|
43
|
-
|
|
43
|
+
# record kinds, enum domains, policy requirements
|
|
44
|
+
canon context --repo .
|
|
44
45
|
canon subject new subject-domain-loop \
|
|
45
46
|
--domain dev --title "Subject domain loop" \
|
|
46
47
|
--summary "The durable product unit + its per-domain loop" \
|
|
@@ -130,7 +131,8 @@ from anywhere). Any other transition is rejected by failure class, exits
|
|
|
130
131
|
canon subject move subject-domain-loop --to specced
|
|
131
132
|
canon subject move subject-domain-loop --to building
|
|
132
133
|
canon subject move subject-domain-loop --to verifying
|
|
133
|
-
|
|
134
|
+
# gated — see below
|
|
135
|
+
canon subject move subject-domain-loop --to shipped
|
|
134
136
|
```
|
|
135
137
|
|
|
136
138
|
On success the status updates in place; `--json` prints the updated
|
|
@@ -182,8 +184,8 @@ a policy. The refusal is an `unreviewed-promotion` naming the subject, and
|
|
|
182
184
|
says what to do:
|
|
183
185
|
|
|
184
186
|
```output
|
|
185
|
-
canon subject move: SUBJECT_GATE_VIOLATION — unreviewed-promotion demo-subject — verifying → shipped: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line; a human must answer the brief, and only from that answer the agent will record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
|
|
186
|
-
canon subject move: refused — get the human's answer to the brief and record it with `canon brief approve`, or pass --override-reason <text> to move anyway; the waiver is recorded on the subject
|
|
187
|
+
output: canon subject move: SUBJECT_GATE_VIOLATION — unreviewed-promotion demo-subject — verifying → shipped: brief not approved — .canon/changes/c-demo/brief.md has no `Approved:` line; a human must answer the brief, and only from that answer the agent will record their words with `canon brief approve c-demo --approver <the human> --note "<their words>"`
|
|
188
|
+
output: canon subject move: refused — get the human's answer to the brief and record it with `canon brief approve`, or pass --override-reason <text> to move anyway; the waiver is recorded on the subject
|
|
187
189
|
```
|
|
188
190
|
|
|
189
191
|
For an external change with no canon brief yet, the reason reads
|
|
@@ -259,7 +261,7 @@ When `.canon/policy.yaml` sets `spec_coverage.require_review` (see
|
|
|
259
261
|
prints on stderr which it ran or skipped:
|
|
260
262
|
|
|
261
263
|
```output
|
|
262
|
-
canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
|
|
264
|
+
output: canon subject move: review guard for building → verifying (spec_coverage.require_review, scope: verifying, shipped)
|
|
263
265
|
ran unreviewed-promotion — every owned scenario needs a review by an actor, and from a session, other than its evidence's
|
|
264
266
|
ran open-blocker — 1 adopted change(s) checked for open blocker findings
|
|
265
267
|
```
|
|
@@ -316,8 +318,8 @@ canon subject move demo-subject --to verifying \
|
|
|
316
318
|
```
|
|
317
319
|
|
|
318
320
|
```output
|
|
319
|
-
canon subject move: reopened `demo-subject` from shipped, recorded by `impl`: follow-up: the retry path leaks a file handle; keep the follow-up in its approved change `c-demo`, then scenario, evidence and review; shipping again runs every guard
|
|
320
|
-
canon subject move: demo-subject → verifying — written directly; nothing to promote
|
|
321
|
+
output: canon subject move: reopened `demo-subject` from shipped, recorded by `impl`: follow-up: the retry path leaks a file handle; keep the follow-up in its approved change `c-demo`, then scenario, evidence and review; shipping again runs every guard
|
|
322
|
+
output: canon subject move: demo-subject → verifying — written directly; nothing to promote
|
|
321
323
|
```
|
|
322
324
|
|
|
323
325
|
- `--reason "<one line>"` is required for `shipped → verifying` (exit 2
|
|
@@ -353,9 +355,11 @@ Planning docs written outside canon become change/task records via
|
|
|
353
355
|
`canon subject adopt` lifts an imported change into a managed Subject:
|
|
354
356
|
|
|
355
357
|
```bash
|
|
356
|
-
|
|
358
|
+
# import → change/task rows
|
|
359
|
+
canon ingest plans --repo .
|
|
360
|
+
# link change → subject
|
|
357
361
|
canon subject adopt subject-domain-loop \
|
|
358
|
-
--change subject-domain-loop-plan
|
|
362
|
+
--change subject-domain-loop-plan
|
|
359
363
|
```
|
|
360
364
|
|
|
361
365
|
A change made with `canon change new` (below) is recorded and adopted
|
|
@@ -377,7 +381,7 @@ second subject adds that subject, never re-points the change, and says
|
|
|
377
381
|
so:
|
|
378
382
|
|
|
379
383
|
```output
|
|
380
|
-
canon subject adopt: linked change `refactor-core` to subject `editing` as well; the change now belongs to `perception` and `editing` — written directly; nothing to promote
|
|
384
|
+
output: canon subject adopt: linked change `refactor-core` to subject `editing` as well; the change now belongs to `perception` and `editing` — written directly; nothing to promote
|
|
381
385
|
```
|
|
382
386
|
|
|
383
387
|
Every reader joins a subject to its changes from both sides (the
|
|
@@ -434,8 +438,8 @@ canon change new add-login --subject auth --title "Add login"
|
|
|
434
438
|
```
|
|
435
439
|
|
|
436
440
|
```output
|
|
437
|
-
canon change new: wrote .canon/changes/add-login/brief.md
|
|
438
|
-
canon change new: recorded change `add-login` adopted into subject `auth` — written directly; nothing to promote
|
|
441
|
+
output: canon change new: wrote .canon/changes/add-login/brief.md
|
|
442
|
+
output: canon change new: recorded change `add-login` adopted into subject `auth` — written directly; nothing to promote
|
|
439
443
|
```
|
|
440
444
|
|
|
441
445
|
- **Writes** canon's own change dir, `.canon/changes/<slug>/`, holding
|
|
@@ -493,8 +497,10 @@ brief (`data.next`, `meta.next`).
|
|
|
493
497
|
### The brief: `canon brief show`, `canon brief check`, `canon brief approve`
|
|
494
498
|
|
|
495
499
|
```text
|
|
496
|
-
|
|
497
|
-
canon brief
|
|
500
|
+
# state and the next one to three steps; never edits
|
|
501
|
+
canon brief show [<slug>]
|
|
502
|
+
# findings; exit 0 clean, 2 blockers, 1 error
|
|
503
|
+
canon brief check [<slug>] [--json]
|
|
498
504
|
canon brief approve <slug> <slug> --approver <the human> --note "<their words>"
|
|
499
505
|
```
|
|
500
506
|
|
|
@@ -567,8 +573,10 @@ step that writes it.
|
|
|
567
573
|
## Where are we: `canon status`
|
|
568
574
|
|
|
569
575
|
```bash
|
|
570
|
-
|
|
571
|
-
canon status
|
|
576
|
+
# subjects by status, their gaps, next commands
|
|
577
|
+
canon status
|
|
578
|
+
# the same report, stable shape
|
|
579
|
+
canon status --json
|
|
572
580
|
canon status --repo ../other
|
|
573
581
|
```
|
|
574
582
|
|
|
@@ -818,7 +826,8 @@ and `canon gate check` exits `0`; read `data.subjects[]` for the counts and
|
|
|
818
826
|
|
|
819
827
|
```bash
|
|
820
828
|
canon query --kind subject --domain dev --status building
|
|
821
|
-
|
|
829
|
+
# renders the "Subjects" panel
|
|
830
|
+
canon report build --repo .
|
|
822
831
|
```
|
|
823
832
|
|
|
824
833
|
- `canon query --kind subject [--domain <d>] [--status <s>]` — the
|