CLAUDE.md · diff

git:20260927.51b76e4 to git:20260927.b4abeb0

36 added, 43 removed. Audit A to A.

# CLAUDE.md
- Guidance for Claude Code when editing **this repository**. User-facing documentation lives in `README.md`; the full artifact contract lives in [`docs/contract.md`](docs/contract.md).
+ Guidance for Claude Code when editing **this repository**. User docs are the `website/` site, which owns usage prose, and `README.md`. The contract is [`docs/contract.md`](docs/contract.md); read the section a rule links before a non-trivial edit. Path-specific how-to in `.claude/rules/` loads when you read a matching file.
+ **Where a rule lives.** Every rule a `/self-audit` lens enforces, and every irreversible one (CHANGELOG, version, commits), stays here as a one-liner linking the contract section that holds its full statement and the why. `.claude/rules/` holds path-specific how-to only.
+
## Quick orient
- A collection of user-invocable Claude Code skills implementing a chat-first "context serialization protocol", not an orchestration engine: discuss freely in chat, then fix the discussion into a fixed-format Markdown artifact under `.task/` with one short skill. What you capture — one task, an initiative, or the decisions they must honor — is the skill name, never a flag. Skills in `skills/<name>/SKILL.md`; the plugin ships exactly one agent, `agents/code-reviewer.md` (the review pass — see the invariants below), and no phase companions, no lock protocol, no hook gate. No build step and no linter; the bash layer has a test suite (`bash tests/run.sh`) and the prompts have eval cases under `evals/` (`claude plugin eval .`, early access, not in CI). Work here is editing markdown (occasional bash) and reasoning about pipeline semantics.
+ The `task` plugin: five skills implementing a chat-first context-serialization protocol, not an orchestration engine. One skill fixes a chat discussion into a Markdown artifact under `.task/`; what you capture — one task with its plan, an initiative with its architecture, or the decisions they must honor — is the skill name, never a flag. No execution skill: a session told `implement .task/task/<slug>.md` follows its `## Execution` pointer, `roadmap-to-workflow` fans items out through the driver `skills/_lib/roadmap-driver.js`, and both hand the diff to the one agent, `agents/code-reviewer.md`. No build step, no plugin hook; the bash layer is tested and shellchecked in CI. Work here is mostly Markdown and pipeline reasoning.
```
discuss freely in chat
↓
grill ← pre-capture: interrogate the decision, no artifact
↓
to-task | to-roadmap ← what you capture is the skill, not a flag
to-spec ← pins technical decisions, cited via Spec:
↓ ↓
implement session roadmap-to-workflow ← the launcher fans items out to sessions
↓ ↓
task:code-reviewer ← the plugin's own review pass, spawned by both:
prove → fix within Touches → Build and Tests → commit the fixes
```
- `grill` sits at the "discuss freely" stage: it interrogates a plan/decision one question at a time, keeps a decision-plus-rationale ledger, ends with a pre-mortem, and routes to the right capture skill — it writes no artifacts and touches nothing under `.task/`. `to-task` captures one task into `.task/task/<slug>.md` — `## Description` plus a `## Plan` of Goal/Touches/Logic steps, always both; `to-roadmap` captures a multi-task initiative into `.task/roadmap/<slug>.md` together with its technical layer — an `## Architecture` section inside that same file (components, interfaces between items, a module-level sketch per item, technical ordering), drafted after the decomposition and written in the same single write — which the planners follow as the intended shape, not a fixed anchor; `to-spec` captures load-bearing technical decisions into a standalone `.task/spec/<slug>.md`, referenced by tasks/roadmaps via a `Spec:` header and read by the executing session as a fixed anchor. There is **no execution skill** — every artifact carries a stamped one-line `## Execution` pointer to `.task/CLAUDE.md` → `## Executing a task`, and an ordinary session told `implement .task/task/<slug>.md` follows it: implement the plan, commit per `.task/CLAUDE.md` → Commit Format, spawn `task:code-reviewer` on the resulting diff (it proves each finding, fixes what it confirms within **Touches**, runs `.task/CLAUDE.md` → Build and Tests, commits its fixes on top of the implementation's commit, and ticks the roadmap item once its review passes if `Roadmap:`/`Source item:` are present). `roadmap-to-workflow` is the one launcher: it reports a roadmap's unchecked items with their dependencies plus the chosen scope, and invokes the plugin-shipped Workflow driver — which computes the dependency-ordered waves itself (`skills/_lib/roadmap-driver.js`, registered as `task:roadmap-driver` through the manifest's `"workflows"` key and invoked by name with `args`) — opus-plans (sonnet for `haiku`-hinted items)/sonnet-implements/`task:code-reviewer`-reviews per item by default, the reviewer ticking the checkbox as its last phase.
+ ## Verify
- Full artifact shapes, producer/consumer table, and bash-layer contract: [docs/contract.md](docs/contract.md). Read it before any non-trivial edit to a skill or bash helper.
+ - `bash tests/run.sh [filter]` is the gate, green before every commit. Driver cases need `node`, some hook checks `jq`; a SKIP line is not a pass.
+ - `claude plugin validate --strict .` checks the marketplace manifest; `npm --prefix website ci && npm --prefix website run docs:build` builds the site.
+ - `claude plugin eval .` runs the prompt evals (early access, not in CI: a signal only); `/self-audit` checks the repo against its own rules.
+ - CI: `.github/workflows/tests.yml` runs the suite and shellcheck; `docs-check.yml` builds the site on PRs; `docs.yml` deploys it.
## Invariants — don't break these when editing skills
- - `.task/` is **flat**: `.task/CLAUDE.md`, `.task/.gitignore` (the self-ignoring `*`), `.task/task/<slug>.md` (one file per task), `.task/roadmap/<slug>.md`, `.task/spec/<slug>.md` (one file per spec). No `.task/workspace/`, no `.task/log/`, no `<task-id>/` subfolders, no `.spec.md` roadmap sidecar (specs are standalone under `.task/spec/`), no archive — git history is the record.
- - `.task/CLAUDE.md` is a **nested `CLAUDE.md`, not a bespoke config format**: the platform auto-loads it into any session that reads a file under `.task/`, which is how the executing session and `task:code-reviewer` get Language / Testing Policy / Build and Tests / Commit Format / `## Executing a task` without being told to. Two limits are load-bearing — the auto-load fires only for file-read tools (never for `cat`/`sed`), and a nested `CLAUDE.md` is **not** re-injected after `/compact`. Hence the explicit `## Execution` pointer in every artifact, and the reviewer's explicit read in its phase 0. **Written once by setup, then user-owned** — never rewritten, never section-repaired; to regenerate it the user deletes it and re-runs any capture.
- - **Slug is the identity.** Kebab-case English, derived from the title; it is the filename, not a header. No task-id, no `[TASK-ID]` bracket, no umbrella grouping.
- - Setup-gate has three categories: `to-task` / `to-roadmap` / `to-spec` auto-run setup in a fresh project by following `skills/_lib/setup.md` (writing `.task/CLAUDE.md`, no confirmation chip); every other skill checks `.task/CLAUDE.md` and hard-stops if absent; `grill` is the exception that neither checks nor creates it — it touches nothing under `.task/` and can run before any capture exists (bash-layer precondition, not relaxed by prompt edits).
- - `task.md` is the single contract: `# <Title>` (plain, no bracket), optional `Roadmap:` / `Source item: #N` / repeatable `Spec:` headers, `---`, `## Description`, `## Plan` (`### Step N:` blocks with Goal/Touches/Logic — every producer writes it; `validate.sh` still accepts an older or hand-written file without one), optional `## Tests` (`### Test N:`), and a stamped one-line `## Execution` pointer (English, parser-stable) to `.task/CLAUDE.md` → `## Executing a task`, which carries execution — implement → commit → review — without a separate skill. `Roadmap:` + `Source item:` are load-bearing for the auto-mark step, `Spec:` for the executing session's fixed-anchor read — keep them ASCII, above the `---`. Specs themselves live at `.task/spec/<slug>.md`, authored only by `to-spec`.
- - **Cross-artifact references are Markdown links**, so a viewer can navigate a `.task/` file: `Roadmap: [<slug>](../roadmap/<slug>.md)`, `Spec: [<slug>](../spec/<slug>.md)`, `### Spec references → [<slug>](../spec/<slug>.md) §N`, and the `## Execution` pointer's `[.task/CLAUDE.md](../CLAUDE.md)`. Hrefs are relative to the artifact's own directory; every kind sits one level under `.task/`, so it is always `../<kind>/<slug>.md`. **The label carries the identity, the href is for viewers** — a consumer takes the slug from the label and rebuilds `$AI_DIR/<kind>/<slug>.md`, never follows the href literally (an agent's cwd is the project root, not `.task/task/`). Producers emit the link form; consumers, `validate.sh` included, still accept a bare slug — earlier versions wrote it and artifacts are hand-edited. Full rules: [docs/contract.md § Cross-artifact references](docs/contract.md#cross-artifact-references).
- - Pipeline is invisible to the project — no tracked edits outside `.task/`, ignored by its own `.task/.gitignore` (pattern `*`, covering the file itself) — never via `.git/info/exclude` or a tracked `.gitignore`. Setup writes it; `preflight.sh` recreates it when missing, never rewrites it. Markers are exactly `git config task.root` + `.task/.gitignore` — **nothing else**: no active-task pointer, no `TASK_ID_OVERRIDE`, no per-worktree pointer file.
- - `resolve-ws.sh` is a pure `.task/`-root finder (exports `AI_DIR`): `task.root` git config *when that path already holds a `.task/CLAUDE.md` and belongs to this repo* (its git common dir is ours, or it is exactly `dirname(git-common-dir)` — a bare repo's container) → ancestor walk for `.task/CLAUDE.md`, *ceilinged at the highest directory still belonging to this project* (its top level, the main worktree root, or a submodule's superproject — whichever is highest and still an ancestor of `$PWD`; above that lies someone else's `.task/`) → `dirname(git-common-dir)/.task` → `$CLAUDE_PROJECT_DIR/.task` when that path already holds a `.task/CLAUDE.md` → `./.task`. Steps 1 and 4 both claim a root **only on evidence** — a stale `task.root` falls through: after a move it names a vanished path (trusting it would send capture setup to write a fresh `.task/CLAUDE.md` beside the real one), after a copy it names the original repo (trusting it would have the copy read and write the original's artifacts). No workspace resolution, no pointer read/write/self-heal logic anywhere. Every producer writes under the resolved `$AI_DIR`, never a cwd-relative `.task/` — a cwd-relative write splits the root, since `validate.sh` resolves `AI_DIR` independently.
- - Orchestration and commits stay delegated to the platform (dynamic Workflows, `.task/CLAUDE.md` → Commit Format) — never hand-rolled inside a skill. **The driver is reached by its registered name**, `task:roadmap-driver` (composed from the plugin's manifest `name` and the driver's own `meta.name`, declared under the manifest's `"workflows"` key as a `./`-prefixed path — the schema rejects a bare relative one and a rejected manifest takes the whole plugin down) — never by `scriptPath`, which the Workflow tool permission-checks against the invoking session's working directory that a plugin is never inside. **Review is the pipeline's own**, and lives in exactly one place: the plugin-shipped `agents/code-reviewer.md`, resolved as `task:code-reviewer` and spawned by both execution paths (a plain session per `## Executing a task`; `roadmap-to-workflow`'s driver as its own stage in the per-item serial loop). The platform's `/verify` and `/code-review` are `disable-model-invocation`, so neither path can run them and the skip is silent — **never instruct any agent or `## Executing a task` to call them.** Verification rides inside the reviewer via `.task/CLAUDE.md` → Build and Tests, never as a separate skill. The reviewer proves each finding before fixing it, confines fixes to **Touches** plus regressions the same diff introduced outside them, and commits its fixes as a separate commit on top of the implementation's, never rewriting it — it never sets `isolation` (it must see and edit that same working tree) and never writes under `.task/`, save the one roadmap checkbox its last phase flips.
- - Every skill carries `disable-model-invocation: true` + `user-invocable: true` + an `argument-hint` mirroring its own **Input:** line (flag-free — a hint never suggests one); the four that call bash also carry `allowed-tools` with **one rule per helper script they invoke** (`preflight.sh`, `write-task.sh`, `roadmap-items.sh`, `detect-project.sh`, `validate.sh`) — load-bearing, since a `!`-preprocessed command that matches no pattern aborts the skill instead of prompting, and deliberately not a single `_lib/*.sh` glob, which a Bash rule would widen to any such script outside the plugin. (`validate` is a bash-only utility — `skills/validate/validate.sh` with no `SKILL.md` — so it has no frontmatter.) Artifacts and user dialog follow `.task/CLAUDE.md` → Language — except `grill`, which by design reads nothing under `.task/` and so mirrors the chat's own language instead; parser-stable strings (headers, cross-artifact link labels, commit trailers, the `## Execution` pointer) stay English.
- - Interaction conventions, all three: (a) every user-facing output ends `→ Next: <command or artifact path>` or `→ Done.`; (b) every capture **writes its artifact immediately, then prints a structural digest** as message text (path, title, sections written, the load-bearing decisions/pins captured one line each — for a spec, *all* pins — and the `validate.sh` result), inviting edits against the written file rather than gating on a preview or a confirmation chip — the chat discussion was the review. `grill` writes nothing, so its decision ledger *is* that digest. Exactly one chip survives, and it is not about distilled content: the slug-collision overwrite guard (a pre-write safety check on a destructive action). Step 0 setup writes `.task/CLAUDE.md` and reports — it does **not** ask. (c) every 2–4 option path fork uses `AskUserQuestion` chips. All flag-free — no `--plan`, `--from`, `--phase`, `--refine` anywhere user-facing.
- - Auto-mark (ticking a roadmap item's checkbox) is **`task:code-reviewer`'s last phase** (phase 7), on both execution paths — run only once its verdict is OK, through one fully-baked command in `agents/code-reviewer.md`, never a hand edit. Never a plan or implement agent's job, and never a stage of its own: a dedicated mark agent cost a whole agent spawn for one `awk` call. In a roadmap run the driver passes the item number and roadmap path to the review explicitly, and the review runs inside the per-item serial loop, so the roadmap file keeps one writer — parallel plan agents never touch it. The driver still asks for proof: a passing review must repeat the flip's own `MARK-OK #N` line in its report (`flipReported`), or the wave stops rather than leave a landed item unchecked. The flip is **idempotent and self-reporting**: it keys on the item number over the full 5-state checkbox class, so an already-ticked item is a no-op reporting OK, and it echoes its outcome on stdout rather than leaving the agent to infer an invisible exit code. Exactly one heading for item N must exist; a missing, renumbered or duplicated heading turns the review into a FAIL, which stops the wave. `tests/reviewer-mark.test.sh` extracts the command verbatim and holds it to that.
- - Commit/PR/release rules: see below and [`CONTRIBUTING.md`](CONTRIBUTING.md) — read it before committing anything in this repo.
+ - `.task/` is **flat**: `CLAUDE.md`, `.gitignore`, one file per artifact under `task/`, `roadmap/`, `spec/`. No subfolders, workspace, log or archive. [§ layout](docs/contract.md#task-layout-flat)
+ - `.task/CLAUDE.md` is a nested `CLAUDE.md`, written once by setup, then user-owned: never rewritten or section-repaired. It auto-loads only through file-read tools and is not re-injected after `/compact`, hence the `## Execution` pointer and the reviewer's phase-0 read. [§ format](docs/contract.md#taskclaudemd-format)
+ - **Slug is the identity**: kebab-case English from the title, the filename, never a header. No task-id, no `[TASK-ID]`, no umbrella grouping. [§ Slug](docs/contract.md#slug-as-identifier)
+ - Setup gate: the three captures run setup without a chip; `roadmap-to-workflow` and `validate.sh` hard-stop without `.task/CLAUDE.md`; `grill` touches nothing under `.task/`. [§ Setup gate](docs/contract.md#setup-gate-categories)
+ - `task.md` is the single contract: ASCII `Roadmap:`, `Source item:`, `Spec:` headers above `---`, `## Description`, `## Plan` (every producer writes it; `validate.sh` still accepts an older file without one), optional `## Tests`. Every task file ends with the stamped English `## Execution` pointer; roadmaps and specs carry none. [§ task.md](docs/contract.md#taskmd-format-tasktaskslugmd)
+ - **Cross-artifact references are Markdown links** (`../<kind>/<slug>.md`; a related roadmap `<slug>.md`). The label is the identity: consumers rebuild `$AI_DIR/<kind>/<slug>.md` from it and accept a bare slug. Only `to-spec` writes specs; users edit them after. [§ references](docs/contract.md#cross-artifact-references)
+ - The pipeline is **invisible** to the project: no tracked edits outside `.task/`, which its own `.task/.gitignore` (`*`) ignores; exactly two markers, `git config task.root` and `.task/.gitignore`. This repo's tracked `.task/` ignore is the dogfooding exception. [§ Markers](docs/contract.md#marker-inventory)
+ - `resolve-ws.sh` is a pure root finder: it exports `AI_DIR`, claiming a root only on evidence. Every producer writes under `$AI_DIR`, never a cwd-relative `.task/`. [§ Root resolution](docs/contract.md#root-resolution-skills_libresolve-wssh)
+ - Orchestration and commits stay delegated to the platform, never hand-rolled in a skill. The driver is reached by its registered name `task:roadmap-driver`, never by `scriptPath`. [§ driver contract](docs/contract.md#roadmap-to-workflow-execution-shape-driver-contract)
+ - Review lives only in `agents/code-reviewer.md`: it proves before fixing, stays within **Touches**, commits at most one fix commit on top (none when clean), never sets `isolation`. Nothing instructs a call to `/verify` or `/code-review`. [§ Agent layer](docs/contract.md#agent-layer-agents)
+ - Auto-mark is the reviewer's phase 7: OK verdict only, one baked flip command, never a plan or implement agent or a stage of its own. [§ Agent layer](docs/contract.md#agent-layer-agents)
+ - Frontmatter: every skill carries `disable-model-invocation: true`, `user-invocable: true` and a flag-free `argument-hint`; the four bash-calling skills share one identical `allowed-tools` line. Each holds exactly one `!`-injection, its Step 0 preflight call; `grill` and `.claude/skills/` hold none. [§ Frontmatter](docs/contract.md#frontmatter)
+ - Artifacts and dialog follow `.task/CLAUDE.md` → Language (`grill` mirrors the chat); parser-stable strings stay English. [§ Language split](docs/contract.md#language-split)
+ - User-facing output ends with a `→ Next:` footer or `→ Done.`; a capture writes, then prints a digest (its only chip: the slug-collision guard); 2–4 option forks use `AskUserQuestion`; no flags. [§ Interaction conventions](docs/contract.md#interaction-conventions)
## Editing protocol — quick rules
- - Treat each `SKILL.md` as a prompt contract — output templates, section headers, step numbering are load-bearing.
- - **Never write anything else in a skill body that looks like Step 0's `!`-injection** — a `!` at line start or after whitespace followed by a backticked command is run by the platform, wrapping it in double backticks does not quote it, and a failing injection aborts the whole skill invocation. Prose describes that case in words; `tests/skill-injections.test.sh` holds each of the four bash-calling skills to exactly one injection, and `grill` to none ([contract § Setup-gate categories](docs/contract.md#setup-gate-categories)).
- - The `task.md` template lives in exactly one place: `skills/_lib/write-task.sh`, which every producer calls (`to-task`, `plan-driver.md`). Changing the shape or the separator coordinates that script and `validate/validate.sh` — the skills carry no template of their own to keep in sync. Changing first-run setup or the `.task/CLAUDE.md` template coordinates `skills/_lib/setup.md` — the single owner of both. The plan pipeline has one owner too: `skills/_lib/plan-driver.md` § Core (`to-task` Steps 3–7 point into it, the driver's plan agent follows it), and the from-roadmap block another: `skills/_lib/roadmap-item.md` (read by `to-task` and that same agent). The roadmap capture flow has a third: `skills/_lib/roadmap-capture.md` § Core (`to-roadmap` Steps 1–7 point into it — the decomposition and the `## Architecture` section, drafted and written together).
- - Prefer Markdown + **bold** over XML.
- - Touching a bash helper (`skills/_lib/*.sh`, `skills/validate/validate.sh`) or the driver means updating its case file under `tests/` in the same commit, and `bash tests/run.sh` must be green before the commit.
- - Changing a skill's prompt has no unit test to catch it; the nearest check is the eval suite (`evals/`, `claude plugin eval .`). It needs the early-access feature and is not wired into CI, so treat a run as a signal, not a gate.
- - Every skill change updates `README.md` and `docs/contract.md` in the same commit; when it changes user-facing behavior, also update the matching `website/` guide/reference page (the docs site — `docs(website): …`, scope `website`). The site is the single owner of user-facing usage/troubleshooting prose; `docs/usage.md` and `docs/troubleshooting.md` are now thin pointers to it.
- - **Never** update `CHANGELOG.md` autonomously. Edit it only when the user explicitly requests it.
- - **Never change `.claude-plugin/plugin.json`'s `version` without explicit user confirmation.** Same rule for cutting `## [Unreleased]` into a numbered release.
-
- ## Commit format
-
- Source of truth: [`CONTRIBUTING.md`](CONTRIBUTING.md). Summary:
+ - Each `SKILL.md` is a prompt contract: output templates, section headers and step numbering are load-bearing.
+ - Edit the single owner, never a copy: the `task.md` shape, `skills/_lib/write-task.sh` (change `skills/validate/validate.sh` and the reviewer's phase 0 with it); setup and the `.task/CLAUDE.md` template, `skills/_lib/setup.md`; the plan pipeline, `skills/_lib/plan-driver.md` § Core; the from-roadmap block, `skills/_lib/roadmap-item.md`; roadmap capture, `skills/_lib/roadmap-capture.md` § Core; the commit fallback, `skills/_lib/templates/conventional-commits.md`.
+ - A plugin-skill change (`skills/*/SKILL.md`) updates `README.md`, `docs/contract.md` and, for user-facing behavior, its `website/` page in the same commit; self-audit is exempt.
+ - A helper or driver change ships its `tests/` case in the same commit (comment- and lint-only edits excepted), with the suite green.
+ - Prefer Markdown and **bold** over XML.
+ - **Never** edit `CHANGELOG.md`, change `.claude-plugin/plugin.json`'s `version`, or cut `## [Unreleased]` into a release unless the user explicitly asks. A repo hook asks first.
+ - Path rules, in `.claude/rules/`: `skills.md`, `lib-bash.md`, `tests.md`, `evals.md`, `website.md`, `agents.md`, `roadmap-driver.md`, `plugin-manifest.md`.
- - Header: `<type>(<scope>): <short summary>` — under 72 chars, imperative, lowercase first letter, no trailing period.
- - Types: `feat | fix | refactor | perf | docs | test | chore | revert`. **Do not invent types.**
- - Scopes (optional but strongly preferred): skill names (`grill`, `to-task`, `to-roadmap`, `to-spec`, `roadmap-to-workflow`, `validate`), or cross-cutting keys (`skills`, `agents`, `lib`, `plugin`, `github`, `readme`, `claudemd`, `changelog`, `contributing`, `contract`, `website`, `tests`, `evals`). **Do not invent scopes.**
- - Body: mandatory for all non-trivial commits; explain **why**, not what; 2–5 bullet list, imperative tense.
- - Footer: `BREAKING CHANGE:` when header carries `!`; `Fixes #N` / `Closes #N` for issues/PRs.
- - AI attribution: every Claude-assisted commit must carry `Co-Authored-By: Claude <noreply@anthropic.com>` as the last footer line.
+ ## Repo-local tooling
- ## Pull requests
+ `.claude/` never ships. `/self-audit` fans out to four lens agents in `.claude/agents/`, read-only by instruction (no Edit or Write tools; Bash for reading), which nothing enforces. `.claude/settings.json` wires the release-file hook `.claude/hooks/guard-release-files.sh` and pre-approves the suite, `validate.sh`, the plugin validator and the site build. The lenses, the hook and `CONTRIBUTING.md` cite this file's headings by name: keep `## Quick orient`, `## Invariants — …`, `## Editing protocol — quick rules` and `## Release procedure` byte-identical.
- Source of truth: [`CONTRIBUTING.md`](CONTRIBUTING.md#pull-request-title). When opening a PR (`gh pr create`), follow it — do NOT default to `gh`'s commit-derived title/body:
+ ## Commits and pull requests
- - **Title**: short descriptive prose for the whole change, sentence case, no `type(scope):` prefix, under ~72 chars.
- - **Body**: use `.github/pull_request_template.md`. Only `## What` is mandatory; fill the rest when it applies, delete what doesn't. End with `Closes #N` / `Fixes #N` when relevant, then the `🤖 Generated with [Claude Code]` attribution line.
- - **Label**: apply exactly one type label mapped from the commit type (`feat`→`enhancement`, `fix`→`fix`, `docs`→`documentation`, `refactor`→`refactor`, `perf`→`performance`, `test`/`chore`→`chore`); add `breaking-change` on top when relevant. **Do not invent labels.**
+ Read [`CONTRIBUTING.md`](CONTRIBUTING.md) before committing: types and scopes from its closed lists, never invented; PR title, body template and label from it, not `gh`'s defaults. Every AI-assisted commit ends with a `Co-Authored-By:` trailer; the form is not pinned.
## Release procedure
- Triggered only when the user explicitly requests a release. Execute in this exact order — do not reorder or merge steps:
+ Only on the user's explicit request, in this exact order — never reorder or merge steps:
- 1. **Release commit** — rename `## [Unreleased]` in `CHANGELOG.md` to `## [X.Y.Z] — YYYY-MM-DD` (do not leave a fresh empty `## [Unreleased]` above it; for breaking changes, add a `## Migration` block to the entry) and bump `"version"` in `.claude-plugin/plugin.json` to match, and bump the docs site's version label (the nav `text: 'vX.Y.Z'` in `website/.vitepress/config.mts`) to the same number — all three in one commit: `chore(changelog): release vX.Y.Z`.
+ 1. **Release commit**, all in one `chore(changelog): release vX.Y.Z` commit — rename `## [Unreleased]` in `CHANGELOG.md` to `## [X.Y.Z] — YYYY-MM-DD` (no fresh empty `## [Unreleased]` above it; a breaking release adds a `## Migration` block), and set the same number as `"version"` in `.claude-plugin/plugin.json` and as the nav label `text: 'vX.Y.Z'` in `website/.vitepress/config.mts`.
2. **Version sentinel commit** — `git commit --allow-empty -m "vX.Y.Z"`.
3. **Tag** — `git tag vX.Y.Z` on the sentinel commit. Then confirm with the user before running `git push origin main && git push origin vX.Y.Z` (the tag alone doesn't push the commits).