@erclx/canon 5.43.0 → 5.45.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 +1 -1
- package/claude/.claude-plugin/plugin.json +1 -1
- package/claude/skills/backlog-triage/references/apply.md +6 -6
- package/claude/skills/canon-cli/SKILL.md +4 -5
- package/claude/skills/canvas-board/REQUIREMENT.md +1 -1
- package/claude/skills/canvas-board/SKILL.md +1 -1
- package/claude/skills/context-fold/references/context.md +1 -1
- package/claude/skills/create-skill/REQUIREMENT.md +1 -1
- package/claude/skills/create-skill/SKILL.md +2 -2
- package/claude/skills/create-skill/references/skill-requirement.md +68 -9
- package/claude/skills/create-skill/references/skill.md +1 -1
- package/claude/skills/design-identity/REQUIREMENT.md +40 -0
- package/claude/skills/design-identity/SKILL.md +138 -0
- package/claude/skills/{draft-identity → design-identity}/references/card-route.md +2 -2
- package/claude/skills/design-taste/REQUIREMENT.md +6 -6
- package/claude/skills/design-taste/SKILL.md +2 -2
- package/claude/skills/design-taste/references/kinds.md +1 -1
- package/claude/skills/design-taste/references/preflight.md +1 -1
- package/claude/skills/draft-and-pick/REQUIREMENT.md +8 -69
- package/claude/skills/draft-and-pick/SKILL.md +3 -153
- package/claude/skills/draft-doc/REQUIREMENT.md +9 -30
- package/claude/skills/draft-doc/SKILL.md +4 -76
- package/claude/skills/draft-figure/REQUIREMENT.md +8 -42
- package/claude/skills/draft-figure/SKILL.md +3 -77
- package/claude/skills/draft-identity/REQUIREMENT.md +8 -23
- package/claude/skills/draft-identity/SKILL.md +3 -130
- package/claude/skills/draft-ready/REQUIREMENT.md +8 -37
- package/claude/skills/draft-ready/SKILL.md +3 -128
- package/claude/skills/draft-screencast/REQUIREMENT.md +8 -23
- package/claude/skills/draft-screencast/SKILL.md +3 -62
- package/claude/skills/draft-slides/REQUIREMENT.md +8 -27
- package/claude/skills/draft-slides/SKILL.md +3 -72
- package/claude/skills/draw-figure/REQUIREMENT.md +59 -0
- package/claude/skills/draw-figure/SKILL.md +85 -0
- package/claude/skills/{draft-figure → draw-figure}/references/architecture-set.md +2 -2
- package/claude/skills/{draft-figure → draw-figure}/references/hand-drawn.md +2 -2
- package/claude/skills/{draft-figure → draw-figure}/references/mermaid-path.md +2 -2
- package/claude/skills/{draft-figure → draw-figure}/references/mermaid.md +1 -1
- package/claude/skills/make-deck/REQUIREMENT.md +44 -0
- package/claude/skills/make-deck/SKILL.md +80 -0
- package/claude/skills/markdown-craft/REQUIREMENT.md +1 -1
- package/claude/skills/markdown-craft/SKILL.md +2 -2
- package/claude/skills/pick-by-eye/REQUIREMENT.md +36 -0
- package/claude/skills/pick-by-eye/SKILL.md +161 -0
- package/claude/skills/plan-feature/SKILL.md +2 -1
- package/claude/skills/plan-feature/references/plan.md +24 -10
- package/claude/skills/plan-groundwork/SKILL.md +1 -1
- package/claude/skills/plan-intake/SKILL.md +1 -1
- package/claude/skills/plan-ready/REQUIREMENT.md +54 -0
- package/claude/skills/plan-ready/SKILL.md +136 -0
- package/claude/skills/{draft-ready → plan-ready}/references/assembly.md +1 -1
- package/claude/skills/{draft-ready → plan-ready}/references/ready.md +1 -1
- package/claude/skills/record-screencast/REQUIREMENT.md +3 -3
- package/claude/skills/record-screencast/SKILL.md +2 -2
- package/claude/skills/role-orchestrator/REQUIREMENT.md +16 -99
- package/claude/skills/role-orchestrator/references/orchestrator-dispatch.md +5 -2
- package/claude/skills/role-orchestrator/references/orchestrator-parked.md +2 -2
- package/claude/skills/role-orchestrator/references/orchestrator-refill.md +18 -13
- package/claude/skills/role-planner/REQUIREMENT.md +15 -73
- package/claude/skills/role-planner/SKILL.md +2 -1
- package/claude/skills/role-worker/REQUIREMENT.md +13 -41
- package/claude/skills/role-worker/SKILL.md +9 -0
- package/claude/skills/script-screencast/REQUIREMENT.md +40 -0
- package/claude/skills/script-screencast/SKILL.md +70 -0
- package/claude/skills/{draft-screencast → script-screencast}/references/beats-template.md +2 -2
- package/claude/skills/search-craft/REQUIREMENT.md +4 -4
- package/claude/skills/search-craft/SKILL.md +1 -1
- package/claude/skills/target-setup/SKILL.md +3 -2
- package/claude/skills/target-setup/references/detect.md +0 -1
- package/claude/skills/target-setup/references/verify.md +2 -2
- package/claude/skills/task-board/SKILL.md +11 -9
- package/claude/skills/task-board/references/board.md +15 -12
- package/claude/skills/teach-workspace/REQUIREMENT.md +1 -1
- package/claude/skills/teach-workspace/SKILL.md +1 -1
- package/claude/skills/teach-workspace/references/lesson-craft.md +2 -2
- package/claude/skills/teach-workspace/references/promotion.md +5 -5
- package/claude/skills/ui-checklist/SKILL.md +2 -0
- package/claude/skills/write-doc/REQUIREMENT.md +46 -0
- package/claude/skills/write-doc/SKILL.md +83 -0
- package/claude/skills/{draft-doc → write-doc}/references/context.md +2 -2
- package/claude/skills/{draft-doc → write-doc}/references/docs.md +2 -2
- package/claude/skills/{draft-doc → write-doc}/references/readme.md +2 -2
- package/claude/skills/{draft-doc → write-doc}/references/wiki-kind.md +3 -3
- package/docs/agents/install-and-sync.md +2 -2
- package/docs/agents/markdown-audit.md +4 -2
- package/docs/agents/migrate.md +2 -2
- package/docs/agents/output-shape.md +1 -2
- package/docs/target/migrations.md +35 -4
- package/docs/target/projects.md +2 -3
- package/docs/target/scenarios.md +4 -1
- package/docs/workflow/parallel-features.md +3 -2
- package/docs/workflow/skill-map-on-request.md +19 -13
- package/docs/workflow/skill-map.md +13 -12
- package/docs/workflow/visual-design-workflow.md +2 -2
- package/governance/detect.toml +4 -0
- package/governance/ledger/framework/astro.md +73 -0
- package/governance/ledger/framework/fastapi.md +76 -0
- package/governance/ledger/framework/nextjs.md +86 -0
- package/governance/ledger/framework/react.md +83 -0
- package/governance/ledger/framework/shadcn.md +60 -0
- package/governance/ledger/framework/tailwind.md +55 -0
- package/governance/ledger/lang/go.md +61 -0
- package/governance/ledger/lang/php.md +50 -0
- package/governance/ledger/lang/python.md +68 -0
- package/governance/ledger/lang/typescript.md +64 -0
- package/governance/ledger/lib/database.md +65 -0
- package/governance/ledger/lib/e2e-reliability.md +57 -0
- package/governance/ledger/lib/pydantic.md +61 -0
- package/governance/ledger/lib/security-server.md +62 -0
- package/governance/ledger/lib/security-web.md +51 -0
- package/governance/ledger/lib/tanstack-query.md +57 -0
- package/governance/ledger/lib/test-scope.md +43 -0
- package/governance/ledger/lib/testing-go.md +57 -0
- package/governance/ledger/lib/testing-php.md +51 -0
- package/governance/ledger/lib/testing-py.md +67 -0
- package/governance/ledger/lib/testing-ts.md +63 -0
- package/governance/ledger/lib/zod.md +47 -0
- package/governance/ledger/tooling/ci-workflow.md +33 -0
- package/governance/ledger/tooling/code-comments.md +48 -0
- package/governance/ledger/tooling/config-comments.md +27 -0
- package/governance/ledger/tooling/dependencies.md +38 -0
- package/governance/ledger/ui/a11y.md +55 -0
- package/governance/ledger/ui/copy.md +49 -0
- package/governance/ledger/ui/design-reference.md +42 -0
- package/governance/ledger/ui/design-taste.md +19 -0
- package/governance/ledger/ui/forms.md +71 -0
- package/governance/ledger/ui/interface-casing.md +47 -0
- package/governance/ledger/ui/keyboard.md +68 -0
- package/governance/ledger/ui/link-behavior.md +29 -0
- package/governance/ledger/ui/motion.md +33 -0
- package/governance/ledger/ui/surface-capture.md +69 -0
- package/governance/ledger/ui/ux-completeness.md +79 -0
- package/governance/rules/framework/astro.md +12 -14
- package/governance/rules/framework/fastapi.md +20 -24
- package/governance/rules/framework/nextjs.md +19 -27
- package/governance/rules/framework/react.md +22 -33
- package/governance/rules/framework/shadcn.md +11 -15
- package/governance/rules/framework/tailwind.md +12 -14
- package/governance/rules/lang/go.md +7 -16
- package/governance/rules/lang/php.md +3 -3
- package/governance/rules/lang/python.md +9 -18
- package/governance/rules/lang/typescript.md +9 -19
- package/governance/rules/lib/database.md +5 -5
- package/governance/rules/lib/e2e-reliability.md +4 -6
- package/governance/rules/lib/pydantic.md +14 -16
- package/governance/rules/lib/security-server.md +4 -4
- package/governance/rules/lib/security-web.md +6 -10
- package/governance/rules/lib/tanstack-query.md +10 -12
- package/governance/rules/lib/test-scope.md +4 -4
- package/governance/rules/lib/testing-go.md +1 -2
- package/governance/rules/lib/testing-php.md +4 -5
- package/governance/rules/lib/testing-py.md +11 -19
- package/governance/rules/lib/testing-ts.md +7 -16
- package/governance/rules/lib/zod.md +6 -8
- package/governance/rules/tooling/code-comments.md +2 -4
- package/governance/rules/tooling/config-comments.md +1 -4
- package/governance/rules/tooling/dependencies.md +1 -1
- package/governance/rules/ui/a11y.md +16 -45
- package/governance/rules/ui/copy.md +6 -9
- package/governance/rules/ui/forms.md +13 -19
- package/governance/rules/ui/interface-casing.md +5 -7
- package/governance/rules/ui/keyboard.md +38 -0
- package/governance/rules/ui/link-behavior.md +3 -3
- package/governance/rules/ui/motion.md +3 -3
- package/governance/rules/ui/surface-capture.md +15 -27
- package/governance/rules/ui/ux-completeness.md +16 -39
- package/governance/rules/writing/markdown.md +1 -1
- package/package.json +1 -1
- package/scripts/core/install-check.sh +1 -1
- package/src/claude/cases/authoring.ts +15 -3
- package/src/claude/cases/misc.ts +12 -0
- package/src/claude/cases/workflow.ts +19 -1
- package/src/claude/skills-audit.ts +113 -1
- package/src/cli/help.ts +0 -1
- package/src/cli.ts +0 -2
- package/src/commands/claude.ts +34 -11
- package/src/commands/demo.ts +1 -1
- package/src/commands/gov.ts +4 -0
- package/src/commands/init.ts +2 -2
- package/src/commands/markdown.ts +1 -1
- package/src/commands/migrate.ts +4 -0
- package/src/commands/pr.ts +30 -6
- package/src/commands/tasks.ts +383 -2
- package/src/commands/tooling.ts +18 -5
- package/src/context/audit.ts +1 -1
- package/src/demo/beats.ts +1 -1
- package/src/design/components.ts +1 -1
- package/src/gov/audit.ts +25 -4
- package/src/init/plan.ts +1 -8
- package/src/init/steps.ts +0 -8
- package/src/inventory/subjects.ts +1 -1
- package/src/markdown/scope.ts +49 -35
- package/src/migrate/record-layout.ts +1 -1
- package/src/migrate/scratch-evidence.ts +12 -4
- package/src/migrate/skill-names.ts +68 -21
- package/src/pr/frames.ts +14 -3
- package/src/records/backup.ts +3 -3
- package/src/records/validate.ts +31 -0
- package/src/roots/record.ts +17 -8
- package/src/tasks/board.ts +854 -0
- package/src/tasks/record.ts +20 -1
- package/src/tasks/validate.ts +206 -9
- package/src/tooling/inject.ts +26 -7
- package/src/tooling/package.ts +32 -0
- package/src/tooling/read.ts +46 -3
- package/src/tooling/scan.ts +8 -2
- package/tooling/astro/configs/card-src/pages/og-card.astro +1 -1
- package/tooling/astro/reference.md +64 -93
- package/tooling/base/configs/.github/workflows/phase-label-gate.yml +1 -1
- package/tooling/base/configs/scripts/verify.ts +1 -1
- package/tooling/base/reference.md +1 -9
- package/tooling/base/seeds/canon/context/{ci.md → development/ci.md} +1 -1
- package/tooling/base/seeds/canon/context/development/index.md +11 -0
- package/tooling/base/seeds/canon/context/{development.md → development/setup.md} +8 -12
- package/tooling/base/seeds/canon/context/index.md +1 -2
- package/tooling/claude/manifest.toml +1 -5
- package/tooling/claude/reference.md +36 -59
- package/tooling/claude/seeds/.claude/hooks/board-validate.sh +65 -0
- package/tooling/claude/seeds/.claude/hooks/index-reminder.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/pr-create-log.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/scratch-guard.sh +3 -10
- package/tooling/claude/seeds/.claude/hooks/search-reminder.sh +2 -7
- package/tooling/claude/seeds/.claude/hooks/standards-audit.sh +2 -4
- package/tooling/claude/seeds/.claude/settings.json +4 -0
- package/tooling/nextjs/reference.md +0 -6
- package/tooling/php/reference.md +0 -4
- package/tooling/web/configs/.github/workflows/verify.yml +28 -0
- package/tooling/web/configs/.oxlintrc.json +7 -0
- package/tooling/web/configs/e2e/capture-types.ts +35 -0
- package/tooling/web/configs/e2e/screenshot.ts +23 -72
- package/tooling/web/manifest.toml +1 -1
- package/tooling/web/reference.md +77 -124
- package/tooling/web/seeds/e2e/capture/cases.ts +47 -0
- package/src/commands/wiki.ts +0 -100
- package/src/wiki/init.ts +0 -85
- /package/claude/skills/{draft-figure → draw-figure}/references/figures.md +0 -0
- /package/claude/skills/{draft-slides → make-deck}/references/deck.md +0 -0
- /package/claude/skills/{draft-and-pick → pick-by-eye}/references/live-arms.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/agent-facing.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/application.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/cli.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/library.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/readme/plugin.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/requirements.md +0 -0
- /package/claude/skills/{draft-doc → write-doc}/references/wiki.md +0 -0
|
@@ -62,14 +62,13 @@ Discover names at runtime rather than hardcoding them.
|
|
|
62
62
|
Set `CANON_NON_INTERACTIVE=1` to refuse every prompt.
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
CANON_NON_INTERACTIVE=1 canon init --stack node --skip
|
|
65
|
+
CANON_NON_INTERACTIVE=1 canon init --stack node --skip records /path/to/project
|
|
66
66
|
CANON_NON_INTERACTIVE=1 canon sync /path/to/project
|
|
67
67
|
CANON_NON_INTERACTIVE=1 canon gov install node --add astro,shadcn /path/to/project
|
|
68
68
|
CANON_NON_INTERACTIVE=1 canon gov sync /path/to/project
|
|
69
69
|
CANON_NON_INTERACTIVE=1 canon gov build /path/to/project
|
|
70
70
|
CANON_NON_INTERACTIVE=1 canon tooling diff astro /path/to/project
|
|
71
71
|
CANON_NON_INTERACTIVE=1 canon tooling sync astro /path/to/project --write
|
|
72
|
-
CANON_NON_INTERACTIVE=1 canon wiki init /path/to/project
|
|
73
72
|
canon tooling inject base /path/to/project --configs --seeds
|
|
74
73
|
canon tooling prune-gitignore base /path/to/project
|
|
75
74
|
canon tooling verify vite-react
|
|
@@ -46,9 +46,22 @@ Run it once, ahead of `canon gov sync` or `canon gov install`.
|
|
|
46
46
|
|
|
47
47
|
## Rename the skill citations, once
|
|
48
48
|
|
|
49
|
-
Plugin skills dropped their `claude-` prefix, so `canon:claude-docs` answers as `canon:context-fold` and `canon:claude-tasks` as `canon:task-board`. The five per-kind drafters merged into `
|
|
49
|
+
Plugin skills dropped their `claude-` prefix, so `canon:claude-docs` answers as `canon:context-fold` and `canon:claude-tasks` as `canon:task-board`. The five per-kind drafters merged into `write-doc`, and no pointer under an old name ships. <!-- canon-keep-retired -->
|
|
50
|
+
|
|
51
|
+
The seven `draft-` skills took verb-first names for what each makes. `canon migrate skill-names --write` carries a project across, and a pointer under each old name answers a typed invocation until it retires.
|
|
52
|
+
|
|
53
|
+
| Old name | New name |
|
|
54
|
+
| ------------------ | ----------------------------------------------- |
|
|
55
|
+
| `draft-doc` | `write-doc` <!-- canon-keep-retired --> |
|
|
56
|
+
| `draft-figure` | `draw-figure` <!-- canon-keep-retired --> |
|
|
57
|
+
| `draft-identity` | `design-identity` <!-- canon-keep-retired --> |
|
|
58
|
+
| `draft-slides` | `make-deck` <!-- canon-keep-retired --> |
|
|
59
|
+
| `draft-and-pick` | `pick-by-eye` <!-- canon-keep-retired --> |
|
|
60
|
+
| `draft-ready` | `plan-ready` <!-- canon-keep-retired --> |
|
|
61
|
+
| `draft-screencast` | `script-screencast` <!-- canon-keep-retired --> |
|
|
50
62
|
|
|
51
63
|
- `canvas` is now `canvas-board`. The sweep rewrites only `canon:canvas` and `skills/canvas`, so replace a bare prose mention by hand. <!-- canon-keep-retired -->
|
|
64
|
+
- `draft-ready` is rewritten only as `canon:draft-ready` and `skills/draft-ready`, since bare it also describes a pull request. Replace a bare mention of the skill by hand. <!-- canon-keep-retired -->
|
|
52
65
|
- `design-extract` and `sketch-design` are replaced by `canon:canvas-board`. <!-- canon-keep-retired -->
|
|
53
66
|
- `review-branch`, `seed-sync`, `restate-plainly`, `bash-cli-script`, `canon-operator`, and `canon-rollout` have no successor <!-- canon-keep-retired -->
|
|
54
67
|
- `create-standard`, `markdown-propose`, `memory-review`, `project-commands`, `repo-metadata`, and `ux-walkthrough` have no successor <!-- canon-keep-retired -->
|
|
@@ -108,7 +121,7 @@ From the registry the walk reports `historyUnavailable`, so check both paths by
|
|
|
108
121
|
| `context-fold` | `context` |
|
|
109
122
|
| `canvas-board` | `canvas`, `design` |
|
|
110
123
|
| `docs-sync` | `docs`, `readme` |
|
|
111
|
-
| `
|
|
124
|
+
| `draw-figure` | `figures`, `mermaid` |
|
|
112
125
|
| `create-rule` | `rule` |
|
|
113
126
|
| `create-skill` | `skill`, `skill-paths`, `skill-practice`, `skill-requirement` |
|
|
114
127
|
| `git-branch` | `branch`, `slug` |
|
|
@@ -119,8 +132,8 @@ From the registry the walk reports `historyUnavailable`, so check both paths by
|
|
|
119
132
|
| `plan-groundwork` | `groundwork`, `groundwork-spikes` |
|
|
120
133
|
| `plan-intake` | `intake` |
|
|
121
134
|
| `plan-feature` | `plan`, `plan-lifecycle` |
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
135
|
+
| `plan-ready` | `ready` |
|
|
136
|
+
| `write-doc` | `requirements`, `wiki` |
|
|
124
137
|
| `session-map` | `session` |
|
|
125
138
|
|
|
126
139
|
The `standard` name became `skill-reference.md` in `create-skill`.
|
|
@@ -147,3 +160,21 @@ canon migrate session-defaults --write --json
|
|
|
147
160
|
```
|
|
148
161
|
|
|
149
162
|
The verb only adds a key that is absent. A person who wants auto memory back sets it in their own `.claude/settings.local.json`.
|
|
163
|
+
|
|
164
|
+
## Move the capture cases out of the harness, once
|
|
165
|
+
|
|
166
|
+
A web project's `e2e/screenshot.ts` is a config, so sync overwrites it. It now loads `CASES` from a seeded `e2e/capture/cases.ts` that sync copies once and never overwrites. Cases edited in the old harness leave the working tree on the first sync and stay in git history.
|
|
167
|
+
|
|
168
|
+
- Copy your cases from the old `e2e/screenshot.ts` into `e2e/capture/cases.ts` before the next sync.
|
|
169
|
+
- Evidence now defaults to `e2e/evidence/`. Set `export const EVIDENCE_ROOT = 'evidence'` in `e2e/capture/cases.ts` to keep a committed baseline at the old path.
|
|
170
|
+
- A run from a folder with no `e2e/capture/cases.ts` exits 1 and names the file.
|
|
171
|
+
|
|
172
|
+
## Add the keyboard rule beside a held a11y rule, once
|
|
173
|
+
|
|
174
|
+
The `a11y` rule split in two. Focus styles, Escape and shortcuts, composite widgets, focus management, and pointer target size moved to a new `keyboard` rule. `canon gov sync` refreshes only the rules a project holds, so it rewrites `a11y.md` without those bullets and never adds `keyboard.md`.
|
|
175
|
+
|
|
176
|
+
A project holding `.claude/rules/canon/ui/a11y.md` adds the new rule alone:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
canon gov install --add keyboard --yes .
|
|
180
|
+
```
|
package/docs/target/projects.md
CHANGED
|
@@ -57,7 +57,7 @@ Before the first feature session:
|
|
|
57
57
|
|
|
58
58
|
1. Fill `canon/REQUIREMENTS.md` with the problem, goals, and non-goals. The seed's 600-word cap gates under `canon context audit`.
|
|
59
59
|
2. For a UI project, write `canon/DESIGN.md` from the seed and name the stylesheet in its lead, or work the direction out with `canon:canvas-board`
|
|
60
|
-
3. Optionally invoke `canon:
|
|
60
|
+
3. Optionally invoke `canon:draw-figure` for an architecture view. The Mermaid CLI downloads on first use.
|
|
61
61
|
4. Start the feature loop in [AI workflow](../workflow/ai-workflow.md)
|
|
62
62
|
|
|
63
63
|
### Stack decision
|
|
@@ -70,10 +70,9 @@ The default is `base`. Escalate only for a project writing code, and `target-set
|
|
|
70
70
|
|
|
71
71
|
### Core domains and skips
|
|
72
72
|
|
|
73
|
-
`canon init` installs base tooling, the Claude workflow, and governance
|
|
73
|
+
`canon init` installs base tooling, the Claude workflow, and governance. Pass `--stack <name>` for a language stack.
|
|
74
74
|
|
|
75
75
|
- `--skip governance` leaves `.claude/rules/` empty. The run prints the `canon gov install <stack> <path>` command that restores the rules it dropped.
|
|
76
|
-
- `--skip wiki` skips the `.claude/wiki/` scaffold. A root `wiki/` is kept.
|
|
77
76
|
|
|
78
77
|
## Add a domain later
|
|
79
78
|
|
package/docs/target/scenarios.md
CHANGED
|
@@ -42,4 +42,7 @@ canon tooling sync python ./backend --skip base --write
|
|
|
42
42
|
|
|
43
43
|
`--skip base` keeps husky, oxfmt, commitlint, and CI at the root. Every subtree still receives `scripts/verify.ts` and `scripts/verify.json`, and its own framework configs.
|
|
44
44
|
|
|
45
|
-
A sync into a subfolder withholds `.github/`, so run the subtree from the root workflow with `working-directory` set to the path the sync prints.
|
|
45
|
+
A sync into a subfolder withholds `.github/`, so run the subtree from the root workflow with `working-directory` set to the path the sync prints. Run `bun scripts/verify.ts` in the subtree, since the `check` script lives at the root.
|
|
46
|
+
|
|
47
|
+
- A subtree with no `package.json` gets a minimal one holding the folder's name, version `0.0.0`, and `type: module`, then the install runs into it
|
|
48
|
+
- An existing file is never rewritten, and one that is not valid JSON ends the sync on `package.json is not valid JSON: fix it in <path>, then sync again`
|
|
@@ -49,13 +49,14 @@ Merge order matters only when two branches touch the same file. Expect to rebase
|
|
|
49
49
|
|
|
50
50
|
## The task board
|
|
51
51
|
|
|
52
|
-
`.canon/tasks/` is gitignored and resolves at the main worktree root, one file per task. A hook generates `index.md`, and `priority.md` carries execution order and blockers.
|
|
52
|
+
`.canon/tasks/` is gitignored and resolves at the main worktree root, one file per task. A hook generates `index.md`, and `priority.md` carries execution order and blockers. `canon tasks place`, `promote`, `move`, and `block` write it, deriving every cell but `Waiting on`.
|
|
53
53
|
|
|
54
54
|
`canon tasks validate` reports and never writes:
|
|
55
55
|
|
|
56
56
|
- A row's cell count must match its header, and a `## Needs a plan` row stating its position is checked against where it sits
|
|
57
57
|
- Every plan pointer resolves, every task file is named once, and every ready row names its files
|
|
58
|
-
- A parked row is reported when its cited task reached the trunk
|
|
58
|
+
- A parked row is reported when its cited task reached the trunk, whether the cell links it or names its bare label
|
|
59
|
+
- A group header must be the columns the group owns, a `Touches` cell must match its plan, and a `Waiting on` cell renders at most 120 characters
|
|
59
60
|
|
|
60
61
|
`canon:task-board` creates a task file, and `canon:task-complete` marks outcomes. The `post-merge` hook archives the task a merged pull request closed, with its plan, and a `post-rewrite` hook does the same for a rebase pull. Both archive only when the merge carried a PR number and the task is closed.
|
|
61
62
|
|
|
@@ -10,18 +10,24 @@ These skills serve a request rather than a moment. With the [skill map](skill-ma
|
|
|
10
10
|
|
|
11
11
|
## Generate an artifact on demand
|
|
12
12
|
|
|
13
|
-
| Skill | When to use
|
|
14
|
-
| ------------------------- |
|
|
15
|
-
| `canon:create-rule` | A project rule the toolkit does not ship
|
|
16
|
-
| `canon:create-skill` | A new `SKILL.md`
|
|
17
|
-
| `canon:
|
|
18
|
-
| `canon:draft-
|
|
19
|
-
| `canon:
|
|
20
|
-
| `canon:
|
|
21
|
-
| `canon:
|
|
22
|
-
| `canon:draft-
|
|
23
|
-
| `canon:
|
|
24
|
-
| `canon:
|
|
13
|
+
| Skill | When to use |
|
|
14
|
+
| ------------------------- | ---------------------------------------------------------------------------------- |
|
|
15
|
+
| `canon:create-rule` | A project rule the toolkit does not ship |
|
|
16
|
+
| `canon:create-skill` | A new `SKILL.md` |
|
|
17
|
+
| `canon:write-doc` | A new `docs/` page, context entry, or `README.md` |
|
|
18
|
+
| `canon:draft-doc` | Never on purpose. A pointer naming `write-doc` <!-- canon-keep-retired --> |
|
|
19
|
+
| `canon:plan-ready` | Finished files a worker should copy |
|
|
20
|
+
| `canon:draft-ready` | Never on purpose. A pointer naming `plan-ready` <!-- canon-keep-retired --> |
|
|
21
|
+
| `canon:draw-figure` | A figure or architecture view inside a doc |
|
|
22
|
+
| `canon:draft-figure` | Never on purpose. A pointer naming `draw-figure` <!-- canon-keep-retired --> |
|
|
23
|
+
| `canon:ci-workflow` | A GitHub Actions workflow file |
|
|
24
|
+
| `canon:make-deck` | A deck rendered to editable PowerPoint |
|
|
25
|
+
| `canon:draft-slides` | Never on purpose. A pointer naming `make-deck` <!-- canon-keep-retired --> |
|
|
26
|
+
| `canon:script-screencast` | A recording script with beats seeded |
|
|
27
|
+
| `canon:draft-screencast` | Never on purpose. A pointer naming `script-screencast` <!-- canon-keep-retired --> |
|
|
28
|
+
| `canon:record-screencast` | Recording a screencast draft into a finished mp4 |
|
|
29
|
+
| `canon:design-identity` | A logo mark and social card |
|
|
30
|
+
| `canon:draft-identity` | Never on purpose. A pointer naming `design-identity` <!-- canon-keep-retired --> |
|
|
25
31
|
|
|
26
32
|
## Answer a question at any point
|
|
27
33
|
|
|
@@ -34,4 +40,4 @@ These skills serve a request rather than a moment. With the [skill map](skill-ma
|
|
|
34
40
|
| `canon:markdown-craft` | Before a substantial markdown edit |
|
|
35
41
|
| `canon:write-human` | Before drafting or revising prose |
|
|
36
42
|
|
|
37
|
-
Ask `canon:teach-workspace` to promote a learning workspace's reference pages and glossaries. It proposes a destination per page and waits. An Anthropic-owned subject goes to the wiki, an internal one to the matching context entry, and the rest to the public docs. A project with no wiki folder gets a refusal naming
|
|
43
|
+
Ask `canon:teach-workspace` to promote a learning workspace's reference pages and glossaries. It proposes a destination per page and waits. An Anthropic-owned subject goes to the wiki, an internal one to the matching context entry, and the rest to the public docs. A project with no wiki folder gets a refusal naming the folder to create.
|
|
@@ -17,18 +17,19 @@ Groups run in the order a project meets them. Every name `canon claude skills li
|
|
|
17
17
|
|
|
18
18
|
## Decide what to build
|
|
19
19
|
|
|
20
|
-
| Skill | When to use
|
|
21
|
-
| -------------------------- |
|
|
22
|
-
| `canon:plan-intake` | The input is a pile of findings
|
|
23
|
-
| `canon:plan-intake-answer` | An intake folder holds unread slots
|
|
24
|
-
| `canon:backlog-triage` | The backlog needs pruning
|
|
25
|
-
| `canon:plan-groundwork` | The state is unmeasured and approaches compete
|
|
26
|
-
| `canon:decision-escalate` | Open decisions turn on your preference
|
|
27
|
-
| `canon:
|
|
28
|
-
| `canon:
|
|
29
|
-
| `canon:
|
|
30
|
-
| `canon:
|
|
31
|
-
| `canon:
|
|
20
|
+
| Skill | When to use |
|
|
21
|
+
| -------------------------- | ---------------------------------------------------------------------------- |
|
|
22
|
+
| `canon:plan-intake` | The input is a pile of findings |
|
|
23
|
+
| `canon:plan-intake-answer` | An intake folder holds unread slots |
|
|
24
|
+
| `canon:backlog-triage` | The backlog needs pruning |
|
|
25
|
+
| `canon:plan-groundwork` | The state is unmeasured and approaches compete |
|
|
26
|
+
| `canon:decision-escalate` | Open decisions turn on your preference |
|
|
27
|
+
| `canon:pick-by-eye` | The call is taste, wanting candidates side by side |
|
|
28
|
+
| `canon:draft-and-pick` | Never on purpose. A pointer naming `pick-by-eye` <!-- canon-keep-retired --> |
|
|
29
|
+
| `canon:canvas-board` | A direction should be drawn as editable frames |
|
|
30
|
+
| `canon:task-board` | A decided item needs a file on the board |
|
|
31
|
+
| `canon:plan-feature` | The approach is settled and needs a plan |
|
|
32
|
+
| `canon:codebase-layout` | A change adds a file and needs a folder |
|
|
32
33
|
|
|
33
34
|
## Build the feature
|
|
34
35
|
|
|
@@ -19,9 +19,9 @@ The default. `canon/DESIGN.md` holds visual intent as one Overview paragraph, at
|
|
|
19
19
|
These skills cover the tier:
|
|
20
20
|
|
|
21
21
|
- `canon:ui-checklist`, `canon:ux-audit`, and `canon:ux-measure` review and measure a UI
|
|
22
|
-
- `canon:
|
|
22
|
+
- `canon:pick-by-eye` drafts candidates as frames on the canvas and takes your pick
|
|
23
23
|
- `canon:canvas-board` works a direction out as HTML frames you edit in the browser. Only the pick moves into `canon/DESIGN.md`.
|
|
24
|
-
- `canon:
|
|
24
|
+
- `canon:design-identity` drafts a logo mark and social card
|
|
25
25
|
|
|
26
26
|
Pick tier 0 when the UI is not the core product, decisions fit in sentences, and stakeholders review code.
|
|
27
27
|
|
package/governance/detect.toml
CHANGED
|
@@ -169,6 +169,10 @@ files = ["index.html", "*/index.html"]
|
|
|
169
169
|
deps = ["react", "vue", "svelte", "astro", "next", "solid-js", "preact"]
|
|
170
170
|
files = ["index.html", "*/index.html"]
|
|
171
171
|
|
|
172
|
+
["keyboard"]
|
|
173
|
+
deps = ["react", "vue", "svelte", "astro", "next", "solid-js", "preact"]
|
|
174
|
+
files = ["index.html", "*/index.html"]
|
|
175
|
+
|
|
172
176
|
["forms"]
|
|
173
177
|
deps = ["react", "vue", "svelte", "astro", "next", "solid-js", "preact"]
|
|
174
178
|
files = ["index.html", "*/index.html"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Astro rule ledger
|
|
3
|
+
description: Sources for governance/rules/framework/astro.md, one row per bullet
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Astro rule ledger
|
|
7
|
+
|
|
8
|
+
The field is front-end engineering, and the authority is the Astro documentation at docs.astro.build. The pages read name no current major, so most rows record the read date alone. The content rows follow the Astro 6 upgrade guide, which removed the legacy collection location.
|
|
9
|
+
|
|
10
|
+
## Static first
|
|
11
|
+
|
|
12
|
+
| Bullet | Source | Read |
|
|
13
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- |
|
|
14
|
+
| `.astro` without client state | [Islands architecture](https://docs.astro.build/en/concepts/islands/): Astro components "render to static HTML with no client-side runtime" | 2026-10-18 |
|
|
15
|
+
| Fetch in the frontmatter | [Data fetching](https://docs.astro.build/en/guides/data-fetching/): "All Astro components have access to the global fetch() function in their component script", run "at build time" | 2026-10-18 |
|
|
16
|
+
|
|
17
|
+
## Islands
|
|
18
|
+
|
|
19
|
+
| Bullet | Source | Read |
|
|
20
|
+
| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
21
|
+
| Directive on the component | [Template directives](https://docs.astro.build/en/reference/directives-reference/): "A client directive can only be used on a UI framework component that is directly imported into a .astro component" | 2026-10-18 |
|
|
22
|
+
| Pick the directive by priority | [Template directives](https://docs.astro.build/en/reference/directives-reference/): `client:load` is for "Immediately-visible UI elements", `client:idle` for "Lower-priority UI elements", `client:visible` for "below the fold" | 2026-10-18 |
|
|
23
|
+
|
|
24
|
+
## Routing and layouts
|
|
25
|
+
|
|
26
|
+
| Bullet | Source | Read |
|
|
27
|
+
| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
28
|
+
| `getStaticPaths()` for params | [Routing](https://docs.astro.build/en/guides/routing/): in static mode every parameter value needing a page comes from `getStaticPaths()`, while "In SSR mode, a page will be generated on request" | 2026-10-18 |
|
|
29
|
+
| Layouts with `<slot />` | [Layouts](https://docs.astro.build/en/basics/layouts/): "Layouts are Astro components used to provide a reusable UI structure", with "a slot to specify where individual page content should be injected" | 2026-10-18 |
|
|
30
|
+
|
|
31
|
+
## Content
|
|
32
|
+
|
|
33
|
+
| Bullet | Source | Read |
|
|
34
|
+
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
|
|
35
|
+
| `src/content.config.ts` loaders | [Content collections](https://docs.astro.build/en/guides/content-collections/): "All of your build-time content collections are defined in a special src/content.config.ts file", with "two built-in loaders (glob() and file())" | 2026-10-18, Astro 6 |
|
|
36
|
+
| Query through the API | [Content collections](https://docs.astro.build/en/guides/content-collections/): "getCollection() fetches an entire collection and returns an array of entries" | 2026-10-18 |
|
|
37
|
+
|
|
38
|
+
## Styles and assets
|
|
39
|
+
|
|
40
|
+
| Bullet | Source | Read |
|
|
41
|
+
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
42
|
+
| Scoped by default | [Styles and CSS](https://docs.astro.build/en/guides/styling/): "Scoped styles should be used as often as possible" and "Global styles should be used only as-needed" | 2026-10-18 |
|
|
43
|
+
| Images in `src/` | [Images](https://docs.astro.build/en/guides/images/): "We recommend that local images are kept in src/ when possible so that Astro can transform, optimize, and bundle them" | 2026-10-18 |
|
|
44
|
+
|
|
45
|
+
## Environment
|
|
46
|
+
|
|
47
|
+
| Bullet | Source | Read |
|
|
48
|
+
| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
49
|
+
| `astro:env` and `PUBLIC_` | [Environment variables](https://docs.astro.build/en/guides/environment-variables/): "only environment variables prefixed with PUBLIC\_ are available in client-side code", and `astro:env` gives "a type-safe schema" | 2026-10-18 |
|
|
50
|
+
|
|
51
|
+
## Declined
|
|
52
|
+
|
|
53
|
+
Every bullet the rewrite removed or reshaped, grouped by why.
|
|
54
|
+
|
|
55
|
+
### Contradicted by the docs
|
|
56
|
+
|
|
57
|
+
- Replaced "content collections in `src/content/` with a `config.ts` schema". The [Astro 6 upgrade guide](https://docs.astro.build/en/guides/upgrade-to/v6/) removed that location in favor of `src/content.config.ts`.
|
|
58
|
+
|
|
59
|
+
### Cut without a source or a bug class
|
|
60
|
+
|
|
61
|
+
- Cut "do not add a framework integration until the first island needs it" as a dependency call with no page read taking a side.
|
|
62
|
+
- Cut "keep islands leaf-level, never wrap layout chrome to enable nested islands", which no reviewer can check against one line.
|
|
63
|
+
- Cut "use `[param].astro` and `[...rest].astro`" as the file convention Claude already follows. The kept routing bullet names the `getStaticPaths()` footgun instead.
|
|
64
|
+
|
|
65
|
+
### Merged or reworded
|
|
66
|
+
|
|
67
|
+
- Reworded the hedged "write pages and components as `.astro` unless interactivity requires an island" to a test on client state and event handlers.
|
|
68
|
+
- Reworded the hedged "prefer server-rendered content over client-fetched data" to where the fetch call sits.
|
|
69
|
+
- Reworded "apply `client:*` directives on the component boundary, not on parents" to the rule the directives reference states.
|
|
70
|
+
- Reworded "prefer `client:visible` or `client:idle` over `client:load`" to the priority each directive is documented for.
|
|
71
|
+
- Merged "access collection entries via `getCollection` and `getEntry`" into the query bullet.
|
|
72
|
+
- Reworded "use `is:global` only in layouts" to include `:global()`, the selector the styling page names for the same case.
|
|
73
|
+
- Extended "read environment variables via `import.meta.env`" with `astro:env`, the typed schema the docs now offer.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: FastAPI rule ledger
|
|
3
|
+
description: Sources for governance/rules/framework/fastapi.md, one row per bullet
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# FastAPI rule ledger
|
|
7
|
+
|
|
8
|
+
The field is back-end Python web engineering, and the authority is the FastAPI documentation at fastapi.tiangolo.com. None of the pages read names a FastAPI major, so the rows record the read date alone.
|
|
9
|
+
|
|
10
|
+
## Routers
|
|
11
|
+
|
|
12
|
+
| Bullet | Source | Read |
|
|
13
|
+
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
14
|
+
| One `APIRouter` per feature | [Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/): "You can think of APIRouter as a mini FastAPI class", and "With app.include_router() we can add each APIRouter" | 2026-10-18 |
|
|
15
|
+
| Router-level dependencies | [Bigger Applications](https://fastapi.tiangolo.com/tutorial/bigger-applications/): router `dependencies` "can be used, for example, to require authentication for a whole group of path operations" | 2026-10-18 |
|
|
16
|
+
|
|
17
|
+
## Path operations
|
|
18
|
+
|
|
19
|
+
| Bullet | Source | Read |
|
|
20
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
21
|
+
| `async def` only when awaited | [Concurrency and async / await](https://fastapi.tiangolo.com/async/): a plain `def` "is run in an external threadpool that is then awaited", and "use async def unless your path operation functions use code that performs blocking I/O" | 2026-10-18 |
|
|
22
|
+
| Response model omits secrets | [Response Model](https://fastapi.tiangolo.com/tutorial/response-model/): FastAPI "will limit and filter the output data to what is defined in the return type" | 2026-10-18 |
|
|
23
|
+
| Body as a Pydantic model | [Request Body](https://fastapi.tiangolo.com/tutorial/body/): "To declare a request body, you use Pydantic models", which validate it and return "a nice and clear error" when it is invalid | 2026-10-18 |
|
|
24
|
+
|
|
25
|
+
## Dependencies
|
|
26
|
+
|
|
27
|
+
| Bullet | Source | Read |
|
|
28
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
29
|
+
| `Annotated` and type aliases | [Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/): "Prefer to use the Annotated version if possible", and the value can be stored "in a variable and use it in multiple places" | 2026-10-18 |
|
|
30
|
+
| Session per request via `yield` | [Dependencies with yield](https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/): "you could use this to create a database session and close it after finishing" | 2026-10-18 |
|
|
31
|
+
| Overrides in tests | [Testing Dependencies with Overrides](https://fastapi.tiangolo.com/advanced/testing-dependencies/): "your FastAPI application has an attribute app.dependency_overrides" | 2026-10-18 |
|
|
32
|
+
|
|
33
|
+
## Lifespan and settings
|
|
34
|
+
|
|
35
|
+
| Bullet | Source | Read |
|
|
36
|
+
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
37
|
+
| `lifespan`, not `on_event` | [Lifespan Events](https://fastapi.tiangolo.com/advanced/events/): "If you provide a lifespan parameter, startup and shutdown event handlers will no longer be called" | 2026-10-18 |
|
|
38
|
+
| Cached `BaseSettings` | [Settings and Environment Variables](https://fastapi.tiangolo.com/advanced/settings/): with `@lru_cache` "the Settings object will be created only once", and a dependency override replaces it during testing | 2026-10-18 |
|
|
39
|
+
|
|
40
|
+
## Errors
|
|
41
|
+
|
|
42
|
+
| Bullet | Source | Read |
|
|
43
|
+
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
44
|
+
| Raise `HTTPException` | [Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/): "To return HTTP responses with errors to the client you use HTTPException" | 2026-10-18 |
|
|
45
|
+
| One exception handler | [Handling Errors](https://fastapi.tiangolo.com/tutorial/handling-errors/): "You could add a custom exception handler with @app.exception_handler()" | 2026-10-18 |
|
|
46
|
+
| Safe summaries only | House choice: an exception message or traceback in a response leaks internals such as SQL, file paths, and library versions to the caller | 2026-10-18 |
|
|
47
|
+
|
|
48
|
+
## Middleware
|
|
49
|
+
|
|
50
|
+
| Bullet | Source | Read |
|
|
51
|
+
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
|
|
52
|
+
| Explicit CORS origins | [CORS](https://fastapi.tiangolo.com/tutorial/cors/): "None of allow_origins, allow_methods and allow_headers can be set to ['*'] if allow_credentials is set to True" | 2026-10-18 |
|
|
53
|
+
|
|
54
|
+
## Declined
|
|
55
|
+
|
|
56
|
+
Every bullet the rewrite removed or reshaped, grouped by why.
|
|
57
|
+
|
|
58
|
+
### Contradicted by the docs
|
|
59
|
+
|
|
60
|
+
- Reworded "define path operations as `async def` unless purely CPU-bound". The [async page](https://fastapi.tiangolo.com/async/) says "If you just don't know, use normal def", and CPU work in `async def` blocks the loop too.
|
|
61
|
+
- Cut "an `app_factory()` callable over a module-level `app` for testability". Every docs example uses a module-level `app` and tests through `app.dependency_overrides`, which the kept bullet names.
|
|
62
|
+
|
|
63
|
+
### Cut without a source or a bug class
|
|
64
|
+
|
|
65
|
+
- Cut "group routers by feature under `src/<pkg>/api/`" as a layout call, which the `codebase-layout` skill owns.
|
|
66
|
+
- Cut "annotate path, query, and body parameters, never `**kwargs`", since FastAPI cannot read `**kwargs` and Claude already annotates them.
|
|
67
|
+
- Cut "configure trusted hosts and HTTPS redirects through middleware" as a deployment choice with no page read taking a side.
|
|
68
|
+
|
|
69
|
+
### Merged or reworded
|
|
70
|
+
|
|
71
|
+
- Merged "mount routes through `APIRouter`, never directly on `FastAPI()`" into the router bullet.
|
|
72
|
+
- Reworded "return pydantic models and set `response_model=`" to name the filter, which is the footgun the [Response Model](https://fastapi.tiangolo.com/tutorial/response-model/) page warns about with passwords.
|
|
73
|
+
- Merged "express shared logic as `Depends(...)` over decorators or globals" into the `Annotated` bullet.
|
|
74
|
+
- Merged "do not perform blocking I/O inside `async def`" into the `async def` bullet.
|
|
75
|
+
- Narrowed "configure CORS through middleware, not per-route checks" to the credentials footgun the CORS page states.
|
|
76
|
+
- Moved "apply `dependencies=[Depends(auth)]` at the router or app level" to the routers section.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Next.js rule ledger
|
|
3
|
+
description: Sources for governance/rules/framework/nextjs.md, one row per bullet
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Next.js rule ledger
|
|
7
|
+
|
|
8
|
+
The field is front-end engineering, and the authority is the Next.js documentation at nextjs.org, read against the App Router docs for Next.js 16. The rule loads on every `.ts` and `.tsx` file in a target, so the rewrite cut it from 352 words to under 250.
|
|
9
|
+
|
|
10
|
+
## Routing
|
|
11
|
+
|
|
12
|
+
| Bullet | Source | Read |
|
|
13
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
|
|
14
|
+
| App Router, not `pages/` | House choice: a second router in one app splits layouts, data fetching, and caching across two models, so a change made in one never reaches routes in the other | 2026-10-18 |
|
|
15
|
+
| Await `params` | [route.js](https://nextjs.org/docs/app/api-reference/file-conventions/route): "`context.params` is now a promise" since v15, and every page example types `params: Promise<{ id: string }>` | 2026-10-18, Next.js 16 |
|
|
16
|
+
|
|
17
|
+
## Server and client components
|
|
18
|
+
|
|
19
|
+
| Bullet | Source | Read |
|
|
20
|
+
| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
|
|
21
|
+
| Server by default | [Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components): "By default, layouts and pages are Server Components", with Client Components for state, event handlers, lifecycle logic, and browser-only APIs | 2026-10-18, Next.js 16 |
|
|
22
|
+
| `'use client'` at the leaf | [Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components): "add 'use client' at the top of the files that define your interactive components instead of marking large parts of your UI as Client Components" | 2026-10-18, Next.js 16 |
|
|
23
|
+
| Serializable, minimal props | [Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components): props "need to be serializable", and [Data Security](https://nextjs.org/docs/app/guides/data-security) marks passing a whole row as "EXPOSED" | 2026-10-18, Next.js 16 |
|
|
24
|
+
| `server-only` on secret modules | [Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components): "To prevent accidental usage in Client Components, you can use the server-only package" | 2026-10-18, Next.js 16 |
|
|
25
|
+
|
|
26
|
+
## Data and caching
|
|
27
|
+
|
|
28
|
+
| Bullet | Source | Read |
|
|
29
|
+
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
|
|
30
|
+
| `'use cache'` with `cacheLife` | [Fetching Data](https://nextjs.org/docs/app/getting-started/fetching-data): "fetch requests are not cached by default", and [Caching](https://nextjs.org/docs/app/getting-started/caching): "We recommend pairing every cache directive with a cacheLife" | 2026-10-18, Next.js 16 |
|
|
31
|
+
| `<Suspense>` around runtime data | [Caching](https://nextjs.org/docs/app/getting-started/caching): "Components that access runtime APIs should be wrapped in Suspense" | 2026-10-18, Next.js 16 |
|
|
32
|
+
| Revalidate after a mutation | [Mutating Data](https://nextjs.org/docs/app/getting-started/mutating-data): "you can revalidate the Next.js cache and show the updated data by calling revalidatePath or revalidateTag within the Server Function" | 2026-10-18, Next.js 16 |
|
|
33
|
+
|
|
34
|
+
## Mutations
|
|
35
|
+
|
|
36
|
+
| Bullet | Source | Read |
|
|
37
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
|
|
38
|
+
| Verify auth inside the action | [Mutating Data](https://nextjs.org/docs/app/getting-started/mutating-data): "Server Functions are reachable via direct POST requests, not just through your application's UI. Always verify authentication and authorization inside every Server Function." | 2026-10-18, Next.js 16 |
|
|
39
|
+
| Validate input, trim output | [Data Security](https://nextjs.org/docs/app/guides/data-security): "You should always validate input from client", and "Only return what the UI needs, not raw database records" | 2026-10-18, Next.js 16 |
|
|
40
|
+
|
|
41
|
+
## Built-in primitives
|
|
42
|
+
|
|
43
|
+
| Bullet | Source | Read |
|
|
44
|
+
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
|
|
45
|
+
| `next/link` and `next/image` | [Linking and Navigating](https://nextjs.org/docs/app/getting-started/linking-and-navigating): "Next.js automatically prefetches routes linked with the Link component", and a plain anchor gets "No prefetching" | 2026-10-18, Next.js 16 |
|
|
46
|
+
| Image dimensions or `fill` | [Image Component](https://nextjs.org/docs/app/api-reference/components/image): "If the source image is a dynamic or a remote URL, you must provide the width and height props", and with `fill` "the parent element must be positioned" | 2026-10-18, Next.js 16 |
|
|
47
|
+
|
|
48
|
+
## Environment
|
|
49
|
+
|
|
50
|
+
| Bullet | Source | Read |
|
|
51
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------- |
|
|
52
|
+
| `NEXT_PUBLIC_` only when needed | [Environment Variables](https://nextjs.org/docs/app/guides/environment-variables): Next.js can "inline a value, at build time, into the js bundle that is delivered to the client", and the values are "frozen with the value evaluated at build time" | 2026-10-18, Next.js 16 |
|
|
53
|
+
|
|
54
|
+
## Declined
|
|
55
|
+
|
|
56
|
+
Every bullet the rewrite removed or reshaped, grouped by why.
|
|
57
|
+
|
|
58
|
+
### Contradicted by the docs
|
|
59
|
+
|
|
60
|
+
- Replaced "set explicit caching on every `fetch`" with the `'use cache'` bullet. New apps run Cache Components, which [Caching](https://nextjs.org/docs/app/getting-started/caching) drives through the directive.
|
|
61
|
+
- Cut "return `NextResponse` over raw `Response`", since the [route.js](https://nextjs.org/docs/app/api-reference/file-conventions/route) reference returns the Web `Response` throughout.
|
|
62
|
+
- Cut "read params from the function signature, not the request URL" as stale. The signature form holds, and the kept bullet adds the `await` the current major requires.
|
|
63
|
+
- Cut "return no `Response` or stream from a Server Action". No page read forbids it, and the kept bullet states what the docs do say about return values.
|
|
64
|
+
|
|
65
|
+
### Cut without a source or a bug class
|
|
66
|
+
|
|
67
|
+
- Cut "use route segment files for their documented purpose" as a convention Claude already follows.
|
|
68
|
+
- Cut "place HTTP endpoints in `app/**/route.ts`, never `pages/api/`" as covered by the App Router bullet.
|
|
69
|
+
- Cut "export named HTTP methods" as enforced by the framework, which only routes the named exports.
|
|
70
|
+
- Cut "export `metadata` or `generateMetadata` over manual head tags" as a convention Claude already follows.
|
|
71
|
+
|
|
72
|
+
### Cut for the word budget
|
|
73
|
+
|
|
74
|
+
A sourced practice cut only because the rule loads on every TypeScript file. A later pass with room can bring it back.
|
|
75
|
+
|
|
76
|
+
- Cut "use `next/font` over manual link tags", which the docs still recommend.
|
|
77
|
+
|
|
78
|
+
### Merged or reworded
|
|
79
|
+
|
|
80
|
+
- Merged "do not fetch in client components when a server alternative exists" into the server-by-default bullet, since the docs list fetching among a Server Component's uses.
|
|
81
|
+
- Merged "do not introduce `pages/` in new code" into the App Router bullet.
|
|
82
|
+
- Merged "push the boundary as deep as possible" into the leaf bullet.
|
|
83
|
+
- Merged "mark Server Actions with `'use server'`", which the build requires, into the mutation bullets.
|
|
84
|
+
- Reworded "validate Server Action inputs with a Zod schema" to any validation, since [Data Security](https://nextjs.org/docs/app/guides/data-security) names no library.
|
|
85
|
+
- Reworded "use `revalidatePath` or `revalidateTag` over manual refetch loops" to the call the mutation page shows.
|
|
86
|
+
- Merged "never read unprefixed env vars in a client component" into the env bullet, since [Server and Client Components](https://nextjs.org/docs/app/getting-started/server-and-client-components) says "If variables are not prefixed, Next.js replaces them with an empty string".
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: React rule ledger
|
|
3
|
+
description: Sources for governance/rules/framework/react.md, one row per bullet
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# React rule ledger
|
|
7
|
+
|
|
8
|
+
The field is front-end engineering, and the authority is the React team's documentation at react.dev. The rewrite started from groundwork spike S2's draft and reads its three unread leads.
|
|
9
|
+
|
|
10
|
+
## Rendering
|
|
11
|
+
|
|
12
|
+
| Bullet | Source | Read |
|
|
13
|
+
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
|
|
14
|
+
| Pure during render | [Components and Hooks must be pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure): side effects "should not run in render, as React can render components multiple times" | 2026-10-18, React 19 |
|
|
15
|
+
| Never mutate props or state | [Components and Hooks must be pure](https://react.dev/reference/rules/components-and-hooks-must-be-pure): "A component's props and state are immutable snapshots. Never mutate them directly." | 2026-10-18, React 19 |
|
|
16
|
+
| Stable data keys, not index | [Rendering lists](https://react.dev/learn/rendering-lists): "Index as a key often leads to subtle and confusing bugs" and "do not generate keys on the fly" | 2026-10-18, React 19 |
|
|
17
|
+
|
|
18
|
+
## State and effects
|
|
19
|
+
|
|
20
|
+
| Bullet | Source | Read |
|
|
21
|
+
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
|
|
22
|
+
| Derive during render | [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect): "When something can be calculated from the existing props or state, don't put it in state. Instead, calculate it during rendering." | 2026-10-18, React 19 |
|
|
23
|
+
| Reset with `key` | [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect): "To reset the state of an entire component tree, pass a different key to it." | 2026-10-18, React 19 |
|
|
24
|
+
| External store through `useSyncExternalStore` | [useSyncExternalStore](https://react.dev/reference/react/useSyncExternalStore): a browser value "can change without React's knowledge, so you should read it with useSyncExternalStore", and the server snapshot "must be the same between the client and the server" | 2026-10-18, React 19 |
|
|
25
|
+
| Fetching effect in a custom hook | [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect): a race "needs a cleanup function to ignore stale responses", and moving fetching "into a custom Hook will make it easier to adopt an efficient data fetching strategy later" | 2026-10-18, React 19 |
|
|
26
|
+
|
|
27
|
+
## Memoization
|
|
28
|
+
|
|
29
|
+
| Bullet | Source | Read |
|
|
30
|
+
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
|
|
31
|
+
| Leave it to the compiler | [React Compiler introduction](https://react.dev/learn/react-compiler/introduction): "For new code, we recommend relying on the compiler for memoization and using useMemo/useCallback where needed to achieve precise control." | 2026-10-18, React Compiler 1 |
|
|
32
|
+
| Without it, memoize only by need | [useMemo](https://react.dev/reference/react/useMemo): worth it for a noticeably slow calculation, "say, 1ms or more", a prop to a `memo` child, or a Hook dependency, and "There is no benefit to wrapping a calculation in useMemo in other cases" | 2026-10-18, React 19 |
|
|
33
|
+
|
|
34
|
+
## Composition
|
|
35
|
+
|
|
36
|
+
| Bullet | Source | Read |
|
|
37
|
+
| ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
|
|
38
|
+
| Props, children, then context | [Passing data deeply with context](https://react.dev/learn/passing-data-deeply-with-context): "Start by passing props", then "Extract components and pass JSX as children", and "If neither of these approaches works well for you, consider context" | 2026-10-18, React 19 |
|
|
39
|
+
|
|
40
|
+
## Error and loading boundaries
|
|
41
|
+
|
|
42
|
+
| Bullet | Source | Read |
|
|
43
|
+
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
|
|
44
|
+
| Error boundaries where a message makes sense | [Component](https://react.dev/reference/react/Component): "consider where it makes sense to display an error message", around the conversation list and each message, and "You don't need to wrap every component" | 2026-10-18, React 19 |
|
|
45
|
+
| What activates Suspense | [Suspense](https://react.dev/reference/react/Suspense): "Suspense does not detect when data is fetched inside an Effect or event handler" | 2026-10-18, React 19 |
|
|
46
|
+
| Boundaries follow the loading sequence | [Suspense](https://react.dev/reference/react/Suspense): "Suspense boundaries should not be more granular than the loading sequence that you want the user to experience" | 2026-10-18, React 19 |
|
|
47
|
+
|
|
48
|
+
## Exports
|
|
49
|
+
|
|
50
|
+
| Bullet | Source | Read |
|
|
51
|
+
| ------------- | -------------------------------------------------------------------------------------------------------- | ---------- |
|
|
52
|
+
| Named exports | House choice: a default export renamed at import drifts from the component's name, so a search misses it | 2026-10-18 |
|
|
53
|
+
|
|
54
|
+
## Declined
|
|
55
|
+
|
|
56
|
+
Every bullet the rewrite removed or reshaped, grouped by why.
|
|
57
|
+
|
|
58
|
+
### Contradicted by the docs
|
|
59
|
+
|
|
60
|
+
- Replaced "`useMemo` for derived state over `useEffect`" with the derive bullet. The effect page says "calculate it during rendering" and keeps `useMemo` for a slow calculation.
|
|
61
|
+
- Cut "memoize components receiving non-primitive props" as contradicted. [memo](https://react.dev/reference/react/memo) is "completely useless if the props passed to your component are always different, such as if you pass an object".
|
|
62
|
+
- Cut "memoize every handler passed to a child" as contradicted. [useCallback](https://react.dev/reference/react/useCallback) says "There is no benefit to wrapping a function in useCallback in other cases" than a `memo` child or a Hook dependency.
|
|
63
|
+
- Cut "no passing props past two levels" as contradicted, since the context page says "it's not unusual to pass a dozen props down through a dozen components".
|
|
64
|
+
|
|
65
|
+
### Cut without a source or a bug class
|
|
66
|
+
|
|
67
|
+
- Cut "domain logic in `src/features/`, shared UI in `src/components/`" as a layout call, which the `codebase-layout` skill owns.
|
|
68
|
+
- Cut "no feature components in the global components folder" as the same layout call.
|
|
69
|
+
- Cut "environment variables only from the validated config module", which is no React practice and which no react.dev page takes a side on.
|
|
70
|
+
- Cut "function declarations over arrow functions" as style with no bug class, and no react.dev page takes a side.
|
|
71
|
+
- Cut "props interface directly above the component" as style with no bug class.
|
|
72
|
+
- Cut "extract components when JSX exceeds one responsibility", which no reviewer can check against a line of code.
|
|
73
|
+
- Cut "compare the previous value and set state during render", since [You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect) says "most components shouldn't need it either" and ranks it after a key reset.
|
|
74
|
+
- Cut "use `<>` unless a key is needed" as a convention Claude already follows. [Rendering lists](https://react.dev/learn/rendering-lists) says the shorthand "won't let you pass a key".
|
|
75
|
+
|
|
76
|
+
### Merged or reworded
|
|
77
|
+
|
|
78
|
+
- Merged "no default exports" into the named-exports bullet, which states the same choice.
|
|
79
|
+
- Narrowed "custom hooks for all fetching and complex effects" to data fetching, since [Reusing logic with custom hooks](https://react.dev/learn/reusing-logic-with-custom-hooks) says "you can (but don't have to) extract custom Hooks".
|
|
80
|
+
- Merged "no `setState` in an effect to sync derived state" into the derive bullet, the same ban. Only the `web` and `nextjs` oxlint configs error on `react/set-state-in-effect`.
|
|
81
|
+
- Reworded "a sentinel from asynchronously hydrating hooks" to `useSyncExternalStore` with a matching server snapshot, the API the reference names for a value React does not own.
|
|
82
|
+
- Reworded "error boundaries at route level", since the reference places a boundary by where a message makes sense rather than at a fixed level.
|
|
83
|
+
- Merged "no single root error boundary as the only net" into the placement bullet.
|