@journeykit/canon 0.6.0 → 0.8.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/index.js +12 -2
- package/dist/skills/SKILL.src.md +46 -0
- package/dist/skills/reference/canon-artifact-ingest.md +72 -0
- package/dist/skills/reference/canon-authoring.md +155 -0
- package/dist/skills/reference/canon-context.md +137 -0
- package/dist/skills/reference/canon-fmt.md +43 -0
- package/dist/skills/reference/canon-gate.md +199 -0
- package/dist/skills/reference/canon-inventory.md +102 -0
- package/dist/skills/reference/canon-learn.md +245 -0
- package/dist/skills/reference/canon-plan-import.md +143 -0
- package/dist/skills/reference/canon-plugins.md +131 -0
- package/dist/skills/reference/canon-policy.md +119 -0
- package/dist/skills/reference/canon-report-dashboard.md +343 -0
- package/dist/skills/reference/canon-retrieve.md +123 -0
- package/dist/skills/reference/canon-session-ingest.md +214 -0
- package/dist/skills/reference/canon-storage.md +152 -0
- package/dist/skills/reference/canon-subject.md +161 -0
- package/dist/skills/reference/canon-vocab.md +115 -0
- package/dist/skills/scripts/canon-retrieve-pre-dispatch.sh +126 -0
- package/package.json +6 -4
package/dist/index.js
CHANGED
|
@@ -78,6 +78,11 @@ function resolveTargetPackageName() {
|
|
|
78
78
|
return "core-linux-x64";
|
|
79
79
|
return null;
|
|
80
80
|
}
|
|
81
|
+
if (process.platform === "win32") {
|
|
82
|
+
if (arch === "x64")
|
|
83
|
+
return "core-win32-x64";
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
81
86
|
return null;
|
|
82
87
|
}
|
|
83
88
|
function resolveRustTargetTriple() {
|
|
@@ -150,5 +155,10 @@ if (!binary) {
|
|
|
150
155
|
console.error(" build from source: cargo build --release -p canon-cli");
|
|
151
156
|
process.exit(1);
|
|
152
157
|
}
|
|
153
|
-
var
|
|
154
|
-
|
|
158
|
+
var bundledSkills = join(cliDir, "dist", "skills");
|
|
159
|
+
var checkoutSkills = join(workspaceRoot, "canon", "skills");
|
|
160
|
+
var skillsSource = existsSync(join(bundledSkills, "SKILL.src.md")) ? bundledSkills : checkoutSkills;
|
|
161
|
+
var result = spawnSync(binary, process.argv.slice(2), {
|
|
162
|
+
stdio: "inherit",
|
|
163
|
+
env: { ...process.env, CANON_SKILLS_SOURCE: skillsSource }
|
|
164
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: canon
|
|
3
|
+
description: The provider-neutral Canon companion skill for agents using the canon CLI. Routes setup, authoring, validation, storage, ingestion, learning, retrieval, reporting, and provider-specific lazy references.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Canon
|
|
7
|
+
|
|
8
|
+
Use this single skill when working with Canon in a consumer repository. Canon's CLI remains explicitly modular; choose the command that matches the operation rather than asking an implicit router to guess.
|
|
9
|
+
|
|
10
|
+
## Setup and provider projection
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
canon init
|
|
14
|
+
canon skills install # detects .claude/.codex/.omp/.pi; if none exists, installs Claude+Codex
|
|
15
|
+
canon skills install --providers=claude,codex,omp,pi
|
|
16
|
+
canon skills check # read-only drift check
|
|
17
|
+
canon skills doctor # diagnostics; never deletes user files
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The canonical bundle is read-only. Claude receives
|
|
21
|
+
`.claude/skills/canon/SKILL.md`; Codex receives the flattened
|
|
22
|
+
`.codex/skills/canon.md`; OMP receives `.omp/skills/canon/SKILL.md`; and Pi
|
|
23
|
+
receives `.pi/skills/canon/SKILL.md`. Every selected provider receives matching
|
|
24
|
+
`reference/**` and `scripts/**` sidecars under its `canon` bundle. OMP and Pi
|
|
25
|
+
projections are project-local passive skill bundles: the
|
|
26
|
+
`scripts/canon-retrieve-pre-dispatch.sh` file is available as a sidecar, not
|
|
27
|
+
installed as a native hook. Load only the reference needed for the current
|
|
28
|
+
task. `canon/skills-dev` is a separate developer-only legacy source and is
|
|
29
|
+
installed explicitly with `--source canon/skills-dev`.
|
|
30
|
+
|
|
31
|
+
## Route by task
|
|
32
|
+
|
|
33
|
+
- **Start product work / pin a durable unit:** read `reference/canon-subject.md`, then run `canon context` and `canon subject`.
|
|
34
|
+
- **Write or reorganize `.feature` specs:** read `reference/canon-authoring.md` before editing; use the scaffold.
|
|
35
|
+
- **Understand available fields/enums/policy bindings:** read `reference/canon-context.md` and `reference/canon-vocab.md`.
|
|
36
|
+
- **Capture replayable run inputs / version prompts:** read `reference/canon-context.md`, then use `canon context-pack create|show|verify` and `canon prompt register|show` with explicit repository-relative JSON manifests.
|
|
37
|
+
- **Validate or index specs:** read `reference/canon-fmt.md` and `reference/canon-inventory.md`.
|
|
38
|
+
- **Run evidence gates, flip tasks, install hooks:** read `reference/canon-gate.md`.
|
|
39
|
+
- **Ingest artifacts or sessions:** read `reference/canon-artifact-ingest.md`, `reference/canon-session-ingest.md`, or `reference/canon-plan-import.md`.
|
|
40
|
+
- **Configure storage, policy, plugins, or strategy learning:** read `reference/canon-storage.md`, `reference/canon-policy.md`, `reference/canon-plugins.md`, or `reference/canon-learn.md`.
|
|
41
|
+
- **Retrieve dispatch guidance:** read `reference/canon-retrieve.md` and load `scripts/canon-retrieve-pre-dispatch.sh` when wiring hooks.
|
|
42
|
+
- **Read generated reports and dashboards:** read `reference/canon-report-dashboard.md`.
|
|
43
|
+
|
|
44
|
+
## Safety contract
|
|
45
|
+
|
|
46
|
+
`canon format --check`, `canon skills check`, and `canon gate check` are read-only. Do not hand-edit generated reports, provenance lines, locks, or task evidence. Inspect `canon context` before authoring typed artifacts, and treat every failure class as actionable evidence rather than bypassing the gate.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# canon-artifact-ingest
|
|
2
|
+
|
|
3
|
+
`canon ingest artifacts` turns a repo's canon-native ARTIFACTS — the
|
|
4
|
+
outputs of review/divergence/task/handoff work — into the regime-keyed
|
|
5
|
+
verdict trajectories that strategy memory and the reward gate consume
|
|
6
|
+
(see `canon-learn`). One pass runs the four adapters, normalizes, derives
|
|
7
|
+
verdicts, and writes idempotently.
|
|
8
|
+
|
|
9
|
+
## `canon ingest artifacts [--repo <dir>] [--watch]`
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
canon ingest artifacts # one pass over the repo's artifacts
|
|
13
|
+
canon ingest artifacts --repo ../svc # a specific repo
|
|
14
|
+
canon ingest artifacts --watch # poll loop
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Source roots resolve from `canon.yaml`'s `artifacts.sources` config
|
|
18
|
+
(`openspec_root`, ledger/divergence/handoff roots) — generic, never a
|
|
19
|
+
hardcoded path; ordinarily the consumer repo's own roots. Unconfigured =
|
|
20
|
+
no scan for that family.
|
|
21
|
+
|
|
22
|
+
## The four adapters
|
|
23
|
+
|
|
24
|
+
Each reads one artifact family and emits a normalized event keyed by that
|
|
25
|
+
family's join key:
|
|
26
|
+
|
|
27
|
+
- **`divergence`** — parity/divergence reports → verdict keyed by the
|
|
28
|
+
lane derived from the report's on-disk path.
|
|
29
|
+
- **`ledger`** — review ledger records → verdict; the record's
|
|
30
|
+
trust-level tag (`@reviewed`/`@ratified`) rides through as a
|
|
31
|
+
passthrough `trust_level` field, not collapsed into one "success"
|
|
32
|
+
bucket. (The other three adapters carry no trust-level concept.)
|
|
33
|
+
- **`openspec_task`** — `tasks.md` checkbox rows: a `- [ ]` → `- [x] … —
|
|
34
|
+
✅ <evidence>` flip, or a `**DEFERRED**`/`**DROPPED**` rewrite, keyed by
|
|
35
|
+
`task_id` (`<change_id>#<n>`). The evidence string is parsed for a
|
|
36
|
+
mergeable PR / CI reference where present (CI-first).
|
|
37
|
+
- **`handoff`** — handoff transitions, keyed by `handoff_id`.
|
|
38
|
+
|
|
39
|
+
## Verdict derivation
|
|
40
|
+
|
|
41
|
+
Verdict derivation is a pure function from a normalized event to an
|
|
42
|
+
optional verdict `{role, polarity, becomes}`:
|
|
43
|
+
|
|
44
|
+
- A matched mapping row → a verdict for that role.
|
|
45
|
+
- No mapped row → NO verdict. A prose-only task flip, a deferred/dropped
|
|
46
|
+
task, or a handoff transition alone produces none — deliberate, not a
|
|
47
|
+
gap.
|
|
48
|
+
|
|
49
|
+
## Idempotence — a re-ingest is a no-op
|
|
50
|
+
|
|
51
|
+
Write-identity is content-digest based: the digest derives both the
|
|
52
|
+
`regime_key` `<hash>` segment and the trajectory write-identity. Before
|
|
53
|
+
writing, the driver does a regime-key existence check — a second ingest
|
|
54
|
+
over an unchanged corpus re-derives the identical id and persists zero
|
|
55
|
+
new trajectories (reported as `trajectories_skipped_duplicate`).
|
|
56
|
+
|
|
57
|
+
## Reading a role's own verdict stream
|
|
58
|
+
|
|
59
|
+
Verdicts persist regime-keyed (`<role>/<repo>/<area>/<hash>`), so a
|
|
60
|
+
role-scoped agent reads only its own lane — the same regime namespacing
|
|
61
|
+
`canon retrieve --role <r> --regime <k>` and `canon learn` query. This
|
|
62
|
+
verdict stream is the evidence the reward gate scores when deciding
|
|
63
|
+
promotion/demotion.
|
|
64
|
+
|
|
65
|
+
## What this skill does NOT cover
|
|
66
|
+
|
|
67
|
+
- Session/cost ingestion (`canon ingest sessions`) — a different
|
|
68
|
+
pipeline; see the `canon-session-ingest` skill.
|
|
69
|
+
- Strategy promotion/demotion mechanics — see the `canon-learn` skill;
|
|
70
|
+
this skill only produces the verdict evidence promotion reads.
|
|
71
|
+
- The `regime_key` grammar itself — see `canon-retrieve`, which derives
|
|
72
|
+
the same key via the `canon regime-key` serializer.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# canon-authoring
|
|
2
|
+
|
|
3
|
+
A `.feature` corpus is the join spine everything else in canon hangs
|
|
4
|
+
off: `canon inventory sync` indexes it, `canon review`/`canon evidence`
|
|
5
|
+
attest against it, `canon gate check` measures coverage over it. A
|
|
6
|
+
corpus that is organized badly does not fail `canon format` — it
|
|
7
|
+
produces a green gate that measures the wrong thing. This skill is the
|
|
8
|
+
organizing rule.
|
|
9
|
+
|
|
10
|
+
## Vocabulary
|
|
11
|
+
|
|
12
|
+
| Term | Is | Is NOT |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| **area** | One bounded context of the product, a kebab noun (`checkout`, `world-map`, `dm`). The directory `area=<area>/`. | A sprint, a team, a theme ("experience", "quality"). |
|
|
15
|
+
| **surface** | One screen, flow, or API a user or caller actually meets (`cart`, `place-lock`, `session-create`). Exactly ONE `.feature` file per surface. | A grab-bag ("misc", "experience", "review") — see anti-patterns. |
|
|
16
|
+
| **scenario** | One observable behavior of that surface: a refusal, a transition, a boundary, a derived value, an idempotence property. Readable by someone who has never seen the code. | A function name, an implementation step, a rule about a document or a report. |
|
|
17
|
+
| **`<area>.<surface>.<nn>`** | The scenario's durable id. Assigned once, never renumbered; gaps are fine. | A sort key you tidy up. |
|
|
18
|
+
|
|
19
|
+
A `Feature:` title names the surface. If you cannot name the surface,
|
|
20
|
+
you do not have one yet.
|
|
21
|
+
|
|
22
|
+
## Lanes: what kind of requirement is this?
|
|
23
|
+
|
|
24
|
+
Every scenario is one of a small set of lanes, tagged `@lane:<value>`:
|
|
25
|
+
|
|
26
|
+
| Lane | The scenario is about | Attested by |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `behavior` | What the product does — state, input, data, navigation, errors. The default. | A test or an observed run. |
|
|
29
|
+
| `design` | How it looks and moves — tokens, spacing, motion, easing. | A design review. |
|
|
30
|
+
| `architecture` | How the code is shaped — layering, ownership, error surfacing. | An architecture review. |
|
|
31
|
+
| `process` | How the TEAM works — what a review report may claim, how acceptance is run, what a build must check. | Nothing in the product. |
|
|
32
|
+
|
|
33
|
+
`process` rules are real, but they have no code surface and can never
|
|
34
|
+
be `faithful` from a test. Keep them out of the coverage number:
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
# .canon/policy.yaml
|
|
38
|
+
spec_coverage:
|
|
39
|
+
require_evidence: true
|
|
40
|
+
scope: [building, verifying]
|
|
41
|
+
exclude_lanes: [process]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The base set comes from `canon.core`; a repo declares its own `lane`
|
|
45
|
+
enum in `.canon/vocab/<id>/enums.yaml` to replace it (see
|
|
46
|
+
`canon-vocab`). `canon context` shows the set in force. A value outside
|
|
47
|
+
a declared set is refused at the scaffold and dropped, with a counted
|
|
48
|
+
diagnostic, at `canon inventory sync`.
|
|
49
|
+
|
|
50
|
+
**The test for a `behavior` scenario:** name the test or run that would
|
|
51
|
+
attest it. If you can't, it is a `process` rule, or it is a gap — record
|
|
52
|
+
the gap, do not write the scenario.
|
|
53
|
+
|
|
54
|
+
## Subject pinning
|
|
55
|
+
|
|
56
|
+
Every scenario belongs to a Subject (the durable product unit, see
|
|
57
|
+
`canon-subject`). Write the Subject first, then pin with `--subject`;
|
|
58
|
+
`canon inventory sync` carries the tag onto the index record and
|
|
59
|
+
`spec_coverage.scope` filters on it. An unpinned scenario is invisible to
|
|
60
|
+
a scoped gate.
|
|
61
|
+
|
|
62
|
+
## The commands — and the one thing you never type
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
canon feature new checkout.cart --title "Cart" # once per surface
|
|
66
|
+
canon scenario new checkout.cart.01 --title "Adding an item raises the count" \
|
|
67
|
+
--subject checkout-core --lane behavior # once per behavior
|
|
68
|
+
canon format specs # clean?
|
|
69
|
+
canon inventory sync # index it
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- `--actor <id>` (or `CANON_ACTOR` in the environment) puts YOUR id on the
|
|
73
|
+
provenance line. Default is `canon-scaffold`.
|
|
74
|
+
- **Never hand-type, move, or edit a `# canon:` line.** The scaffold
|
|
75
|
+
writes it directly above the scenario's tags:
|
|
76
|
+
|
|
77
|
+
```gherkin
|
|
78
|
+
# canon: {"schema":1,"at":"2026-09-16T10:02:11Z","actor":{"agent_id":"Main"}}
|
|
79
|
+
@subject:checkout-core
|
|
80
|
+
@lane:behavior
|
|
81
|
+
@checkout.cart.01
|
|
82
|
+
Scenario: Adding an item raises the count
|
|
83
|
+
Given an empty cart
|
|
84
|
+
When one item is added
|
|
85
|
+
Then the count reads 1
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A line directly UNDER the header (older corpora) is also accepted.
|
|
89
|
+
Anywhere else — separated by a blank line, above `Feature:` with
|
|
90
|
+
scenario tags in between — is `missing-provenance`, and the whole
|
|
91
|
+
root's sync aborts.
|
|
92
|
+
- Steps are yours to write; the scaffold's `Given a step` is a
|
|
93
|
+
placeholder, not a spec.
|
|
94
|
+
|
|
95
|
+
## Anti-patterns, by name
|
|
96
|
+
|
|
97
|
+
- **The grab-bag surface.** One `experience.feature` holding pointer
|
|
98
|
+
capture, i18n fallback, a compiler tag rule, and "the review report
|
|
99
|
+
must not claim video quality". Four surfaces and a process rule. Split
|
|
100
|
+
by what the user meets; move the rule to `lane:process`.
|
|
101
|
+
- **A Then about a document.** "Then the report distinguishes X from Y."
|
|
102
|
+
The product has no report. `lane:process`, or `policy.yaml`.
|
|
103
|
+
- **A Feature title that is a theme.** "Fidelity of the original
|
|
104
|
+
experience" names no surface. Name the screen.
|
|
105
|
+
- **Hand-stamped provenance.** Eighty lines with one timestamp and the
|
|
106
|
+
same `agent_id`. Use `canon scenario new --actor`.
|
|
107
|
+
- **Coverage by splitting.** One behavior as two scenarios so two rows go
|
|
108
|
+
green. One behavior, one id.
|
|
109
|
+
- **Runner tags as classification.** `@design`, `@p2`, `@wip` are
|
|
110
|
+
invisible to canon — they index nothing. Only `@lane:` and `@subject:`
|
|
111
|
+
are read; any other `@name:value` namespace is counted as a diagnostic
|
|
112
|
+
at sync so you can see it was dropped.
|
|
113
|
+
|
|
114
|
+
## Worked example
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
specs/features/kind=feature/area=checkout/
|
|
118
|
+
cart.feature # surface: the cart screen
|
|
119
|
+
payment.feature # surface: the payment step
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```gherkin
|
|
123
|
+
Feature: Cart
|
|
124
|
+
# canon: {"schema":1,"at":"2026-09-16T10:02:11Z","actor":{"agent_id":"Main"}}
|
|
125
|
+
|
|
126
|
+
# canon: {"schema":1,"at":"2026-09-16T10:02:11Z","actor":{"agent_id":"Main"}}
|
|
127
|
+
@subject:checkout-core
|
|
128
|
+
@lane:behavior
|
|
129
|
+
@checkout.cart.01
|
|
130
|
+
Scenario: Adding an item raises the count
|
|
131
|
+
Given an empty cart
|
|
132
|
+
When one item is added
|
|
133
|
+
Then the count reads 1
|
|
134
|
+
|
|
135
|
+
# canon: {"schema":1,"at":"2026-09-16T10:02:40Z","actor":{"agent_id":"Main"}}
|
|
136
|
+
@subject:checkout-core
|
|
137
|
+
@lane:design
|
|
138
|
+
@checkout.cart.02
|
|
139
|
+
Scenario: The count badge uses the accent token and a 120ms ease-out
|
|
140
|
+
Given a cart with one item
|
|
141
|
+
When a second item is added
|
|
142
|
+
Then the badge animates over 120ms with ease-out in the accent color
|
|
143
|
+
|
|
144
|
+
# canon: {"schema":1,"at":"2026-09-16T10:03:02Z","actor":{"agent_id":"Main"}}
|
|
145
|
+
@subject:checkout-core
|
|
146
|
+
@lane:process
|
|
147
|
+
@checkout.cart.03
|
|
148
|
+
Scenario: A cart review names the device it was run on
|
|
149
|
+
Given a cart design review
|
|
150
|
+
When the report is written
|
|
151
|
+
Then it names the device and OS the review ran on
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
`.03` is excluded from coverage by `exclude_lanes: [process]`; `.01` is
|
|
155
|
+
attested by a test, `.02` by a design review.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# canon-context
|
|
2
|
+
|
|
3
|
+
`canon context` is a capability QUERY over the same schema/policy/
|
|
4
|
+
vocabulary registry `canon format`/`canon gate` validate against — never
|
|
5
|
+
validation itself. It answers "what CAN I author in this repo, and how?":
|
|
6
|
+
record kinds + their envelope fields, enum domains, join-key grammars,
|
|
7
|
+
partition layout, policy-derived evidence requirements, the typed
|
|
8
|
+
authoring vocabulary, and the CEL binding surface — folded into one
|
|
9
|
+
deterministic authoring surface.
|
|
10
|
+
|
|
11
|
+
## `canon context [--repo <dir>] [--json]`
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
canon context # compact human outline (prompt-injectable)
|
|
15
|
+
canon context --json # the full machine-readable surface
|
|
16
|
+
canon context --repo ../other # resolve a specific repo's surface
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Reproducible context packs and prompt bundles
|
|
20
|
+
|
|
21
|
+
Use an explicit, repository-relative JSON manifest when a run needs a
|
|
22
|
+
replayable snapshot. The manifest selects files; Canon copies their bytes into
|
|
23
|
+
an immutable content-addressed registry and records only metadata and digests
|
|
24
|
+
in the pack manifest.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
canon context-pack create --manifest .canon/context-manifest.json
|
|
28
|
+
canon context-pack create --manifest .canon/context-manifest.json --repo ../my-repo --json
|
|
29
|
+
canon context-pack show sha256:<pack-digest> --repo . --json
|
|
30
|
+
canon context-pack verify sha256:<pack-digest>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`create` prints only the pack id by default, so captured content is never
|
|
34
|
+
written to concise terminal output. `--json` prints the pack manifest,
|
|
35
|
+
including selected-path metadata and content digests. `show` verifies the
|
|
36
|
+
manifest and immutable content objects before returning it; `verify` exits
|
|
37
|
+
nonzero when the pack is missing, stale, or tampered. Manifest paths must be
|
|
38
|
+
relative to the resolved repo, remain inside it, and contain no symlink;
|
|
39
|
+
missing or unsafe paths are rejected by the context-pack module.
|
|
40
|
+
|
|
41
|
+
## Provider-neutral adapter responses
|
|
42
|
+
|
|
43
|
+
An execution provider may return a versioned response envelope for Canon to
|
|
44
|
+
validate. Validation is read-only: `canon` never starts a provider, interprets
|
|
45
|
+
provider-specific extension payloads, or enforces declared capabilities.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
canon adapter validate --response response.json
|
|
49
|
+
canon adapter validate --response response.json --repo . --json
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The envelope has `protocol_version: 1`, required `run_id`, `provider`,
|
|
53
|
+
`model`, and `context_pack_id`, a closed status vocabulary
|
|
54
|
+
(`succeeded`/`failed`/`aborted`), and strict filesystem/network/secrets
|
|
55
|
+
capability vocabularies. Evidence references are safe, relative references
|
|
56
|
+
with `sha256:<64-hex>` digests. Telemetry timestamps must be RFC3339 with
|
|
57
|
+
`ended_at >= started_at`, and counts/cost are nonnegative.
|
|
58
|
+
|
|
59
|
+
Core fields are closed and unknown fields are rejected. Provider-specific JSON
|
|
60
|
+
belongs only under opaque `extensions`; successful JSON output contains the
|
|
61
|
+
normalized core summary and extension key names, never extension payloads.
|
|
62
|
+
`--repo` can verify the referenced context pack; file-only validation reports
|
|
63
|
+
`context_join_verified: null`. A valid declaration is not a sandbox:
|
|
64
|
+
providers MUST enforce filesystem, network, and secret capabilities before
|
|
65
|
+
execution.
|
|
66
|
+
|
|
67
|
+
Version prompt inputs separately when several runs should share the same
|
|
68
|
+
prompt files:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
canon prompt register --name reviewer --version v1 \
|
|
72
|
+
--manifest .canon/reviewer-prompt.json
|
|
73
|
+
canon prompt show --name reviewer --version v1 --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Prompt registration uses the same immutable content registry. `prompt show`
|
|
77
|
+
verifies the selected bundle and returns its metadata/digests; neither concise
|
|
78
|
+
output form includes captured prompt bytes.
|
|
79
|
+
|
|
80
|
+
- **A capability query, never validation:** `canon context` ALWAYS exits
|
|
81
|
+
`0` with the full surface — even when `canon format --check` or
|
|
82
|
+
`canon gate` would report diagnostics against the same repo. It reads
|
|
83
|
+
only the schema/policy/vocabulary registry, never the corpus or the
|
|
84
|
+
evidence ledger.
|
|
85
|
+
- `--repo` resolves through the same nearest-`canon.yaml`-ancestor walk
|
|
86
|
+
`canon format`/`canon gate`/`canon retrieve` use: omitted or `.` walks up
|
|
87
|
+
from cwd to the project root; any other explicit dir is used as-is.
|
|
88
|
+
- `--json` renders the full surface; the default renders a compact per-
|
|
89
|
+
section outline. Both project from the identical resolution (byte-stable
|
|
90
|
+
across runs).
|
|
91
|
+
|
|
92
|
+
## The surface sections
|
|
93
|
+
|
|
94
|
+
- **`kinds`** — each record kind's `{schema_version, envelope_fields,
|
|
95
|
+
partition}`.
|
|
96
|
+
- **`enums`** — each enum domain's members (verdicts, statuses, lanes,
|
|
97
|
+
roles, polarity, …).
|
|
98
|
+
- **`joinKeys`** — the join-spine grammar string per key (`regime_key`,
|
|
99
|
+
`session_id`, `task_id`, …).
|
|
100
|
+
- **`policy`** — the resolved `policy.yaml`-derived evidence/trust
|
|
101
|
+
requirements per kind.
|
|
102
|
+
- **`vocab`** — the typed authoring vocabulary (directive/enum/evidence-
|
|
103
|
+
kind index) + its content-hash version.
|
|
104
|
+
- **`cel`** — the per-kind CEL binding surface: the bindable
|
|
105
|
+
`record.<field>` names + types and the callable function allowlist a
|
|
106
|
+
`policy.yaml` `applies_when:`/predicate may reference. The agent-facing
|
|
107
|
+
answer to "what can a CEL predicate for this kind reference?"
|
|
108
|
+
|
|
109
|
+
## Single source of truth
|
|
110
|
+
|
|
111
|
+
`canon context` never re-derives a schema/policy/enum list of its own — it
|
|
112
|
+
resolves through the same shared schema, policy, and vocabulary loaders
|
|
113
|
+
the validators use. A schema edit propagates to `canon context`'s output
|
|
114
|
+
AND `canon format`'s diagnostics from one edit site, never two.
|
|
115
|
+
|
|
116
|
+
## Reading an "expected one of: …" validator error
|
|
117
|
+
|
|
118
|
+
When `canon format --check` rejects an out-of-domain enum value it emits:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
`not-a-real-kind` is not a valid value for `kind` of `run` (expected one of: run, review, divergence, …)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The `expected one of:` member list is the SAME enum domain `canon context
|
|
125
|
+
--json`'s `enums.<field>` reports for that kind — so to fix the artifact,
|
|
126
|
+
pick a member `canon context` lists. Both read the member list off the
|
|
127
|
+
same schema, no hand-maintained second copy.
|
|
128
|
+
|
|
129
|
+
## What this skill does NOT cover
|
|
130
|
+
|
|
131
|
+
- `canon format --check`'s full violation taxonomy — see `canon-fmt`;
|
|
132
|
+
this skill only covers reading its enum diagnostic against the surface.
|
|
133
|
+
- Authoring a typed task atom / handoff body — see
|
|
134
|
+
`canon-vocab`; `canon context`'s `vocab`/`cel` sections
|
|
135
|
+
tell you what's declarable, not how to declare it.
|
|
136
|
+
- `policy.yaml` CEL authoring semantics — see `canon-policy`; this skill
|
|
137
|
+
only surfaces the bindable identifier/function set per kind.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# canon-fmt
|
|
2
|
+
|
|
3
|
+
`canon format --check` is canon's read-only format validator over a
|
|
4
|
+
consumer-repo artifact corpus: ledger records (run/drill/review/clear/
|
|
5
|
+
code-review/design-review), divergence events (manifest/review/
|
|
6
|
+
remediation), `features/`, `inventory/`, and `policy.yaml`. It never
|
|
7
|
+
rewrites or mutates the corpus — it only validates and reports.
|
|
8
|
+
|
|
9
|
+
## Running
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
canon format --check <corpus-root> # e.g. a consumer repo's spec/
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Read-only, always. Exits nonzero if any violation is found, and prints
|
|
16
|
+
a report grouped by failure class in this fixed order:
|
|
17
|
+
|
|
18
|
+
| Failure class | Meaning | Fix |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `layout-grammar` | Wrong Hive path shape — a `features/`/`inventory/` file not under a `kind=<kind>/area=<area>/` prefix, a wrong leaf filename, or `assets.lock`'s ad-hoc format. | Move the file under the correct `kind=…/area=…/` prefix with the expected leaf name. |
|
|
21
|
+
| `missing-envelope` | A YAML file (`inventory/`, `policy.yaml`) has no top-level `schema`/`kind`/`at`/`actor` keys. | Add the four envelope keys at the top level. |
|
|
22
|
+
| `missing-provenance` | A `.feature` file's `Feature:`/`Scenario:` header has no `# canon: {...}` comment either directly above it (with its tags, no blank line) or directly below it. | Use `canon scenario new` / `canon feature new`, which stamp it; never hand-type the line. See `canon-authoring`. |
|
|
23
|
+
| `missing-actor` | No structured `actor` object — a bare `by` string, or absent. | Replace `by: <name>` with a structured `actor` object. |
|
|
24
|
+
| `unspecified-evidence` | A ledger `run`/`drill` record's `evidence` field is absent or an empty, untyped array. | Add a typed `evidence` array. |
|
|
25
|
+
| `free-text-ref` | `upstream_ref`/`port_ref` has a segment not matching `<file>#<symbol>[:<a>-<b>]`. | Rewrite the ref into the `<file>#<symbol>[:<a>-<b>]` grammar. |
|
|
26
|
+
| `joined-ref` | `upstream_ref`/`port_ref` is `;`- or `,`-joined but not split into a structured `refs` array. | Split into a `refs:` array, one entry per ref. |
|
|
27
|
+
| `abbreviated-sha` | `app_sha`/`harness_sha` is present but shorter than the full 40-hex form. | Use the full 40-character SHA. |
|
|
28
|
+
| `one-way-backref` | A divergence review event's `ledger_ref` has no reciprocal `divergence_refs` entry on the ledger record it names. | Add the matching `divergence_refs` entry to that ledger record. |
|
|
29
|
+
| `missing-join-identity` | Corpus-wide, one line: no ledger record carries `change_id`/`task_id`. | Standing note only — new records carry these going forward; historical backfill is out of scope. |
|
|
30
|
+
|
|
31
|
+
Every class is a stable string, safe to grep/diff across runs.
|
|
32
|
+
|
|
33
|
+
## What it does NOT do
|
|
34
|
+
|
|
35
|
+
- **Rewrite anything.** It only validates and reports; a one-shot
|
|
36
|
+
migration of an existing corpus is a separate, per-repo concern.
|
|
37
|
+
- **Backfill `change_id`/`task_id` on historical records.** Both stay
|
|
38
|
+
absent on records that predate the schema; `missing-join-identity` is
|
|
39
|
+
a standing corpus-level note, not a per-record defect it fixes.
|
|
40
|
+
- **Guess a `{file, symbol}` from free prose.** A non-conforming ref is
|
|
41
|
+
reported as `free-text-ref` exactly as found, never fabricated.
|
|
42
|
+
- **Touch a consumer repo's CI gates.** Conforming a corpus and
|
|
43
|
+
reconciling its own tooling is that repo's own operational step.
|