@erclx/canon 5.38.0 → 5.40.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/README.md +5 -5
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/api-design/SKILL.md +12 -9
- package/claude/skills/auto-ship/SKILL.md +43 -23
- package/claude/skills/backlog-triage/SKILL.md +62 -53
- package/claude/skills/backlog-triage/references/apply.md +69 -0
- package/claude/skills/build-in-slices/SKILL.md +8 -4
- package/claude/skills/canon-cli/SKILL.md +5 -1
- package/claude/skills/canon-feedback/SKILL.md +18 -8
- package/claude/skills/canon-feedback-triage/SKILL.md +10 -3
- package/claude/skills/canvas-board/SKILL.md +37 -18
- package/claude/skills/ci-workflow/SKILL.md +5 -4
- package/claude/skills/code-craft/SKILL.md +10 -6
- package/claude/skills/codebase-layout/SKILL.md +3 -5
- package/claude/skills/context-fold/REQUIREMENT.md +4 -4
- package/claude/skills/context-fold/SKILL.md +42 -23
- package/claude/skills/context-fold/references/context-refresh.md +4 -3
- package/claude/skills/context-fold/references/context.md +79 -64
- package/claude/skills/create-rule/SKILL.md +7 -3
- package/claude/skills/create-skill/SKILL.md +27 -7
- package/claude/skills/create-skill/references/skill-reference.md +41 -17
- package/claude/skills/decision-escalate/SKILL.md +8 -5
- package/claude/skills/deploy-app/SKILL.md +1 -1
- package/claude/skills/deprecation-migration/SKILL.md +12 -4
- package/claude/skills/design-taste/SKILL.md +17 -11
- package/claude/skills/docs-sync/REQUIREMENT.md +1 -0
- package/claude/skills/docs-sync/SKILL.md +17 -6
- package/claude/skills/docs-sync/references/docs.md +54 -21
- package/claude/skills/docs-sync/references/readme.md +32 -8
- package/claude/skills/document-health/SKILL.md +3 -4
- package/claude/skills/draft-and-pick/SKILL.md +73 -47
- package/claude/skills/draft-doc/SKILL.md +9 -4
- package/claude/skills/draft-doc/references/context.md +4 -4
- package/claude/skills/draft-doc/references/docs.md +1 -0
- package/claude/skills/draft-doc/references/wiki.md +3 -2
- package/claude/skills/draft-figure/SKILL.md +9 -7
- package/claude/skills/draft-identity/SKILL.md +24 -52
- package/claude/skills/draft-identity/references/card-route.md +46 -0
- package/claude/skills/draft-ready/SKILL.md +19 -7
- package/claude/skills/draft-screencast/SKILL.md +6 -112
- package/claude/skills/draft-screencast/references/beats-template.md +119 -0
- package/claude/skills/draft-slides/SKILL.md +9 -7
- package/claude/skills/draft-slides/references/deck.md +183 -0
- package/claude/skills/git-branch/SKILL.md +3 -3
- package/claude/skills/git-commit/SKILL.md +5 -3
- package/claude/skills/git-followup/SKILL.md +16 -9
- package/claude/skills/git-issue/SKILL.md +6 -5
- package/claude/skills/git-pr/SKILL.md +56 -44
- package/claude/skills/git-pr/references/evidence.md +2 -2
- package/claude/skills/git-pr/references/final-command.md +1 -1
- package/claude/skills/git-pr/references/labels.md +1 -1
- package/claude/skills/git-pr/references/publish.md +1 -1
- package/claude/skills/git-ship/SKILL.md +43 -34
- package/claude/skills/git-ship/references/ci-watch.md +31 -0
- package/claude/skills/git-split/SKILL.md +28 -100
- package/claude/skills/git-split/references/independent.md +40 -0
- package/claude/skills/git-split/references/stacked.md +73 -0
- package/claude/skills/git-stage/SKILL.md +9 -7
- package/claude/skills/git-worktree/SKILL.md +27 -49
- package/claude/skills/git-worktree/references/cleanup.md +55 -0
- package/claude/skills/markdown-craft/SKILL.md +2 -2
- package/claude/skills/markdown-craft/references/markdown.md +82 -53
- package/claude/skills/plan-feature/SKILL.md +52 -46
- package/claude/skills/plan-feature/references/batches.md +46 -0
- package/claude/skills/plan-groundwork/SKILL.md +60 -74
- package/claude/skills/plan-groundwork/references/output.md +48 -0
- package/claude/skills/plan-intake/SKILL.md +28 -21
- package/claude/skills/plan-intake-answer/SKILL.md +14 -13
- package/claude/skills/read-frames/SKILL.md +2 -0
- package/claude/skills/record-screencast/SKILL.md +31 -11
- package/claude/skills/review-address/SKILL.md +76 -158
- package/claude/skills/review-address/references/rebase-only.md +34 -0
- package/claude/skills/review-craft/SKILL.md +27 -11
- package/claude/skills/review-pr/SKILL.md +91 -40
- package/claude/skills/review-ui/SKILL.md +63 -37
- package/claude/skills/review-ui/references/hosted-preview.md +30 -0
- package/claude/skills/role-orchestrator/SKILL.md +105 -74
- package/claude/skills/role-orchestrator/references/orchestrator-filing.md +26 -0
- package/claude/skills/role-orchestrator/references/orchestrator-handback.md +1 -1
- package/claude/skills/role-planner/SKILL.md +66 -64
- package/claude/skills/role-reviewer/SKILL.md +57 -46
- package/claude/skills/role-worker/SKILL.md +68 -63
- package/claude/skills/search-craft/SKILL.md +7 -5
- package/claude/skills/session-compact/SKILL.md +16 -11
- package/claude/skills/session-map/SKILL.md +31 -10
- package/claude/skills/session-relay/SKILL.md +32 -65
- package/claude/skills/session-resume/SKILL.md +18 -13
- package/claude/skills/session-worktree/SKILL.md +70 -42
- package/claude/skills/systematic-debugging/SKILL.md +6 -1
- package/claude/skills/target-check/SKILL.md +13 -6
- package/claude/skills/target-setup/SKILL.md +39 -27
- package/claude/skills/task-board/SKILL.md +68 -60
- package/claude/skills/task-board/references/board.md +1 -1
- package/claude/skills/task-board/references/create-report.md +36 -0
- package/claude/skills/task-board/references/tasks.md +1 -1
- package/claude/skills/task-complete/SKILL.md +20 -18
- package/claude/skills/teach-workspace/SKILL.md +61 -33
- package/claude/skills/test-craft/SKILL.md +2 -1
- package/claude/skills/test-first/SKILL.md +15 -9
- package/claude/skills/ui-checklist/SKILL.md +18 -16
- package/claude/skills/ux-audit/SKILL.md +9 -10
- package/claude/skills/ux-measure/SKILL.md +23 -19
- package/claude/skills/video-craft/SKILL.md +15 -7
- package/claude/skills/write-human/SKILL.md +9 -1
- package/claude/skills/youtube-transcripts/SKILL.md +2 -1
- package/docs/agents/audits.md +61 -60
- package/docs/agents/context-audit.md +40 -58
- package/docs/agents/index.md +11 -61
- package/docs/agents/indexes.md +25 -29
- package/docs/agents/install-and-sync.md +125 -235
- package/docs/agents/markdown-audit.md +54 -96
- package/docs/agents/migrate.md +41 -16
- package/docs/agents/output-shape.md +60 -45
- package/docs/agents/overview.md +36 -12
- package/docs/agents/records.md +37 -79
- package/docs/agents/sessions-transfer.md +26 -70
- package/docs/agents/targets.md +25 -77
- package/docs/target/index.md +0 -1
- package/docs/target/migrations.md +57 -66
- package/docs/target/projects.md +36 -78
- package/docs/target/scenarios.md +9 -19
- package/docs/target/sync.md +27 -68
- package/docs/workflow/ai-workflow.md +22 -68
- package/docs/workflow/operating-model.md +32 -186
- package/docs/workflow/parallel-features.md +29 -66
- package/docs/workflow/skill-map-on-request.md +22 -24
- package/docs/workflow/skill-map.md +72 -76
- package/docs/workflow/visual-design-workflow.md +25 -118
- package/docs/workflow/zshrc-aliases.md +18 -37
- package/package.json +1 -1
- package/src/canvas/client/inspector/fields.css +4 -0
- package/src/canvas/index.html +6 -0
- package/src/claude/skills-reach.ts +2 -2
- package/src/cli/ui.ts +3 -1
- package/src/commands/canvas.ts +23 -0
- package/src/commands/capture.ts +14 -0
- package/src/commands/claude.ts +14 -1
- package/src/commands/context.ts +106 -7
- package/src/commands/demo.ts +22 -0
- package/src/commands/deps.ts +6 -0
- package/src/commands/driver.ts +28 -2
- package/src/commands/gov.ts +52 -18
- package/src/commands/hooks.ts +63 -0
- package/src/commands/intake.ts +17 -0
- package/src/commands/labels.ts +38 -5
- package/src/commands/markdown.ts +169 -32
- package/src/commands/pr.ts +160 -43
- package/src/commands/records.ts +8 -0
- package/src/commands/secrets.ts +6 -0
- package/src/commands/sessions.ts +8 -0
- package/src/commands/tasks.ts +52 -0
- package/src/commands/teach.ts +13 -0
- package/src/commands/upstream.ts +25 -1
- package/src/commands/worktrees.ts +5 -0
- package/src/context/audit.ts +274 -5
- package/src/context/classify/prompts.ts +1 -1
- package/src/context/folders.ts +1 -1
- package/src/context/gate.ts +23 -7
- package/src/context/shape-gated.ts +30 -0
- package/src/counts/scan.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/design/document.ts +1 -1
- package/src/design/tokens.ts +1 -1
- package/src/gate/boundaries.ts +4 -1
- package/src/gate/measures.ts +16 -191
- package/src/gate/stages.ts +14 -30
- package/src/git/env.ts +6 -0
- package/src/hooks/reply-links.ts +110 -0
- package/src/markdown/density.ts +258 -0
- package/src/markdown/gate.ts +57 -18
- package/src/markdown/reference-shape.ts +103 -0
- package/src/markdown/scope.ts +162 -0
- package/src/markdown/structure.ts +9 -59
- package/src/pr/lift.ts +153 -19
- package/src/pr/painted.ts +87 -0
- package/src/roots/record.ts +18 -1
- package/src/sandbox/census.ts +1 -1
- package/src/sandbox/headless/run.ts +3 -2
- package/src/sandbox/headless/watch.ts +3 -4
- package/src/shipped/references.ts +1 -1
- package/src/slides/convert/master.ts +3 -0
- package/src/sync/format.ts +46 -0
- package/src/sync/stamp.ts +6 -0
- package/tooling/astro/reference.md +2 -2
- package/tooling/base/reference.md +1 -1
- package/tooling/claude/seeds/.claude/hooks/reply-links.sh +72 -0
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +22 -1
- package/tooling/claude/seeds/.claude/settings.json +4 -0
- package/tooling/go/reference.md +1 -1
- package/tooling/nextjs/reference.md +1 -1
- package/tooling/php/reference.md +1 -1
- package/tooling/python/reference.md +1 -1
- package/tooling/vite-react/reference.md +1 -1
- package/tooling/web/reference.md +1 -1
- package/docs/agents/canvas.md +0 -86
- package/docs/agents/capture.md +0 -65
- package/docs/agents/census.md +0 -23
- package/docs/agents/commands.md +0 -154
- package/docs/agents/comments.md +0 -34
- package/docs/agents/context-audit-checks.md +0 -90
- package/docs/agents/context-classify.md +0 -101
- package/docs/agents/counts.md +0 -74
- package/docs/agents/demo.md +0 -140
- package/docs/agents/docs.md +0 -27
- package/docs/agents/drift-surfaces.md +0 -201
- package/docs/agents/driver.md +0 -103
- package/docs/agents/gate.md +0 -90
- package/docs/agents/gov-detect.md +0 -47
- package/docs/agents/hooks.md +0 -58
- package/docs/agents/intake.md +0 -81
- package/docs/agents/key-changes.md +0 -116
- package/docs/agents/label-coverage.md +0 -86
- package/docs/agents/markdown-audit-weight.md +0 -81
- package/docs/agents/pr-evidence-layout.md +0 -70
- package/docs/agents/pr-evidence.md +0 -273
- package/docs/agents/pr-frames.md +0 -131
- package/docs/agents/pr-lift.md +0 -132
- package/docs/agents/pr-local.md +0 -111
- package/docs/agents/pr-preview.md +0 -155
- package/docs/agents/pr-reads.md +0 -111
- package/docs/agents/pr-tick.md +0 -72
- package/docs/agents/records-push.md +0 -61
- package/docs/agents/records-stale.md +0 -40
- package/docs/agents/records-validate.md +0 -57
- package/docs/agents/restated.md +0 -83
- package/docs/agents/routing.md +0 -61
- package/docs/agents/rule-citations.md +0 -90
- package/docs/agents/sandbox.md +0 -126
- package/docs/agents/scripting.md +0 -142
- package/docs/agents/sessions.md +0 -128
- package/docs/agents/skills-audit.md +0 -120
- package/docs/agents/skills-reach.md +0 -64
- package/docs/agents/slides.md +0 -176
- package/docs/agents/state-scoped-risk.md +0 -105
- package/docs/agents/superseded.md +0 -85
- package/docs/agents/tasks-archive.md +0 -83
- package/docs/agents/tasks-plans.md +0 -152
- package/docs/agents/tasks-validate.md +0 -133
- package/docs/agents/tasks.md +0 -123
- package/docs/agents/teach-authoring.md +0 -118
- package/docs/agents/teach.md +0 -157
- package/docs/agents/test-order.md +0 -58
- package/docs/agents/upstream.md +0 -94
- package/docs/agents/worktrees.md +0 -118
- package/docs/target/standards-moved.md +0 -34
- package/src/markdown/growth.ts +0 -43
|
@@ -47,7 +47,7 @@ Seeds live in `tooling/base/seeds/`. Sync drops each once on first install and n
|
|
|
47
47
|
- `pre-commit` runs `bunx lint-staged`.
|
|
48
48
|
- `commit-msg` runs `bunx commitlint --edit "$1"`.
|
|
49
49
|
- `pre-push` runs `bun run check`.
|
|
50
|
-
- `post-merge` runs `canon hooks post-merge`: archive the task a merged pull request closed, push the records, reclaim merged worktrees, reinstall the CLI, and update the plugin. It does nothing when the board is absent. `CANON_SKIP_RECLAIM`, `CANON_SKIP_UPGRADE`, and `CANON_SKIP_PLUGIN_UPDATE` turn off the three steps that act on the machine.
|
|
50
|
+
- `post-merge` runs `canon hooks post-merge`: archive the task a merged pull request closed, push the records, reclaim merged worktrees, reinstall the CLI, and update the plugin. It does nothing when the board is absent. `CANON_SKIP_RECLAIM`, `CANON_SKIP_UPGRADE`, and `CANON_SKIP_PLUGIN_UPDATE` turn off the three steps that act on the machine. Run `canon hooks post-merge --help` for the contract.
|
|
51
51
|
- `post-rewrite` delegates to `post-merge` on `rebase`, so a `pull.rebase=true` machine still gets the check.
|
|
52
52
|
|
|
53
53
|
## lint-staged
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Claude Code sends a payload and closes stdin. A bare read with nothing feeding
|
|
4
|
+
# it blocks forever and holds the session open, so the read is bounded. `read`
|
|
5
|
+
# rather than `timeout cat`, which macOS does not ship.
|
|
6
|
+
IFS= read -r -d '' -t 2 input
|
|
7
|
+
[ -n "$input" ] || {
|
|
8
|
+
printf '%s reads a Claude Code hook payload on stdin and cannot be run by hand.\n' "${0##*/}" >&2
|
|
9
|
+
exit 1
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
# A reply with no link is the ordinary turn, so it leaves before anything
|
|
13
|
+
# spawns. The payload holds the reply JSON-escaped, and `](` survives the
|
|
14
|
+
# escaping untouched, so a shell test on the raw payload is enough. This is the
|
|
15
|
+
# one quiet exit: every later failure to measure reports instead.
|
|
16
|
+
case "$input" in
|
|
17
|
+
*']('*) ;;
|
|
18
|
+
*) exit 0 ;;
|
|
19
|
+
esac
|
|
20
|
+
|
|
21
|
+
# A failure to measure exits 1 rather than 2. Exit 2 forces the session to
|
|
22
|
+
# continue, and a hook that cannot read `stop_hook_active` would then block
|
|
23
|
+
# every continuation too.
|
|
24
|
+
unread() {
|
|
25
|
+
printf 'Reply-links: the final reply was not checked. %s\n' "$1" >&2
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
command -v jq >/dev/null 2>&1 || unread 'Found no `jq` on PATH.'
|
|
30
|
+
|
|
31
|
+
event=$(printf '%s' "$input" | jq -r '.hook_event_name // empty' 2>/dev/null)
|
|
32
|
+
[ -n "$event" ] || unread 'The payload did not parse.'
|
|
33
|
+
[ "$event" = "Stop" ] || exit 0
|
|
34
|
+
|
|
35
|
+
# The forced continuation after a block fires this hook again with the field
|
|
36
|
+
# true. Passing it is what makes the block fire once, so the corrected links
|
|
37
|
+
# are not checked a second time.
|
|
38
|
+
stop_hook_active=$(printf '%s' "$input" | jq -r '.stop_hook_active // false')
|
|
39
|
+
[ "$stop_hook_active" = "true" ] && exit 0
|
|
40
|
+
|
|
41
|
+
reply=$(printf '%s' "$input" | jq -r '.last_assistant_message // empty')
|
|
42
|
+
case "$reply" in
|
|
43
|
+
*']('*) ;;
|
|
44
|
+
*) exit 0 ;;
|
|
45
|
+
esac
|
|
46
|
+
|
|
47
|
+
# The verb resolves a relative link against the main worktree root, read from
|
|
48
|
+
# the directory the session stands in, so the payload's cwd is named rather than
|
|
49
|
+
# inherited from wherever the hook was spawned.
|
|
50
|
+
cwd=$(printf '%s' "$input" | jq -r '.cwd // empty')
|
|
51
|
+
[ -n "$cwd" ] && [ -d "$cwd" ] || unread 'The payload carried no working directory that exists.'
|
|
52
|
+
|
|
53
|
+
# A project has no checkout of the CLI, so this resolves the installed binary
|
|
54
|
+
# alone, and a machine without it says so rather than passing the reply.
|
|
55
|
+
if command -v canon >/dev/null 2>&1; then
|
|
56
|
+
record=$(cd "$cwd" && printf '%s' "$reply" | canon hooks reply-links --json 2>/dev/null)
|
|
57
|
+
else
|
|
58
|
+
unread 'Found no `canon` binary on PATH. Install one with `bun add -g @erclx/canon`.'
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# The record decides rather than the exit code. A binary predating the verb
|
|
62
|
+
# exits 1 on an unknown command, which is the code a finding also leaves, and
|
|
63
|
+
# it writes no record.
|
|
64
|
+
ok=$(printf '%s' "$record" | jq -r 'if .ok == true then "true" elif .ok == false then "false" else empty end' 2>/dev/null)
|
|
65
|
+
case "$ok" in
|
|
66
|
+
true) exit 0 ;;
|
|
67
|
+
false)
|
|
68
|
+
printf '%s\n' "$(printf '%s' "$record" | jq -r '.message')" >&2
|
|
69
|
+
exit 2
|
|
70
|
+
;;
|
|
71
|
+
*) unread 'The link check returned no record. An installed `canon` that predates `canon hooks reply-links` does this.' ;;
|
|
72
|
+
esac
|
|
@@ -77,13 +77,24 @@ headings=$(printf '%s' "$record" |
|
|
|
77
77
|
colons=$(printf '%s' "$record" |
|
|
78
78
|
jq -r --arg new "$new" '.entries[]?.colons[]? | (.lead // (.text[:.column] | sub("^.*\\s"; ""))) as $lead | select($new | contains($lead + ":")) | ":\(.line):\(.column + 1) \(.text)"' 2>/dev/null)
|
|
79
79
|
|
|
80
|
+
# Density findings are handed back whole, gating or not, since the verb only
|
|
81
|
+
# returns them for a path in its scope and a finding the push does not fail on
|
|
82
|
+
# yet is the one a rewrite has to clear before its folder is gated.
|
|
83
|
+
density=$(printf '%s' "$record" |
|
|
84
|
+
jq -r '.entries[]?.density[]? | ":\(.line) \(.kind) " + (if .limit == null then "opens with neither a paragraph nor a table" else "\(.value) past \(.limit)" end) + (if .gating then " gating" else "" end)' 2>/dev/null)
|
|
85
|
+
|
|
86
|
+
# A page marked `kind: reference` carries reference shape findings, handed back
|
|
87
|
+
# whole the same way, since a gated one fails the push like a density finding.
|
|
88
|
+
shape=$(printf '%s' "$record" |
|
|
89
|
+
jq -r '.entries[]?.referenceShape[]? | ":\(.line) \(.kind) \(.text)" + (if .gating then " gating" else "" end)' 2>/dev/null)
|
|
90
|
+
|
|
80
91
|
# A set the verb shipped empty measures nothing and would report a clean file.
|
|
81
92
|
# Reading the findings alone turns that narrowed check into a pass, so the field
|
|
82
93
|
# is read beside them.
|
|
83
94
|
empty=$(printf '%s' "$record" |
|
|
84
95
|
jq -r '[.bans.emptySets[]?] | join(", ")' 2>/dev/null)
|
|
85
96
|
|
|
86
|
-
[ -z "$hits" ] && [ -z "$headings" ] && [ -z "$colons" ] && [ -z "$unread" ] && [ -z "$empty" ] && exit 0
|
|
97
|
+
[ -z "$hits" ] && [ -z "$headings" ] && [ -z "$colons" ] && [ -z "$density" ] && [ -z "$shape" ] && [ -z "$unread" ] && [ -z "$empty" ] && exit 0
|
|
87
98
|
|
|
88
99
|
nl=$'\n'
|
|
89
100
|
msg=""
|
|
@@ -111,4 +122,14 @@ if [ -n "$colons" ]; then
|
|
|
111
122
|
msg="${msg:+$msg$nl}$found"
|
|
112
123
|
fi
|
|
113
124
|
|
|
125
|
+
if [ -n "$density" ]; then
|
|
126
|
+
found=$(printf 'Standards-audit: %s breaks the markdown density limits, being a 350-character paragraph, 2 paragraphs in a row, a 200-character bullet, 5 plain bullets in a row, no H4, and a paragraph or table opening every H3. Split each block at its seam rather than trimming words to pass. A finding marked gating fails the push.\n%s' "$file" "$density")
|
|
127
|
+
msg="${msg:+$msg$nl}$found"
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [ -n "$shape" ]; then
|
|
131
|
+
found=$(printf 'Standards-audit: %s is marked kind: reference and breaks its shape, being an opening, then Output, Refusals, and See also, each at most once and in that order, no H3, and no flag table. Point at the command'"'"'s own --help for flags. A finding marked gating fails the push.\n%s' "$file" "$shape")
|
|
132
|
+
msg="${msg:+$msg$nl}$found"
|
|
133
|
+
fi
|
|
134
|
+
|
|
114
135
|
jq -nc --arg msg "$msg" '{hookSpecificOutput:{hookEventName:"PostToolUse",additionalContext:$msg}}'
|
package/tooling/go/reference.md
CHANGED
|
@@ -59,4 +59,4 @@ Append to the `## Scripts` table:
|
|
|
59
59
|
|
|
60
60
|
## CI docs (extend)
|
|
61
61
|
|
|
62
|
-
In `canon/context/ci.md`, the Typecheck row's assertion reads: `` `go vet ./...` passes ``. Add a Lint row whose assertion reads: `` `golangci-lint run` passes ``. Add a Tests row whose assertion reads: `` `go test -race ./...` exits 0 ``. <!-- audit-ignore-citations: canon/context/ci.md -->
|
|
62
|
+
In `canon/context/development/ci.md`, the Typecheck row's assertion reads: `` `go vet ./...` passes ``. Add a Lint row whose assertion reads: `` `golangci-lint run` passes ``. Add a Tests row whose assertion reads: `` `go test -race ./...` exits 0 ``. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
|
@@ -50,4 +50,4 @@ Append to the `## Scripts` table:
|
|
|
50
50
|
|
|
51
51
|
## CI docs (extend)
|
|
52
52
|
|
|
53
|
-
In `canon/context/ci.md`, the Typecheck row's assertion reads: `` `next typegen && tsc --noEmit` passes ``. <!-- audit-ignore-citations: canon/context/ci.md -->
|
|
53
|
+
In `canon/context/development/ci.md`, the Typecheck row's assertion reads: `` `next typegen && tsc --noEmit` passes ``. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
package/tooling/php/reference.md
CHANGED
|
@@ -73,4 +73,4 @@ Append to the `## Scripts` table:
|
|
|
73
73
|
|
|
74
74
|
## CI docs (extend)
|
|
75
75
|
|
|
76
|
-
In `canon/context/ci.md`, the Typecheck row's assertion reads: `` `phpstan analyse` passes ``. Add a Lint row whose assertion reads: `` `php-cs-fixer check` passes ``. Add a Tests row whose assertion reads: `` `phpunit` exits 0 ``. <!-- audit-ignore-citations: canon/context/ci.md -->
|
|
76
|
+
In `canon/context/development/ci.md`, the Typecheck row's assertion reads: `` `phpstan analyse` passes ``. Add a Lint row whose assertion reads: `` `php-cs-fixer check` passes ``. Add a Tests row whose assertion reads: `` `phpunit` exits 0 ``. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
|
@@ -62,4 +62,4 @@ Append to the `## Scripts` table:
|
|
|
62
62
|
|
|
63
63
|
## CI docs (extend)
|
|
64
64
|
|
|
65
|
-
In `canon/context/ci.md`, the Typecheck row's assertion reads: `` `mypy .` passes ``. Add a Lint row whose assertion reads: `` `ruff check` and `ruff format --check` pass ``. Add a Tests row whose assertion reads: `` `pytest` exits 0 ``. <!-- audit-ignore-citations: canon/context/ci.md -->
|
|
65
|
+
In `canon/context/development/ci.md`, the Typecheck row's assertion reads: `` `mypy .` passes ``. Add a Lint row whose assertion reads: `` `ruff check` and `ruff format --check` pass ``. Add a Tests row whose assertion reads: `` `pytest` exits 0 ``. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
|
@@ -44,4 +44,4 @@ Append to the `## Scripts` table:
|
|
|
44
44
|
|
|
45
45
|
## CI docs (extend)
|
|
46
46
|
|
|
47
|
-
In `canon/context/ci.md`, the Typecheck row's assertion reads: `` `tsc --noEmit` passes ``. <!-- audit-ignore-citations: canon/context/ci.md -->
|
|
47
|
+
In `canon/context/development/ci.md`, the Typecheck row's assertion reads: `` `tsc --noEmit` passes ``. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
package/tooling/web/reference.md
CHANGED
|
@@ -82,7 +82,7 @@ Sticky negative knowledge. Do not relearn.
|
|
|
82
82
|
|
|
83
83
|
## CI docs (extend)
|
|
84
84
|
|
|
85
|
-
Extend `canon/context/ci.md` so the `## Checks` table reflects the web jobs. <!-- audit-ignore-citations: canon/context/ci.md -->
|
|
85
|
+
Extend `canon/context/development/ci.md` so the `## Checks` table reflects the web jobs. <!-- audit-ignore-citations: canon/context/development/ci.md -->
|
|
86
86
|
|
|
87
87
|
Append rows:
|
|
88
88
|
|
package/docs/agents/canvas.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Canvas
|
|
3
|
-
description: The canvas server, its content format, and the verbs that list, arrange, fit, select, edit, mark, and capture frames
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Canvas
|
|
7
|
-
|
|
8
|
-
`canon canvas` serves a local canvas of pages and HTML frames and gives an agent the verbs the operator's mouse has. A page is a folder under `.canon/canvas/`, a frame is one HTML file in it, and `layout.json` beside them holds each frame's box. `claude/skills/canvas-board/references/canvas.md` fixes that content format, and the `canvas-board` skill carries the procedure a session follows to drive the canvas.
|
|
9
|
-
|
|
10
|
-
## Serve
|
|
11
|
-
|
|
12
|
-
`canvas serve` serves the canvas on `127.0.0.1`, walks ports like `canon serve`, refuses a `Host` other than loopback on its own port, and runs until interrupted. Each frame gets the project's token stylesheet injected, being this toolkit's tokens in its own checkout, else `.claude/design/base.css` plus anything under `.claude/design/project/`, else none with a notice. An open canvas reloads a frame whose file changes.
|
|
13
|
-
|
|
14
|
-
The toolkit's own tokens arrive with the font faces they name embedded, so a frame renders in them on a machine that never installed them. An installed base gets the same treatment: each vendored face its sheets name is embedded, unless a project rule declares that family itself.
|
|
15
|
-
|
|
16
|
-
A project's own `@font-face` rules under `.claude/design/project/` have each `url()` inlined as a `data:` URI. A rule whose file is missing, or whose path leads out of `.claude/design/project/` after links resolve, is dropped and the frame still renders. `canvas serve` warns once per dropped rule and names each under `tokens.dropped` in its `--json` record. The confinement check reads each `url()` after percent-decoding it. `canon design fonts add` writes those rules.
|
|
17
|
-
|
|
18
|
-
Before it binds a port, `canvas serve` checks that `preact` and `@preact/signals` resolve from the package the CLI runs from, never from the served project. When either is missing it refuses with reason `missing-client-deps` and names `bun install` in the detail, rather than serving a shell that loads as a blank page.
|
|
19
|
-
|
|
20
|
-
The write routes the shell posts to also refuse a request carrying an `Origin` other than the server's own, and a body that is not JSON.
|
|
21
|
-
|
|
22
|
-
## List and add
|
|
23
|
-
|
|
24
|
-
`canvas list --json` emits every page with its frames. `page add`, `page rename`, and `frame add` (`--width`, `--height`) each emit one record under `--json`, refusing a name that is not one path segment, a page that already exists, or a root that is not a directory, with the reason on stderr.
|
|
25
|
-
|
|
26
|
-
## Arrange and select
|
|
27
|
-
|
|
28
|
-
`frame move <page> <name> --x <px> --y <px>` rewrites one frame's position in `layout.json` and keeps its size. An omitted axis stays where the frame is. It refuses a frame or page that does not exist and a layout that does not parse.
|
|
29
|
-
|
|
30
|
-
`frame resize <page> <name> --width <px> --height <px>` rewrites one frame's whole box in one write, and `--x` and `--y` move it at the same time. An omitted flag keeps the frame's current value. It refuses a width or height that is not a positive number as `invalid-size`, a position that is not a number as `invalid-position`, and a missing frame, a missing page, or a layout that does not parse as `frame move` does.
|
|
31
|
-
|
|
32
|
-
`canvas arrange <page>` re-lays a page's frames. It keeps the rows they already sit in, where boxes whose vertical spans overlap share a row, orders each row left to right by `x`, places the boxes on the 80px frame gap from the page's leftmost edge, and stacks the rows on their tallest box plus the gap from the page's top edge. It also drops every layout entry whose frame file is gone. `--check` writes nothing. `--json` emits `{ ok, page, written, moved, dropped }`, where `moved` lists each frame with its `from` and `to` position and `dropped` lists the entries with no file. Sizes never change. Under `--check` it exits 2 when a frame would move or an entry would drop, and it refuses a missing page as `no-page` and a layout that does not parse as `malformed-layout`.
|
|
33
|
-
|
|
34
|
-
`canvas fit <page>/<frame>` and `canvas fit <page>` set each frame's height to its content. The content is measured in the capture browser at the frame's box width, through the served address, after fonts and the load event settle, and the height is that measure rounded up with no margin. The write goes through the same writer as `frame resize`. `--check` writes nothing. `--json` emits `{ ok, written, frames }`, one row per frame carrying `height`, `fitted`, `wide`, `font`, `viewport`, `family`, and `owed`. `wide` is true when the content is wider than the box, which fit reports and never widens, since the width is the frame's declared render width. `font` is true when the first family of the body text is not one the served sheet declares a face for, being the toolkit faces `Geist Variable`, `Noto Sans Mono`, and the hand-drawn pair, plus any face the project declares, because a height fitted against a machine family may not hold in another browser. `viewport` is true when the frame's height depends on the viewport, as a height in `vh` does. The lowest element edge is read with the viewport at the box height and at twice it, and an edge that moved means the content measure is not the height a viewer draws, so its height is kept and nothing is written for it. Under `--check` it exits 2 when any row is owed, and it refuses as `no-page`, `no-frame`, `no-server`, or `capture-failed` the way `canvas capture` does. Rows below a frame that grew do not move, so run `canvas arrange` after a fit.
|
|
35
|
-
|
|
36
|
-
The shell writes through the same writer when the operator drags a frame or one of its corner handles. Both take a lock file beside the layout, read it, merge their change, and replace it, so a drag released while a verb writes loses neither position. A writer that cannot get the lock within two seconds refuses with reason `busy`.
|
|
37
|
-
|
|
38
|
-
`canvas selection --json` emits `{ ok, selection }` with the page, frame, file, box, and path of the frame the operator selected, or `selection: null` when nothing is selected or the selected frame has since been removed. Read it when the operator says "this one".
|
|
39
|
-
|
|
40
|
-
The operator can also pick one element inside a frame, by clicking it on the surface or in the frame's layers tree. The selection then carries `element`, recording the `index` in document order, `tag`, `classes`, and `text` excerpt as they were at the pick. An edit to the frame since can shift that index onto another element, so `stale` turns true once the file's content no longer matches what the pick was made against. Check it before acting on the index.
|
|
41
|
-
|
|
42
|
-
A pick is refused as `address-mismatch` when the browser builds elements the file never states, such as a `tbody` a table leaves out or a `body` after a `head` the file states. A fragment is picked like a whole document, since the server writes the missing `html`, `head`, and `body` into the served frame and the shell leaves them out of its count. The shell sends its own element count beside the index, so a frame the two sides count differently is reported rather than recorded against the wrong element. A pick is refused as `stale-address` when the frame file changed between the frame being served and the pick arriving, since every served frame carries the hash of its file and the shell sends that hash back.
|
|
43
|
-
|
|
44
|
-
## Edit
|
|
45
|
-
|
|
46
|
-
`canvas edit <page>/<frame> --element <index> --set <property>=<value>` sets one property of the element at that index, the same index `canvas selection` reports. The properties are `text`, `color`, `background-color`, `font-size`, `font-weight`, `font-family`, `line-height`, `letter-spacing`, `text-align`, `width`, `height`, `padding`, `gap`, `display`, `flex-direction`, `justify-content`, `align-items`, `flex-wrap`, `opacity`, `border-radius`, `border-top-left-radius`, `border-top-right-radius`, `border-bottom-right-radius`, and `border-bottom-left-radius`. A style property is written into the element's inline `style`, replacing that property and leaving the others as they were, and an empty value drops it. Writing `border-radius` or `padding` also drops that shorthand's longhands from the same `style`, so no corner or side left over overrides the new value. Writing a longhand leaves its shorthand in place, since the longhand comes later and wins.
|
|
47
|
-
|
|
48
|
-
`text` replaces the text of an element holding text alone and refuses one holding other elements as `not-text-only`. Every byte outside the element stays as it was. `--json` emits the page, frame, file, path, and the file's new `hash`.
|
|
49
|
-
|
|
50
|
-
The operator edits the same set from the inspector, which posts to the same writer with the hash the frame was served with. Dragging a selected element's corner handle writes `width` and then `height` in pixels through that writer, the second edit carrying the hash the first answered. An edit made against a version of the file Claude has since rewritten is refused as `stale-address` and the shell reloads the frame, so nothing lands on a shifted element. Both writers take the frame file's lock, and an edit that keeps the selected element where it was keeps the selection fresh.
|
|
51
|
-
|
|
52
|
-
Size, padding, opacity, radius, and the type properties show in the inspector for every element. Family and font size list the sheet's `font-family` and `font-size` token groups first and write a pick as `var(--<name>)`, the same as a color. The flex fields show only on a flex container, a grid container gets none, and the inspector sets `display` only to `flex`, so any other `display` change goes through the verb.
|
|
53
|
-
|
|
54
|
-
A color picked from the project's tokens is written as `var(--<name>)`, and below full opacity as a `color-mix()` of that `var()` with `transparent` at the opacity percent, so it keeps following the theme. A browser older than 2023 drops a `color-mix()` value, which leaves the property unset there. A hex is written as six digits, or eight below full opacity. The inspector's full color picker writes a hex for any color it sets, so the field marks the value raw, and only its alpha keeps a token through the `color-mix()` form.
|
|
55
|
-
|
|
56
|
-
Inline style beats a class, so an operator's edit masks a class change Claude makes later. Read a frame's inline styles before restyling it, and remove one the change should replace. The inspector marks a color, a background, or a family or font size the sheet has tokens for, set inline, with the word `raw` when its value names no `var()` and is not `currentColor` or a CSS-wide keyword, since that value stays fixed when the theme changes. A property outside the set, or a value carrying `;`, `{`, `}`, `<`, `>`, or a line break, is refused as `invalid-edit`.
|
|
57
|
-
|
|
58
|
-
The Theme tab in the shell lists what the token stylesheet defines, grouped as color, spacing, radius, font family, font size, and other. The page record at `/api/pages` carries the same list as `tokens.groups`.
|
|
59
|
-
|
|
60
|
-
## Undo in the shell
|
|
61
|
-
|
|
62
|
-
The operator undoes and redoes their own shell edits, frame moves, and frame resizes from Ctrl or Cmd with Z, Shift with it or Ctrl with Y, or the tool strip's buttons. The history lives in the `canvas serve` process and covers shell edits alone, so a `canvas edit`, `canvas frame move`, or `canvas frame resize` never enters it, and their `--json` records are unchanged. A restart clears it.
|
|
63
|
-
|
|
64
|
-
An undo writes the recorded state back only while the element or frame still holds what the operator's edit left. When Claude has since rewritten what that edit changed, being the element's inline style or, for a text edit, its text, or has added or removed an element in that frame, the operator's entry is dropped and nothing is written, and the shell says so. A write that changes another element's style or text, or another part of the same element, leaves the entry live. The page record at `/api/pages` carries `history` as `{ canUndo, canRedo }`.
|
|
65
|
-
|
|
66
|
-
The tool strip also holds a toggle, bound to backslash, that hides both side panels to show the whole surface, and each panel resizes from a handle on its inner edge. Both are remembered in the browser and write nothing to the project.
|
|
67
|
-
|
|
68
|
-
## Mark a frame being edited
|
|
69
|
-
|
|
70
|
-
`canvas editing <page>/<frame>` marks a frame as being edited, so an open canvas shows who is working on it before the write lands. The shell draws the mark as `<by> editing` on that frame's label with a dashed outline around it, and drops it on the reread after `--done` or at the mark's `until` with no reread. Run it before writing a frame and again with `--done` once the edits are written. A bare `canvas editing` lists the live marks, and `--json` emits `{ ok, editing }` after each of the three, with each mark carrying `page`, `frame`, `by`, `since`, and `until`.
|
|
71
|
-
|
|
72
|
-
The label is `--by <name>` when given. Without it, the verb reads the caller's name off the session roster, and falls back to `a session` when the environment names no session or the roster holds none matching it.
|
|
73
|
-
|
|
74
|
-
The marks live in `.canon/canvas/editing.json`, keyed by `<page>/<frame>`. Each write takes the record's lock and merges its one key, so two sessions marking two frames both keep their marks. A mark lapses five minutes after it was written, and marking the frame again renews it, so a session that never clears its mark misleads the operator for five minutes at most. A read leaves out a lapsed mark and a mark on a frame since removed, and a record that does not parse reads as holding none and is replaced by the next mark.
|
|
75
|
-
|
|
76
|
-
A mark refuses `no-page` or `no-frame` for a target not on disk, and `invalid-name` for a target that is not `<page>/<frame>` or for `--done` with no target. `--done` on a frame holding no mark succeeds and writes nothing. The mark gates no write, so an inspector edit to a marked frame still lands, and the hash check still refuses one made against a file the session rewrote. The page record at `/api/pages` carries the live marks as `editing`, each with `page`, `frame`, `by`, and `until`.
|
|
77
|
-
|
|
78
|
-
## Capture
|
|
79
|
-
|
|
80
|
-
`canvas capture <page>/<frame>` renders one frame as a PNG, and `canvas capture <page>` renders every frame on the page. Each goes through a server started for the call, so the injected tokens are in the image, and renders at the frame's own width from the layout, so a media query resolves there. It never captures the file on disk.
|
|
81
|
-
|
|
82
|
-
`--out` is the PNG for a frame and a folder for a page, defaulting to session scratch. `--json` emits `{ ok, captures }` with the path and pixel size of each frame. Each PNG is the frame's whole document, so its height follows the document and not the frame's box. The font check `canon capture` makes applies, so a frame naming a font the machine lacks fails with that reason. A refused capture reports `no-page` or `no-frame` for a target that does not exist, `no-server` when the server for the call cannot start, and `capture-failed` for an error the engine throws, such as a browser that will not launch.
|
|
83
|
-
|
|
84
|
-
`canvas capture <page> --composite` renders the whole page as one PNG, with every frame at its layout position and its own width. The image is the union of the frame boxes with no padding, transparent where no frame sits, and frames that overlap paint in the board's order. It shows the frames only, with no captions and no selection outline. Each frame is clipped to its box as it is on the board, so its height can differ from the per-frame PNG, and each shows in its default theme, since the board's theme toggle is client state the capture never sees. The font check covers the composite page and not the documents inside its frames.
|
|
85
|
-
|
|
86
|
-
Under `--composite`, `--out` is the PNG itself, defaulting to `<page>.png` beside the per-frame folder in session scratch. `--json` emits `{ ok, composite }` carrying the page, the path, and the pixel size. The flag takes a page alone, and a `<page>/<frame>` target is refused as `invalid-name`. For the length of the call the generated page sits at `.canon/canvas/.composite/`, so it shares an origin with the frames, and the capture removes it after.
|
package/docs/agents/capture.md
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Capture
|
|
3
|
-
description: Rendering HTML sources to PNG, what the command asserts about fonts, and why the selector has no default
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Capture
|
|
7
|
-
|
|
8
|
-
`canon capture [source] --selector <sel>` renders HTML sources to PNG, which is how a generated documentation image is rebuilt from the markup it was generated out of. The source defaults to `assets/`, where a directory expands to every `.html` directly inside it, so adding a capture means dropping a file beside the first one and running the same command. That default is a generic starting point rather than a convention every target shares, and it stays because a missing folder still refuses loud, naming the argument, rather than failing silently. This repository no longer takes it: its own sources moved to `assets/captures/` and its images moved to `assets/frames/`, so a run here names the source explicitly and sends the output where that run wants it, `--out assets/frames` to rebuild the committed images and somewhere disposable to preview them.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
canon capture --selector .window
|
|
12
|
-
canon capture assets/captures/install.html --selector .window --out assets/frames
|
|
13
|
-
canon capture assets/captures --selector .window --out .canon/review/captures
|
|
14
|
-
canon capture https://example.com --selector .window --out preview.png
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
`--selector` is required and every example above passes it. The element a capture crops to belongs to the page, not to the command, so there is no value that could be right for an arbitrary project's markup. `.window` is what this repository's own five sources declare, and a project renders its own pages by naming whatever theirs declare.
|
|
18
|
-
|
|
19
|
-
## What this repository captures
|
|
20
|
-
|
|
21
|
-
A capture set here spans two folders. `assets/captures/` holds three sources and the two templates they are written from, and `assets/frames/` holds their images and the built-page capture a document points at with the stamp answering for each, outside the `evidence` segment `canon pr evidence` compares. The folder name is this repository's own layout, and a target picks its own `--out`. One run over the source folder rebuilds every image, and it takes `--out assets/frames` to put each PNG where its document points rather than beside the markup it rendered. None of the sources is edited by hand. `scripts/core/regen-hero.ts` writes each `.html` from the template beside it, filling one shared value map into all of them. A branch commits none of them for a moved count or token, since the refresh workflow regenerates them from `main` and opens one pull request, and `bun run check` runs the script with `--check`, which fills every template into a temp folder and fails when the regeneration cannot run.
|
|
22
|
-
|
|
23
|
-
The `hero` template takes catalog data, so a stack gaining a rule moves the frame on the next run. `install.html` is the exception, since it holds terminal text from a real run in its template rather than derived from a live catalog at build time. `assets/frames/arrival.png` is the one image with no source here: it is the built page's `.fold` element captured in dark mode against a local `web/` preview, since `canon capture` takes no color scheme and the page follows the browser's default of light, so it is retaken by hand when the page's first screen changes.
|
|
24
|
-
|
|
25
|
-
The README shows each still in two themes through `<picture>`, so a frame is a pair named `<name>` and `<name>-light`. `install` takes the light half from its template, which `regen-hero.ts` fills a second time with the plain color roles pointed at the light ones, and each half is its own capture set with its own stamp. `arrival-light.png` is the same `.fold` capture of the same address taken without forcing dark, so it is retaken by hand alongside `arrival.png`, and nothing catches one drifting from the other.
|
|
26
|
-
|
|
27
|
-
A stamp for a URL source digests the address string rather than the page it served, so two themes of one address carry one `source-sha256` and only `image-sha256` tells the frames apart. That holds for `examples/teach/evidence/root-listing-light.png`, which is retaken by serving a copy of the fixture with `data-theme="light"` on its `<html>` element at the same address, since the page follows the dark default and the command takes no scheme.
|
|
28
|
-
|
|
29
|
-
`assets/captures/` is read flat and never descends, by the regeneration script and by this command alike. A source nested a further folder down is skipped by both with nothing reported, so a new frame is a template dropped directly in rather than a folder of its own. The split is what retired the name prefix the flat layout used to need: a frame is named for itself now, since `assets/captures/` no longer mixes markup in with the images.
|
|
30
|
-
|
|
31
|
-
A branch is not asked whether the HTML is current. The PNG is a chromium render whose bytes move with the browser version, so the refresh workflow rebuilds it with `canon capture assets/captures --selector .window --out assets/frames` only when the regenerated HTML changed.
|
|
32
|
-
|
|
33
|
-
Every render writes a stamp beside its PNG, `hero.png` next to `hero.stamp`, holding the source filename, a `source-sha256` over the markup bytes it read, and an `image-sha256` over the image bytes it wrote. Both digests are what `bun run check` compares, so a markup edit committed without a capture and a PNG swapped under unchanged markup each fail. The stamp is tracked and commits alongside the pair. A capture that cannot write it reports that source as failed and exits 1, so an image whose stamp never landed is reported rather than passed over.
|
|
34
|
-
|
|
35
|
-
Neither digest is ever written by hand. A digest is what the gate compares, so a hand-set one asserts agreement the tool never checked, and the way to move it is a capture. The `source:` line above them is the one field a rename may correct in place, since nothing reads it and the alternative is a stamp naming a file that no longer exists. Renaming a frame is the case that comes up, and the correction is the same basename the next capture would have written anyway.
|
|
36
|
-
|
|
37
|
-
| Option | Behavior |
|
|
38
|
-
| ------------------ | ------------------------------------------------------------------------------------------------------ |
|
|
39
|
-
| `--out <dir>` | Write every PNG here instead of beside its source. For a URL source, names the destination PNG itself. |
|
|
40
|
-
| `--selector <sel>` | Element to capture, required and never defaulted |
|
|
41
|
-
| `--width <px>` | Render at this viewport width so a media query resolves there. One whole number of 1 or more. |
|
|
42
|
-
|
|
43
|
-
## What the command asserts
|
|
44
|
-
|
|
45
|
-
Each source renders at `deviceScaleFactor` 2 with a transparent background, and the success line reports the pixel dimensions the element wrapped to. Size is reported and never asserted. The height of a terminal frame is whatever its text wrapped to at a fixed width, so pinning that number would harden an accident.
|
|
46
|
-
|
|
47
|
-
What is asserted is the font. The command reads the first family of each rendered element holding text inside the captured element, and fails when the browser did not resolve one of them, because a fallback face rewraps the block and silently changes the output. A generic keyword as the first family, such as `monospace` or `system-ui`, also fails with its own reason, since it resolves to a different font on each machine, though a quoted `"monospace"` is a family name and goes through the probe. An element holding no text skips the check, since there is nothing to rewrap. Sources therefore name a real font rather than relying on `monospace`. A source that cannot render reports its own line and exits 1 without dropping the rest of the batch.
|
|
48
|
-
|
|
49
|
-
The user agent sets `monospace` on `pre`, `code`, `kbd`, and `samp` and does not inherit the `body` font into them, so each needs its own `font-family`.
|
|
50
|
-
|
|
51
|
-
A run refuses before it reads anything else when `--selector` is absent, naming the flag and pointing at `--help`. Ordering it first is what keeps the message about the invocation: the source defaults to `assets`, so checking that first would answer `assets not found` from whatever directory the caller happened to be in and say nothing about the flag that was actually missing. That source default is a deliberate choice rather than one inherited from some general convention: a missing folder still refuses loud, naming the argument, once the flag check passes, where the selector's dropped default cropped the wrong region in silence.
|
|
52
|
-
|
|
53
|
-
The browser binary installs separately from the package. A first run does `bunx playwright install chromium` once, and a run that cannot launch one reports the engine's own remediation inside the frame and exits 1 rather than escaping as a stack trace.
|
|
54
|
-
|
|
55
|
-
The command ships to targets, alongside `demo`, `inventory`, and `drive`. It was held back while its only caller was this repository regenerating its own committed images, which described the caller rather than the render. A project has generated pages of its own, and the command that would show them rendering and prove their fonts resolved was the one it could not run.
|
|
56
|
-
|
|
57
|
-
Shipping it also fixed what the exclusion was hiding. The render module imported the `@playwright/test` development dependency, which no published tarball carries. Every browser reference still sits behind a dynamic import, so a browser loads for this command rather than in front of every other one.
|
|
58
|
-
|
|
59
|
-
`demo.md` and `driver.md` cover two of the other three browser commands. What separates this one is that a capture renders a single state, from a file on disk or a named `http(s)://` URL, where the rest drive a running application.
|
|
60
|
-
|
|
61
|
-
## Capturing at a width
|
|
62
|
-
|
|
63
|
-
`--width` sets the browser viewport and leaves the page alone. A media query answers to the viewport, so a wrapper narrowed to 390px renders a thin column of the desktop layout and proves nothing about the mobile one. The height stays at Playwright's default of 720, which keeps `vh` units where they are without the flag. A run that passes no `--width` passes no viewport option at all, so every committed image renders as before and no stamp digest moves.
|
|
64
|
-
|
|
65
|
-
The flag takes one integer and no list. A sweep across breakpoints is one run per width, and the caller picks `--out` for each, since two widths written into one directory overwrite each other under the source's name. A value that is not a whole number of 1 or more refuses ahead of the browser import, naming the flag.
|
package/docs/agents/census.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Census
|
|
3
|
-
description: Tracked-plus-untracked file count, a breakdown by extension, and a line total that skips whatever reads as binary
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Census
|
|
7
|
-
|
|
8
|
-
`canon census [path]` reports how large a tree is: the tracked-plus-untracked file count, a breakdown by extension, and a line total. It reads `listRepositoryFiles`, the same corpus the citation check, the markdown corpus, and the secret scan already read, so this is not a fourth definition of what counts.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
canon census
|
|
12
|
-
canon census src --json
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
| Option | Behavior |
|
|
16
|
-
| -------- | ---------------------------------------------------------- |
|
|
17
|
-
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
18
|
-
|
|
19
|
-
Grouping is by extension rather than by a named language category. A config file and a source file land in separate buckets and two source files sharing an extension land in one, and a file with no extension, such as `Dockerfile`, lands under `no-extension`.
|
|
20
|
-
|
|
21
|
-
Line counts are text-only. A file that reads as binary, and a file git lists that will not open, such as a symlink leaving the tree, are counted toward the file total and their extension's file count, and left out of every line count. The record's `skipped` field states that gap rather than leaving a reader to infer it from the difference between the file count and the summed extension line counts. It carries both causes as one number: on a healthy tree the two are indistinguishable, so a `skipped` count above what the tree's own binary files explain is itself the signal that something in the corpus will not open.
|
|
22
|
-
|
|
23
|
-
The command reports a snapshot rather than a delta. It registers in the audit catalog with an empty gating set, so `canon audits run --record` is what turns two snapshots into the growth series a hand count used to approximate: 481 files on one date and 965 five weeks later, with nothing between them because nobody had counted again.
|
package/docs/agents/commands.md
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Command catalog
|
|
3
|
-
description: Every top-level command with its purpose, each domain's subcommands and the page describing them, the browser commands, and the version skew report
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Command catalog
|
|
7
|
-
|
|
8
|
-
Bare `canon --help` lists every top-level command under five headings, Project, Domains, Author and render, Session and ship, and Repo reports, with descriptions cut at 80 columns. A pipe gets the same text without the frame glyphs. Behavior notes for the install and sync verbs live in `install-and-sync.md`.
|
|
9
|
-
|
|
10
|
-
`canon <command> --help` lists subcommands, and `canon <command> <subcommand> --help` a leaf's flags, exit codes, and examples. `canon <command> --help --all` prints both. An unknown subcommand exits 1 under a group taking no operand.
|
|
11
|
-
|
|
12
|
-
## Project-level
|
|
13
|
-
|
|
14
|
-
One row per top-level command, in the order `canon --help` prints them. A domain's subcommands are in `## Domain commands` below.
|
|
15
|
-
|
|
16
|
-
| Command | Purpose |
|
|
17
|
-
| --------------------------- | ------------------------------------------------------------------------------------------ |
|
|
18
|
-
| `canon init [path]` | Bootstrap a project with selected toolkit domains |
|
|
19
|
-
| `canon sync [path]` | Sync every installed domain, or report drift and version skew with `--check` |
|
|
20
|
-
| `canon upgrade` | Reinstall the CLI globally with the package manager the install path names |
|
|
21
|
-
| `canon migrate <verb>` | Move a project off a retired name or layout, reporting the plan until `--write` |
|
|
22
|
-
| `canon targets <verb>` | Report the projects this toolkit installed into |
|
|
23
|
-
| `canon gov <verb>` | Install and sync governance rules, and audit the tree against them |
|
|
24
|
-
| `canon tooling <verb>` | Sync, diff, and verify tooling stacks |
|
|
25
|
-
| `canon claude <verb>` | Install the Claude workflow and audit both skill corpora |
|
|
26
|
-
| `canon wiki <verb>` | Scaffold the wiki pages |
|
|
27
|
-
| `canon indexes <verb>` | Regenerate `index.md` files from sibling frontmatter, or flatten them |
|
|
28
|
-
| `canon docs [topic]` | Emit toolkit reference docs (`list`, or a topic by name) |
|
|
29
|
-
| `canon design <verb>` | Render or regenerate `canon/DESIGN.md` tokens, emit their CSS, install the base stylesheet |
|
|
30
|
-
| `canon slides <verb>` | Render a deck folder of HTML slides, or list the decks |
|
|
31
|
-
| `canon capture [source]` | Render HTML or a URL to PNG and prove each declared font resolved |
|
|
32
|
-
| `canon serve [dir]` | Serve a directory on loopback and print the link that opens it |
|
|
33
|
-
| `canon demo <verb>` | Compile and record a running app |
|
|
34
|
-
| `canon inventory [subject]` | Group every route's elements by one computed property, never gating |
|
|
35
|
-
| `canon drive <url> <run>` | Walk a page through named interactions and measure each state |
|
|
36
|
-
| `canon transcripts <url>` | Fetch a YouTube transcript with metadata frontmatter (needs `yt-dlp`) |
|
|
37
|
-
| `canon teach <verb>` | Open and author learning workspaces |
|
|
38
|
-
| `canon canvas <verb>` | Serve a local canvas of pages and HTML frames, arrange, edit, and capture them |
|
|
39
|
-
| `canon sandbox [cat:cmd]` | Run sandbox scenarios, toolkit-only like the tree it reads |
|
|
40
|
-
| `canon tasks <verb>` | Read and write the task board, the plans it cites, and its archive |
|
|
41
|
-
| `canon intake <verb>` | Report intake folders and write answers into them |
|
|
42
|
-
| `canon records <verb>` | Validate, size, prune, and back up the session records |
|
|
43
|
-
| `canon sessions <verb>` | Resolve live sessions to worktree and branch, and move one between machines |
|
|
44
|
-
| `canon worktrees <verb>` | Report and remove worktrees whose pull request merged |
|
|
45
|
-
| `canon hooks <verb>` | Run the steps a git hook drives |
|
|
46
|
-
| `canon pr <verb>` | Read a pull request's diff, head, checks, and review, and post its evidence |
|
|
47
|
-
| `canon feedback` | Open a GitHub issue from toolkit feedback on stdin, or print the block on failure |
|
|
48
|
-
| `canon audits <verb>` | Run every audit as one set under one verdict against the recorded baseline |
|
|
49
|
-
| `canon gate <verb>` | Run every stage that guards a branch here |
|
|
50
|
-
| `canon secrets <verb>` | Report credential-shaped values in the tree the package ships |
|
|
51
|
-
| `canon deps <verb>` | Report published advisories against the resolved dependency set |
|
|
52
|
-
| `canon labels <verb>` | Read a changed set against the label map, and scan pull request text |
|
|
53
|
-
| `canon comments <verb>` | Measure comment density by language and kind, with a trend from git |
|
|
54
|
-
| `canon context <verb>` | Report context folder health, and classify changed or stale sections |
|
|
55
|
-
| `canon markdown <verb>` | Fail markdown on a banned character or a dead link, and report its structure |
|
|
56
|
-
| `canon census [path]` | Report tracked file count, extensions, and a line total skipping binaries |
|
|
57
|
-
| `canon upstream <verb>` | Read Claude Code releases from a cursor, and list the toolkit's own mechanisms |
|
|
58
|
-
|
|
59
|
-
`canon serve` drives no browser, which is what separates it from the four that do. All four ship now that `capture` does, so the line between them is the engine rather than the package. A generated page loses its script to an editor preview and to a `file://` open, so the link is the delivery rather than a convenience, and every generated surface here reaches a reader through one. A teach lesson's stylesheet is embedded rather than linked, so only its script still needs a server. It binds `127.0.0.1` and never a wildcard, because what it is pointed at is routinely a gitignored record tree. It sends `cache-control: no-store`, since a preview exists to be edited and reloaded and a cached stylesheet reads as a fix that did not work.
|
|
60
|
-
|
|
61
|
-
A port already in use is the ordinary case rather than a refusal, so it walks forward to the next free one and reports which it took. That is why a caller reads `url` off the `--json` record instead of composing one from the port it asked for. Only contention is walked past. Any other bind failure refuses as `bind-failed` carrying the error's code, rather than being retried twenty times and reported as a range being full, which names a cause nothing checked.
|
|
62
|
-
|
|
63
|
-
A request naming a directory is redirected to its trailing-slash form rather than answered in place. A browser resolves a relative asset against the last slash of the URL it is on, so answering `/lesson` directly leaves the page asking for `/course.css` instead of `/lesson/course.css`, and it renders unstyled through the server that exists to prevent exactly that.
|
|
64
|
-
|
|
65
|
-
Containment is tested after symlinks are followed rather than on the path as written, and the test sits immediately before the read rather than beside the request that produced it. Resolving a request lexically clears a link pointing outside the served root, and a link out of the served root is the shape it guards against. Position is what makes the property hold: a directory request appends its index after the request path has been checked, so a check placed earlier leaves that index untested. `--index` answers a directory holding no `index.html` with a listing read per request, where the default stays a 404. Every entry the listing names takes the same containment test a request for it would, so a link out of the root is absent rather than greyed, and dotfiles are hidden. With no `--entry` and no root `index.html`, the printed link is `/` and `entryExists` reads true. An `--entry` that escapes the root refuses with `no-entry` before a port is taken, because `url` is the field a caller hands to a reader.
|
|
66
|
-
|
|
67
|
-
`canon demo` is the second browser command and the one that ships, since its purpose is running in a target rather than regenerating what this repository commits. It needs a browser binary the package does not carry, installed once with `bunx playwright install chromium`.
|
|
68
|
-
|
|
69
|
-
`canon inventory` is the third and takes the same answer for the same reason. It reads `inventory.toml` at the project root for its base URL, its routes, and the element query each subject runs over, so what it walks comes from the project rather than from the toolkit. It reports how many different answers a site gives for one property and never gates, because whether five focus rings across four routes is a defect is a judgment. A missing server and an unmatched query are both refusals rather than empty listings, since a listing with no rows reads as one consistent answer.
|
|
70
|
-
|
|
71
|
-
```toml
|
|
72
|
-
base-url = "http://localhost:4173"
|
|
73
|
-
routes = ["/", "/pricing", "/docs"]
|
|
74
|
-
|
|
75
|
-
[subjects.focus]
|
|
76
|
-
query = "button, a[href], input, select, textarea, [tabindex]"
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
`canon drive` is the fourth and ships for the same reason the three before it do. What separates it from all three is the axis rather than the destination: `capture` and `inventory` each answer about a page as it loads, and every defect that exists only after a menu opens or the page scrolls is invisible to both. It takes a JSON run file naming the viewport, the probes, and the interaction sequence, since a route catalog is state a project holds and an interaction sequence is a script written for one question. Viewport heights are never defaulted, because the heights a defect hides at belong to the layout rather than to this command. It reports findings and never gates, since every probe it ships carries a class of false finding a throwaway version already produced. See `driver.md`.
|
|
80
|
-
|
|
81
|
-
## Domain commands
|
|
82
|
-
|
|
83
|
-
Each domain exposes a consistent shape where applicable: `list`, `install`, `sync`, `create`. The page named beside a domain carries its flags, records, and refusals, and `canon <domain> --help --all` prints every subcommand's flags.
|
|
84
|
-
|
|
85
|
-
- **`migrate`**, in `migrate.md`: `rename`, `skill-names`, `records`, `surface-roots`, `record-tree`, `rule-layout`, `scratch-evidence`, `record-layout`
|
|
86
|
-
- **`targets`**, in `targets.md`: `list`, `pulls`
|
|
87
|
-
- **`gov`**, in `install-and-sync.md`: `list`, `install`, `sync`, `build`, `regen`, `detect` (in `gov-detect.md`), `test-order`, `counts`, `superseded`, `citations`, `restated`
|
|
88
|
-
- **`tooling`**, in `install-and-sync.md`: `list`, `sync`, `diff`, `reference`, `verify`, `inject`, `prune-gitignore`
|
|
89
|
-
- **`claude`**, in `skills-audit.md`: `init`, `sync`, `setup`, `routing`, `plugin-update`, `seeds list`, `skills list`, `skills audit`, `skills drift`, `skills reach`, `skills rank`
|
|
90
|
-
- **`wiki`**, in `scripting.md`: `init`
|
|
91
|
-
- **`indexes`**, in `indexes.md`: `regen`, `list`
|
|
92
|
-
- **`docs`**, in `docs.md`: `list`, `<topic>`
|
|
93
|
-
- **`design`**, in `install-and-sync.md` for `install`, `sync`, and `fonts`, and below for the rest: `render`, `regen`, `css`, `install`, `sync`, `fonts`
|
|
94
|
-
- **`slides`**, described below: `render`, `list`
|
|
95
|
-
- **`demo`**, in `demo.md`: `compile`, `run`, `frames`
|
|
96
|
-
- **`inventory`**, described above: `run`
|
|
97
|
-
- **`teach`**, in `teach.md`: `list`, `up`, `open`, `resource`, `glossary`, `lesson`, `stylesheet`, `nav`, `render`
|
|
98
|
-
- **`canvas`**, described below: `serve`, `list`, `page add`, `page rename`, `frame add`, `frame move`, `frame resize`, `fit`, `arrange`, `selection`, `edit`, `editing`, `capture`
|
|
99
|
-
- **`sandbox`**, in `sandbox.md`: `run`, `equivalence`, `reset`, `clean`, `check`, `coverage`
|
|
100
|
-
- **`tasks`**, in `tasks.md`: `next-label`, `archive`, `decline`, `plan-citations`, `plan-answers`, `plan-branch`, `plan-reach`, `plan-link`, `pull-request`, `outcome`, `list`, `validate`
|
|
101
|
-
- **`intake`**, in `intake.md`: `list`, `answer`
|
|
102
|
-
- **`records`**, in `records.md`: `validate`, `ordinal`, `size`, `stale`, `prune-tmp`, `push`, `pull`
|
|
103
|
-
- **`sessions`**, in `sessions.md`: `list`, `export`, `import`
|
|
104
|
-
- **`worktrees`**, in `worktrees.md`: `list`, `reclaim`, `repair-bare-flag` (hidden)
|
|
105
|
-
- **`hooks`**, in `hooks.md`: `post-merge`
|
|
106
|
-
- **`pr`**, in `pr-reads.md`: `key-changes`, `head`, `checks`, `review-state`, `evidence`, `preview`, `local`, `frames`, `lift` (in `pr-lift.md`), `tick` (in `pr-tick.md`)
|
|
107
|
-
- **`upstream`**, in `upstream.md`: `fetch`, `catalog`, `due`, `advance`
|
|
108
|
-
- **`audits`**, in `audits.md`: `run`, `list`
|
|
109
|
-
- **`gate`**, in `gate.md`: `run`
|
|
110
|
-
- **`secrets`**, in `state-scoped-risk.md`: `scan`
|
|
111
|
-
- **`deps`**, in `state-scoped-risk.md`: `audit`
|
|
112
|
-
- **`labels`**, in `label-coverage.md`: `audit`, `apply`, `scan`
|
|
113
|
-
- **`comments`**, in `comments.md`: `scan`
|
|
114
|
-
- **`context`**, in `context-audit.md`: `audit`, `classify diff`, `classify sweep`, `classifier show`, `classifier set`
|
|
115
|
-
- **`markdown`**, in `markdown-audit.md`: `audit`
|
|
116
|
-
|
|
117
|
-
Common patterns:
|
|
118
|
-
|
|
119
|
-
- **`list --json`** → machine-readable catalog on stdout.
|
|
120
|
-
- **`install <name> <path>`** → install a specific entry into a target project.
|
|
121
|
-
- **`sync <path>`** → reapply all installed entries in a target project.
|
|
122
|
-
- **`create [name]`** → scaffold a new authoring entry in this repo.
|
|
123
|
-
|
|
124
|
-
Subcommands no other page describes:
|
|
125
|
-
|
|
126
|
-
- **`claude plugin-update`** matches the installed marketplace plugin against `claude/.claude-plugin/plugin.json`'s own name and runs `claude plugin update` on it, reading the version back off `claude plugin list --json`, since the update call reports none of its own (`--json`).
|
|
127
|
-
- **`claude skills rank`** scores either skill corpus's descriptions against a case corpus by TF-IDF cosine similarity, reporting rank-one and top-three (`--cases <path>`).
|
|
128
|
-
- **`design regen`** rewrites this repository's `canon/DESIGN.md` from `src/design/tokens.ts` and `src/design/base.css` from `src/design/neutral.ts`. `design css` emits the tokens and components as CSS on stdout, with `--no-components` for properties alone, and `design render` declares each vendored face the typography table names under `--embed-fonts`.
|
|
129
|
-
- **`slides list --json`** emits one row per deck under `.canon/slides/`, carrying `name`, `title`, `slides`, and `path`.
|
|
130
|
-
- **`slides render [deck]`** takes a deck name or a folder, defaulting to the only deck, and lays out each `.html` file in filename order in Chromium at 1280 by 720 and rebuilds it as editable shapes. Each element drawn as a picture prints one `✗` line on stderr naming the slide, the selector, and the properties that forced it. A link left out, being a `#slide-N` past the deck's end or any target that is neither that nor an absolute URL, prints one too, and the exit stays 0.
|
|
131
|
-
- **`slides.md`** describes a deck folder's `deck.json` and the faces it embeds, its per-slide `<body>` attributes, transitions and entrances, speaker notes, and charts.
|
|
132
|
-
- **`canvas`**, with its verbs, content format, and write routes, is described in `canvas.md`.
|
|
133
|
-
- **`labels apply <number>`** adds the labels this branch earns to its open pull request, refusing a pull request whose head is not the current branch or that is not open, and never creating a label the remote lacks or removing one a person added (`--check` writes nothing and exits 2 when labels are owed, `--base`, `--json`).
|
|
134
|
-
- **`labels scan`** fails a pull request or a posted review whose title, body, or review comment carries a phase label, a label a code span quotes, a gitignored record path, a session link, a banned character, a body heading outside the closed section list or a missing `## Summary` or `## Key changes`, or a title breaking `claude/skills/git-pr/references/pr.md`'s format, casing, or length rule (`--event`, `--body-file`, `--json`).
|
|
135
|
-
|
|
136
|
-
## Version skew
|
|
137
|
-
|
|
138
|
-
`canon sync --check` and `canon claude skills drift` are the two moments a
|
|
139
|
-
target already stops to reconcile with the toolkit, so each reports the
|
|
140
|
-
installed version against the newest published one. No other command performs
|
|
141
|
-
the lookup, which keeps a registry round trip out of the catalog reads an agent
|
|
142
|
-
runs in a loop.
|
|
143
|
-
|
|
144
|
-
The report carries three states and never changes an exit code. `behind` names
|
|
145
|
-
`canon upgrade` as the remedy, `current` says so, and `unknown` carries the
|
|
146
|
-
reason the registry could not be reached. Branch on the `skew.state` field in
|
|
147
|
-
the JSON record rather than on the exit, since an offline machine has to read as
|
|
148
|
-
unmeasured rather than as a failing check.
|
|
149
|
-
|
|
150
|
-
`canon upgrade --json` carries one further state, `pending`, that the skew
|
|
151
|
-
report does not: the working directory's checkout holds a release npm does not
|
|
152
|
-
serve yet, so there is nothing to install. The record names it in `checkout`
|
|
153
|
-
beside `latest`, exits 0, and its `message` starts `CLI stays at`. Outside a
|
|
154
|
-
canon checkout it never reads `pending`.
|
package/docs/agents/comments.md
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Comments
|
|
3
|
-
description: Comment density by language and kind, the two structural exclusions, and how the degradation sweep finds its vocabulary
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Comments
|
|
7
|
-
|
|
8
|
-
`canon comments scan [path]` reports comment density for a tree, split by language and by comment kind. It is the only command that parses the target's own source, so its scope stays deliberately narrow: TypeScript and bash, line-oriented, no AST.
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
canon comments scan
|
|
12
|
-
canon comments scan src --json
|
|
13
|
-
canon comments scan --since v0.5.0
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
| Option | Behavior |
|
|
17
|
-
| -------------------- | --------------------------------------------------------------- |
|
|
18
|
-
| `--json` | Add a machine-readable record on stdout, keeping the frame |
|
|
19
|
-
| `--since <rev>` | Report the trend from this revision instead of a snapshot alone |
|
|
20
|
-
| `--languages <list>` | Comma-separated subset of `ts,sh` (default: both) |
|
|
21
|
-
|
|
22
|
-
A line counts as a comment when its first non-whitespace token opens one, which is what keeps a URL in a string literal from reading as a `//` comment without a parser. Density is `commentLines / lines`, reported and never graded. The command produces the number and a rule produces the judgment.
|
|
23
|
-
|
|
24
|
-
Two exclusions are structural rather than tuning. Heredoc bodies are dropped from both the numerator and the denominator, because a scenario script carrying markdown inside one has `#` opening a heading rather than a comment, which inflated a measured 112 comment lines to 427. Fixture trees are pruned by path segment for the same reason. The line-1 shebang is not a comment, since every script has one and counting it puts a floor under density that reports the file count.
|
|
25
|
-
|
|
26
|
-
`--since` recomputes each point from git via `ls-tree` and `cat-file --batch`, checking nothing out. No ledger is written or read. Six points spread evenly across the window by default, and the boundary revision is always included so the series keeps the reading it is measured against.
|
|
27
|
-
|
|
28
|
-
This works only because density is a pure function of a tree. Which author or session wrote a comment is not recoverable from git and does not belong here.
|
|
29
|
-
|
|
30
|
-
## Degradation sweep
|
|
31
|
-
|
|
32
|
-
The degradation sweep reads its vocabulary from whichever rule publishes a `## Degradation vocabulary` heading, preferring `.claude/rules/` over `governance/rules/`, so one definition serves the toolkit and every target. Discovery anchors on the heading rather than a filename, because a renamed rule would otherwise empty the vocabulary while the sweep still reported clean. With no such rule the sweep reports **skipped** rather than zero hits, since finding nothing and looking for nothing mean opposite things.
|
|
33
|
-
|
|
34
|
-
`090-code-comments` is the rule that publishes the list, and it ships on the `base` stack. A project that installs or syncs governance for the first time after that rule landed gets a sweep that previously reported skipped, so hits appear where the command used to stay quiet. Edit the backticked terms in the installed copy to change what that project sweeps for. The sweep matches comment text, so a comment naming a term as an example is a hit, and a hit is a prompt to read the line rather than a verdict on it.
|