diff --git a/.claude/memory/decisions.md b/.claude/memory/decisions.md index 011f854..9c187b1 100644 --- a/.claude/memory/decisions.md +++ b/.claude/memory/decisions.md @@ -86,6 +86,7 @@ rules: | BDR-063 | 2026-07-10 | GSC multi-account: OAuth2 installed-app flow + label-keyed token store, explicit (account,property) args, no global state | accepted | | BDR-064 | 2026-07-14 | global memory split: repo file → CLAUDE.global.md (deployed name unchanged), CLAUDE.md freed for project scope; consumer/maintainer wording rule | accepted | | BDR-065 | 2026-07-14 | transient planning artifacts (superpowers spec/plan): committed during run, deleted post-merge; git history = archive; codified in project CLAUDE.md | accepted | +| BDR-066 | 2026-07-15 | Model routing: reflection inline (session big model) + sonnet-pinned executors + blocking gate | accepted | --- @@ -975,3 +976,18 @@ rules: - **Why**: user call 2026-07-14 — registries already capture decisions; a stale plan describes a superseded intermediate state and misleads future readers; accumulation pollutes the repo. Precedent: gsc-crux cleanup (8a1fac0, 2026-07-10) did the same — this makes it law, not habit. - **Alternatives rejected**: never-commit (gitignore docs/superpowers) — breaks mid-run: briefs, reviewers, other-machine checkouts need the files; superpowers brainstorming commits the spec by convention. Keep-forever — the drift + pollution complained about. - **Reference**: project CLAUDE.md; cleanup commit this chore; precedent 8a1fac0. Linked [[BDR-064]], [[LRN-124]]. + +--- + +## BDR-066 — Model routing: reflection inline (session big model), executors pinned sonnet, blocking gate + +- **Date**: 2026-07-15 +- **Status**: accepted (partial supersede of BDR-050: /feat dev no longer inline; bugfix/hotfix dev-inline CONSERVED) +- **Decision**: reflection (brainstorm, plan, contract, audit judgment, loop decisions) runs on session model (Fable; Opus fallback) — inline or inherit subagents, never pinned down. Execution (code from closed plan, fix-bundle application) runs sonnet-pinned subagents: feater + hotfixer pinned sonnet; SDD implementation+review subagents dispatched `model: "sonnet"` (ship-feature/init-project); web-validate fixes via hotfixer L1 (was inline Edit). analyzer haiku pin REMOVED (digest feeds plan = reflection tier). verifier + security-auditor STAY sonnet (job9 confirmed — procedural gates, ≤3×/loop). Blocking gate `lib/model-gate.md` (self-check + witness `lib/model-check.sh`) wired in 12 reflection orchestrators; small → STOP, unknown → fail-visible; census guard `lib/tests/model-routing.test.sh` flip-tested. +- **Why**: big-model quota burned on mechanical execution (Fable exhausted mid-job8); plan closed at dispatch → executor needs obedience not judgment; fresh sonnet gates catch executor drift. +- **Alternatives rejected**: opus pins on audit agents (session-independent) — rejected: session assumed big + blocking gate as backstop, one tier fewer; advisory gate — rejected by user, blocking; split bugfix/hotfix too — rejected: bugfix investigation interleaved w/ fix, hotfix gain marginal vs dispatch overhead. +- **Caveats**: client-handover-writer conversion (inline-load → sonnet dispatch, 11 human-gate sites to relocate) DEFERRED to own plan — its opus pin stays inert meanwhile; feater cannot ask → NEED-DECISION report = escalation valve, plan must close decisions; witness reads settings.json — lags `--model`-launched sessions (self-check compensates). +- **Caveat (execution)**: /feat re-arch broke 5 stale assertions in lib/tests/loops-light.test.sh (locked OLD feater architecture) — repointed to skills/feat/SKILL.md (FSK, mirrors HOT/HSK split) + new dispatch lock + 1-line reflow in feat SKILL for single-line grep lock (LRN-093 class). +- **Wave 2 (2026-07-15, user directive)**: wave-1 exclusion list left execution running on the big session model = the waste this split kills. REVERSES the "split hotfix rejected" alternative above (reason held for bugfix — investigation interleaved w/ fix — but NOT hotfix: LOCATE→apply is linear/separable). Changes: /hotfix split like /feat (LOCATE reflection inline + MODEL GATE, hotfixer sonnet EXECUTOR — rewritten dual-use: also the seo/geo/web-validate L1 applier; revert-not-loop preserved) → hotfix JOINS gated group, census 12→13. /commit-change dispatches sonnet commit-changer (propose→dispatcher gates→apply; grouping ON sonnet so NO model gate; AskUserQuestion dropped from agent). /release-candidate dispatches new sonnet release-executor (2 spans prep/finish; when-to-release + push + version-number decision STAY in dispatcher). /doc → doc-syncer (sonnet) dispatch; /status → status-reporter (kept HAIKU — right tier for read-only collection; win = off big model, not the tier). Gate exclusion list now = commit-change/doc/status/release-candidate. Consumer-staleness swept (LRN-113): feat Rule 1 DOWNGRADE + feat commit-split both repointed off the bare executor agents to the /hotfix + /commit-change skills. +- **Wave 3 (2026-07-15/16, user directive)**: split the last two inline execution-carrying agents like /feat. /bugfix: investigation+diagnosis+contract inline behind the gate; bugfixer = sonnet EXECUTOR (fix + regression test from a closed FIX PLAN; no Agent/AskUserQuestion; BUGFIX-EXEC REPORT). verify+secure loop stays in main loop, executor = its re-dispatched dev (verify-secure-loop.md intro now: BOTH consumers dispatched, no inline branch). FINISHES reversing the "split bugfix rejected" carve-out (hotfix went wave 2, bugfix now) — investigation↔fix coupling accepted, mitigated by structured DIAGNOSIS + verify loop. /code-clean: PHASE-1 audit + validation gate inline (reflection); code-cleaner = sonnet PHASE-2 EXECUTOR (delete approved dead code, inline-load refactorer, re-audit) — refactor NOW on sonnet (inline-load pin was inert on big model). exported-symbol per-item consent stays AT THE GATE. Consumer-staleness swept: hotfix deeper-bug escalation → /bugfix skill (not bare agent); onboard STEP 6 + tour Phase B read-only-audit → general-purpose/analyzer (big model, NEVER the sonnet executor — audit stays big). Both skills STAY gated. Also: Explore built-in kept inheriting session (search feeds reflection = big deserved; custom sonnet override created then reverted — built-in already inherits + no owned prompt). census 36→42, loops-light repointed 35/0. +- **Reference**: spec `docs/superpowers/specs/2026-07-15-model-routing-design.md` + plan `docs/superpowers/plans/2026-07-15-model-routing.md` (transient, BDR-065 lifecycle), branch `feature/model-routing`. diff --git a/.claude/memory/journal.md b/.claude/memory/journal.md index b35b827..cf6f231 100644 --- a/.claude/memory/journal.md +++ b/.claude/memory/journal.md @@ -381,3 +381,8 @@ rules: ## 2026-07-14 - `/ship-feature` feature/claude-global-md-rename (unmerged, human GO pending): global memory → CLAUDE.global.md + project-scope CLAUDE.md, 8 commits (a4ee7e1 docs → e9a38a0 guards). Full pipeline: analyzer + contract (17 criteria), brainstorm/spec/plan gates, SDD 5 tasks (all task reviews Approved), verifier CONFORME 17/17 (after user-arbitrated criterion-9 consumer-wording + FILE-SCOPE [gated] enrichment), security PASS (semgrep 43 rules, 0), final review "Yes" after 2 Important fixes (guard-test drift → 7/7; doctor exact-target check). Decided [[BDR-064]]; learned [[LRN-122]] (2-commit rename split), [[LRN-123]] (exact symlink target). `make test` green throughout. settings.json plugin toggles = session-scoped, NOT committed — restore (gstack/ui-ux-pro-max/frontend-design/emil-design-eng/darwin-skill/magic ON) after merge. - Merges to develop: feature/claude-global-md-rename (2d54df5), chore/untrack-audit-reports (d557ee9), chore/post-merge-cleanup. /cso triage: 75 gitleaks findings → 0 real (60 git SHAs vs sourcegraph rule; gitflow-test AWS fixture; expired GitHub image JWT; presigned-URL key ids; doc placeholders; job7-purged artifacts). .gitleaks.toml → [[allowlists]] format + 8 targeted entries; `make scan-secrets` green 0+0. Makefile "safe to commit" hint root-caused → [[LRN-124]]. Transient spec+plan deleted per [[BDR-065]] (user decree, gsc-crux precedent). Mid-merge discovery: user commit 5842119 (gitignore `.audit/` + model pin fable-5) — explains the .audit-in-diff question. cso report: .gstack/security-reports/2026-07-14-secrets-triage.json. + +## 2026-07-15 +- model routing shipped on feature/model-routing: BDR-066 (reflection inline big / executors sonnet / blocking gate), /feat re-arch, census guard. client-handover conversion deferred to plan 2. +- model routing WAVE 2 (same branch, user directive): doc/status dispatch their agent (sonnet/haiku pins effective); /hotfix split like /feat (joins gated group 12→13, hotfixer dual-use executor); /commit-change → sonnet commit-changer (propose/apply, gates relocated); /release-candidate → sonnet release-executor (human gates + version decision kept in dispatcher). Consumer-staleness swept (feat Rule 1 + commit-split). census 36/0, make test green. Branch still unmerged. +- model routing WAVE 3 (same branch): /bugfix + /code-clean split like /feat — reflection inline, sonnet executors (bugfixer, code-cleaner). code-clean refactor now runs on sonnet (inline-load pin was inert). consumers rerouted (hotfix deeper-bug→/bugfix skill; onboard/tour read-only audit→big-model agent). Explore kept built-in (inherits big). census 42/0, loops-light 35/0. Branch still unmerged. diff --git a/.claude/memory/learnings.md b/.claude/memory/learnings.md index 61c2b45..a45b468 100644 --- a/.claude/memory/learnings.md +++ b/.claude/memory/learnings.md @@ -1241,3 +1241,10 @@ rules: - **why**: redaction removes VALUES, not INTELLIGENCE. And tool output is instruction — a hint that says "safe to commit" will eventually be obeyed by a human or an agent. - **future application**: derived security artifacts (scan reports, triage JSONs, audit findings) stay local/ignored; only the allowlist CONFIG (reviewable rules) is committed. When auditing tooling, grep its user-facing hints for wording that invites committing outputs. - **cousin**: [[BDR-057]] (secrets by reference, redact at capture), [[BDR-065]] (transient planning artifacts — same "process artifacts ≠ repo content" family), [[LRN-103]] (re-probe before acting). + +## LRN-125 — don't make an agent dual-use across model tiers; route the audit consumer to a big-model agent, not the sonnet executor + +- **pattern**: splitting `code-cleaner` into a sonnet PHASE-2 executor broke its OTHER consumers (onboard STEP 6, tour Phase B) which dispatched it read-only AUDIT-only. Reflex "keep it dual-use (audit-only OR execute)" would have run an AUDIT on the sonnet-pinned executor = silent violation of the audit=big-model principle. Fix: reroute the audit consumers to a big-model agent (general-purpose/analyzer, inherits session), never the sonnet executor. +- **why**: a dual-use agent inherits ONE pinned model. If its two uses sit on different tiers (audit=big, execution=sonnet), the pin silently mis-tiers one of them. hotfixer dual-use is fine because BOTH its uses are execution (same tier); code-cleaner's would have straddled tiers. +- **future application**: before making an agent dual-use, check both consumers are on the SAME tier. Audit/reflection consumer + execution consumer → split the routing (audit → big-model agent, execution → sonnet executor); never overload one pinned agent. Distinct from [[LRN-113]] (sweep ALL consumers on a pattern fix) — this is WHICH agent a consumer routes to, not whether you found them all. +- **cousin**: [[BDR-066]] (model routing: reflection/audit big, execution sonnet), [[LRN-113]] (consumer-staleness sweep on a pattern fix). diff --git a/.claude/tasks/TODO.md b/.claude/tasks/TODO.md index c3550de..fafdf9c 100644 --- a/.claude/tasks/TODO.md +++ b/.claude/tasks/TODO.md @@ -1,5 +1,40 @@ # TODO +## 2026-07-15 — model routing (feature/model-routing) +Spec + plan in docs/superpowers/ (transient, BDR-065). BDR-066. Branch +unmerged — human gate. +- [x] gate lib/model-check.sh + lib/model-gate.md (flip-tested) wired ×12 +- [x] pins: hotfixer/feater sonnet, analyzer un-pinned; SDD model:"sonnet"; + web-validate → hotfixer L1; census guard model-routing.test.sh +- [x] /feat re-arch: reflection inline → feater sonnet executor (partial + supersede BDR-050) +- [x] WAVE 2 (user directive): doc/status dispatch (sonnet/haiku pins + effective); /hotfix split like /feat (joins gated 12→13, hotfixer + dual-use executor); /commit-change → sonnet commit-changer + (propose/apply, gates relocated); /release-candidate → sonnet + release-executor (human gates + version decision kept in dispatcher); + census 36/0. Exclusion list now commit-change/doc/status/release-candidate. +- [ ] DOGFOOD (manual, next sessions): /feat live run — plan closes + decisions, dispatch carries sonnet, verify loop in main loop; gate + STOP on a sonnet session (LRN-079 class, not automatable here). Also + dogfood /hotfix split + /commit-change propose/apply + /release-candidate spans. +- [x] Explore agent: kept as built-in (inherits session = opus/fable). User + call — search feeds reflection, silent-incompleteness risk → deserves the + big model. Custom sonnet Explore.md created then reverted (built-in already + inherits + no owned prompt). +- [x] WAVE 3 (user directive): /bugfix split + /code-clean split → reflection + inline (behind existing gate), execution → sonnet executors. bugfixer = + pure fix+regression exec (BUGFIX-EXEC REPORT, no Agent/AskUserQuestion); + code-cleaner = PHASE-2 exec (refactor now runs on sonnet — inline-load pin + was inert). Both skills STAY gated. census wave-3 + loops-light repoint + (guarded). Supersedes BDR-050 bugfix carve-out. +- [ ] WAVE 4 — client-handover: DECIDED = dispatch the WHOLE writer (spec §5, + not redaction-only). Needs resumable-gate protocol (~8-11 AskUserQuestion + → GATE NEEDED yields, dispatcher asks + SendMessage-resumes) + force-big + on nested audit dispatches (STEP 3/4/7 — else audits inherit sonnet) + + MODEL GATE on the skill. NOT yet spec'd — dedicated pass after wave-3; + read writer 1123-1774 first. + ## 2026-07-08 — full back-merge release/1.0.0→develop (chore/backmerge-release-full) Genèse : la revue avait porté ~5/19 commits ; back-merge complet demandé. Cherry-pick par catégorie, 1 commit atomique/item, make test après chaque code. Branche non mergée (gate humain). diff --git a/CHANGELOG.md b/CHANGELOG.md index b537bd1..1160de4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,11 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). - `/deploy` checklist reshaped on first-real-run feedback, in two passes: runbook steps are **one command per line, interactive-session style** (an early step opens the ssh session; later lines run on the box; local steps say "from your machine") instead of folded `ssh host "cd … && …"` one-liners — step = comment header + command lines up to the next blank line, a `@delta:` directive governs the whole block; and the checklist is now **display-only** — `NEXT.sh` is no longer written at all (throwaway artifact; `PENDING.json` + the live runbook regenerate it in any session) and every hand-back **ends the turn with the full checklist as the final text, no tool call after it** (a checklist printed above a blocking question tool was observed never reaching the user). Template `templates/deploy/PROCEDURE.md` restyled to match. - `settings.json`: `inputNeededNotifEnabled: true` adopted (harness notification toggle); committed layout otherwise unchanged. - gsd-pi upgraded 2.64.0 → 3.0.0 — `status-reporter` output parser adapted to the ADR-013 cutover. +- `hotfixer` pinned `model: sonnet` (seo/geo/web-validate L1 applier); `analyzer` haiku pin removed (inherits the session model). +- ship-feature / init-project: SDD implementation + review subagents dispatched with `model: "sonnet"`. +- web-validate `--fix`: bundle applied via `hotfixer` at L1 instead of inline Edit (BDR-061 alignment). +- Model routing wave 2 — the pure-execution + reflection-split skills stop running execution on the big session model. `/doc` and `/status` now **dispatch** their agent (doc-syncer sonnet, status-reporter haiku) instead of inline-loading it, so the pin takes effect. `/hotfix` split like `/feat`: reflection (LOCATE root cause) inline behind the model gate, the fix applied by a `hotfixer` sonnet executor (rewritten dual-use — it is also the seo/geo/web-validate L1 applier); revert-not-loop preserved; hotfix joins the gated group (13th). `/commit-change` dispatches a sonnet `commit-changer` (propose → dispatcher-owned approval gates → apply; grouping runs on sonnet, `AskUserQuestion` removed from the agent). `/release-candidate` dispatches a new sonnet `release-executor` for the mechanical spans (prep / finish+tag), the two human gates (when-to-release, push) and the version-number decision staying in the dispatcher. +- Model routing wave 3 — the last two inline execution-carrying skills split like `/feat`. `/bugfix`: root-cause investigation, diagnosis and contract run inline behind the model gate; the fix + regression test are applied by a `bugfixer` sonnet executor (was a single inline agent), with the verify+secure loop staying in the main loop and the executor as its re-dispatched dev. `/code-clean`: the dead-code / style / structural audit and the approval gate run inline; a `code-cleaner` sonnet PHASE-2 executor then applies the approved scope — and the style/structural refactor (which inline-loads `refactorer`) now finally runs on sonnet, its pin having been inert under the old inline-load. Both skills stay gated (they keep reflection); their read-only-audit consumers (`onboard`, `tour`) reroute to a big-model agent so an audit never runs on the sonnet executor. Supersedes the BDR-050 "bugfix stays inline" carve-out. The built-in `Explore` search agent is deliberately left inheriting the session (search feeds reflection). ### Security - **Magic MCP fully ask-gated** — all four `mcp__magic__*` tools (builder, refiner, inspiration, logo_search) moved to `permissions.ask` in `settings.json`; no magic call can auto-execute. The builder opens an unauthenticated local callback server (`127.0.0.1:9221+`, `Access-Control-Allow-Origin: *`, no token check) whose POST body is injected verbatim into the tool result the model consumes — the ask-gate is the mitigation on our side (BDR-059). @@ -23,6 +28,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/). - **GSC + CrUX data layer for `/seo` FULL** — `lib/seo-data/` engine pulls real Google Search Console (Search Analytics + URL Inspection) and Chrome UX Report field data into the `/seo` FULL audit: CrUX p75 field metrics become the primary Core Web Vitals signal (anonymous PageSpeed lab stays the fallback), and a "Performance GSC (90 j)" section flags position 4-10 quick wins. Multi-account via OAuth2 (`make seo-connect`, one-time consent, `webmasters.readonly` scope only) with a per-label token store (0600 file / 0700 dir, atomic write, refresh tokens redacted, gitleaks-allowlisted) so two concurrent site audits never conflict. Absent credentials degrade gracefully to anonymous PageSpeed — the audit never fails. Config: `GOOGLE_OAUTH_CLIENT_ID` / `GOOGLE_OAUTH_CLIENT_SECRET` / `CRUX_API_KEY` in `~/.claude/.env`. Engine contract documented in `lib/seo-data/README.md`. - **impeccable** (pbakaus, Apache-2.0) wired into the toolchain as the design counterpart of semgrep: the `/impeccable` skill (23 verbs under one command: audit, polish, bolder, quieter…) plus the 45-rule deterministic anti-pattern detector (`npx impeccable detect`, exit 0/2, `--json`). Complementary to `frontend-design` (kept — aesthetic direction at build time); impeccable adds the deterministic audit floor and per-project design context (`/impeccable init`). CLI pinned in `plugins.lock.json` (3.2.0 — a silent rules update would change audit output on unchanged code); dist is machine-owned under `skills-external/impeccable/` (gitignored, ctx7 pattern), staged-installed by `install-plugins.sh` Step 8d, refreshed pin-honored by `update-all.sh`, symlinked by `link.sh`, listed in the design/web/web-full/full profiles and the design-work routing. Requires Node ≥ 24: the install baseline is bumped from 22 to 24 LTS (NodeSource `setup_24.x` / brew `node@24`), so `make plugin` upgrades a too-old host in place; the impeccable steps still skip gracefully if Node stays below 24. Not in the design gate's GATE-BLOCK list yet — promotion deliberate, after first dogfood. - `/tour` skill — grouped all-axes sweep over one or several projects: security (pinned-semgrep `security-auditor` agent + `/cso` posture when gstack is ON) → cleanup → re-verify → reconcile (report-only, never edits the target TODO/registries) → doc sync, looping until a full pass applies zero fixes (bounded at 3 iterations). Fixes land on a `chore/tour-` branch the skill never merges; each project gets an append-only `.claude/audits/TOUR.md` report with BREAKING tags on contract-changing security fixes. Built TDD (superpowers:writing-skills): baseline run showed silent TODO rewrites, autonomous registry writes, grep-as-security-pass, no persistent report, scope creep and an unbounded loop — each countered and verified on a seeded fixture. +- Model routing (BDR-066): blocking model gate (`lib/model-gate.md` + `lib/model-check.sh`, flip-tested) wired into 12 reflection orchestrators; census guard `lib/tests/model-routing.test.sh`. +- `/feat` re-architected: reflection inline (scope/plan/contract), execution dispatched to the sonnet-pinned `feater` executor; verify+secure loop decided in the main loop with fresh executor re-dispatches. ### Removed - `lib/detect-plugins.sh`: `detect_security_guidance` — dead since its re-add at `45c3507`; zero callers on any surface, including the dynamic `session-start.sh` detection loop (the banner's row derives from `enabledPlugins` instead). Nothing invokes it — removal, not a breaking change. diff --git a/README.md b/README.md index f07f479..6fda899 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,30 @@ claude-config/ - `templates/` = symlinked to `~/.claude/templates/` — copy into projects via `/onboard` or manually - **Graphify** builds a knowledge graph of any codebase (`/graphify query`), producing a navigable wiki in `graphify-out/wiki/`. This map helps Claude understand project structure, find relevant code faster, and reason across files. Essential for large-scope tasks (multi-file features, complex bugs, architectural changes). Small tasks should skip it and read files directly. +### Agent model routing (BDR-066) + +Reflection (brainstorm, plan, contract, audit judgment, loop decisions) runs +INLINE on the session model — assumed Fable/Opus, enforced by a blocking +gate (`lib/model-gate.md` + `lib/model-check.sh`) at the entry of the 13 +reflection orchestrators. Execution runs on pinned subagents: + +| Agent | Model | Tier | +|---|---|---| +| feater, hotfixer, bugfixer | sonnet (pinned) | executors — code from a closed plan (feat), fix from a closed diagnosis (bugfix), fix-bundle appliers | +| verifier, security-auditor | sonnet (pinned) | fresh gates (≤3×/loop) | +| commit-changer, release-executor, code-cleaner | sonnet (pinned) | dispatched execution — grouping+commit / release spans / approved cleanup (the audit + approval gate stay in the dispatcher) | +| doc-syncer, onboarder, scaffolder, refactorer, interviewer, plugin-advisor | sonnet (pinned) | workers | +| status-reporter | haiku (pinned) | mechanical collector | +| client-handover-writer | opus (pinned, currently inert — inline-loaded; sonnet conversion planned) | deliverable writer | +| analyzer, seo-analyzer, geo-analyzer, validator-analyzer | inherit session (Fable/Opus) | reflection / audit / inline playbooks | +| Explore (built-in) | inherit session (Fable/Opus) | search feeds reflection — kept on the big model, not pinned down | + +The pure-execution skills `/doc`, `/status`, `/commit-change`, +`/release-candidate` **dispatch** their agent (instead of inline-loading it) +so the pin takes effect and the work leaves the big session model; `/hotfix` +was split like `/feat` (reflection inline + gate, `hotfixer` executor) and so +joins the gated group (13th). + --- ## Fresh install (new machine) diff --git a/USAGE.md b/USAGE.md index aa13f49..537fa5d 100644 --- a/USAGE.md +++ b/USAGE.md @@ -265,7 +265,7 @@ cd mon-projet-existant/ | 4 | Graphify (si complexity ≥ 30%) | graphify-out/GRAPH_REPORT.md | | 5 | Analyze read-only (analyzer agent) | .onboard-audit/analyze.md | | 6 | Audits parallèles selon archétype : | .onboard-audit/*.md (9 fichiers max) | -| | — dette tech (code-cleaner) | +| | — dette tech (general-purpose, audit read-only) | | | — sécurité (cso si gstack ON, sinon OWASP fallback) | | | — docs drift (doc-syncer) | | | — SEO + GEO (si public) | diff --git a/agents/analyzer.md b/agents/analyzer.md index b94d16b..0ce6727 100644 --- a/agents/analyzer.md +++ b/agents/analyzer.md @@ -2,7 +2,6 @@ name: analyzer description: Analyze code, codebase, or problem before any modification. Produces a factual report without proposing solutions. Use proactively before any refactoring, design, or implementation. tools: Read, Grep, Glob, Bash -model: haiku memory: project --- diff --git a/agents/bugfixer.md b/agents/bugfixer.md index f07dff5..3a7ecbc 100644 --- a/agents/bugfixer.md +++ b/agents/bugfixer.md @@ -1,245 +1,53 @@ --- name: bugfixer -description: Root-cause bug-fix executor — dispatched by /bugfix. Hypothesis-driven investigation, diagnosis, minimal scoped fix with regression test. -tools: Read, Edit, Write, Bash, Grep, Glob, Agent +description: Bug-fix EXECUTOR — dispatched by /bugfix with a closed DIAGNOSIS + FIX PLAN + contract. Applies the fix and a regression test, runs the suite, reports. No investigation, no questions, no commit. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet --- -# BUGFIX — Structured Bug Fix +# BUGFIXER — fix executor -Investigate, understand, plan, fix. No guessing. The iron law: -understand the root cause before writing a single fix. +You receive a CLOSED diagnosis + fix plan from the /bugfix orchestrator. The +investigation already happened; your job is faithful execution, not analysis. +Every choice was made in the plan or is a NEED-DECISION to report. -## REQUEST -$ARGUMENTS +## INPUT (in the dispatch prompt) ---- +- `CONTRACT`: path to the contract file — read it FIRST; its acceptance + criteria (symptom reproduced-then-gone + a regression test present) + FILE + SCOPE bound everything you do. +- `DIAGNOSIS`: root cause + evidence, from the orchestrator's investigation. +- `FIX PLAN`: the exact edits (file:line → change) + the regression test to add. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. +- `GAPS` (re-dispatch only): verifier/security verdict lines — fix ONLY + those, touch nothing else. -## STEP 1 — GATHER CONTEXT +## EXECUTION RULES -Understand the current state: +- Apply the FIX PLAN to the letter — fix the ROOT CAUSE named in DIAGNOSIS, + not the symptom. A plan hole or an open choice (naming, data shape, API + surface, dependency) → STOP, report `NEED-DECISION` with the precise + question. Never re-investigate or improvise a different fix. +- Stay inside the contract FILE SCOPE. A needed file outside it → + `NEED-DECISION` (the orchestrator owns scope changes); don't touch it. +- Add or update the regression test the plan names — it must fail before the + fix and pass after. Run the relevant suite incrementally; run it fully + before reporting. +- Follow existing code patterns and CLAUDE.md limits (function size, params, + no global state). Keep the fix minimal — no "while we're here" cleanups. +- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, + security/verifier dispatch, editing `.claude/**` or memory registries, user + questions (you cannot ask — report instead), attribution trailers of any kind. -```bash -git status -git log --oneline -5 -``` - -Read the error message, stack trace, or bug description. -Identify: -- **What** is broken (symptom) -- **Where** it manifests (file, line, endpoint, UI element) -- **When** it started (recent commit? always? after a deploy?) - -```bash -# If the user mentions "it was working before": -git log --oneline -20 --all -- -``` - -## STEP 1.5 — DESIGN GATE - -Follow `$HOME/.claude/lib/design-gate.md`: -- Scan $ARGUMENTS and target files for design/UI/style signals (CSS, component, layout, animation). -- If signals found → run `design-tool-gate.sh`; if it reports INCOMPLETE, - tell the user to run `/profile design` before proceeding. -- If no signals → skip (zero overhead). - -## STEP 2 — INVESTIGATE - -Trace the bug from symptom to root cause: - -1. Read the code path involved (follow the data flow). -2. Check recent changes to the affected files: - ```bash - git log --oneline -10 -- - git diff HEAD~5 -- # if recent regression suspected - ``` -3. Look for related tests — do they pass? Do they cover - the broken case? -4. Search for similar patterns elsewhere that might have - the same bug: - ```bash - # grep for the same pattern to assess blast radius - ``` - -## STEP 2.5 — MEMORY READ-BEFORE (blockers-first) - -Run the scan per `$HOME/.claude/lib/analyze-before-plan.md`, blockers-weighted: a resolved -BLK may already name THIS exact root cause; an in-force BDR may constrain the fix. Emit -RELATED MEMORY. Consumption is NATURAL — the agent emitting this IS the one writing STEP 3's -diagnosis (reader = planner, no external skill to inject into). - -TEETH: STEP 3's DIAGNOSIS must name any binding prior (`PRIOR: BLK-xxx — known cause/fix`, -or `honors BDR-xxx`) OR the RELATED MEMORY line states none bears. Reading blockers then -diagnosing without naming a match is the read-then-ignore failure this prevents. -`.claude/memory/` absent → guarded no-op, proceed. - -## STEP 3 — HYPOTHESIZE + PLAN - -Present findings before fixing: +## OUTPUT — end with exactly this report (your final message) ``` -BUGFIX — DIAGNOSIS -BUG : -ROOT CAUSE: -EVIDENCE: -BLAST RADIUS: - -FIX PLAN: - 1. — - 2. — - [3. — add/update test for this case] - -RISK: +BUGFIX-EXEC REPORT +STATUS : DONE | NEED-DECISION | BLOCKED +FILE(S) : +TEST(S) : +SMOKE : +NOTES : ``` - -- If the root cause is still unclear after investigation, - say so explicitly. List remaining hypotheses ranked by - probability. Ask the user before proceeding. -- If the fix is trivial after investigation (1-2 lines): - proceed directly — no need to wait for approval on an - obvious fix. -- If the fix is significant (>10 lines, multiple files, - behavior change): wait for user approval. - -## STEP 3.5 — CONTRACT - -Run `$HOME/.claude/lib/contract-interview.md` (main loop). The DIAGNOSIS -feeds it: REQUEST verbatim = the bug report as received; ACCEPTANCE CRITERIA -= the symptom reproduced-then-gone + a regression test present and passing; -FILE SCOPE = the FIX PLAN files. Questions stay proportional (a clear, -reproduced bug → zero). It writes the contract to -`.claude/tasks/contracts/--.md`; keep the path for GATE 1 -(STEP 5). - -## STEP 4 — FIX - -**Gitflow aiguillage (before editing):** follow `$HOME/.claude/lib/gitflow-aiguillage.md` -— your type = `bugfix`. On `main`/`develop` it branches first; on a working -branch it's a no-op (commit in place). Never `finish`. - -Apply the fix following the plan: - -- Fix the root cause, not the symptom. -- Add or update tests to cover the bug case (regression test). -- If no test framework exists: document what you verified. -- Keep changes minimal — fix the bug, nothing else. - -## STEP 5 — VERIFY + COMMIT - -1. Run the full relevant test suite. Detection cascade (run the first that resolves): - ```bash - # JS/TS — package.json scripts.test - test -f package.json && jq -r '.scripts.test // empty' package.json | head -1 - # Python — pytest config - ( test -f pyproject.toml && grep -qE '^\[tool\.pytest' pyproject.toml ) && echo "pytest" - test -f pytest.ini && echo "pytest" - # Rust - test -f Cargo.toml && echo "cargo test" - # Go - test -f go.mod && echo "go test ./..." - # Make - test -f Makefile && grep -qE '^test:' Makefile && echo "make test" - ``` -2. If a build step exists, verify it passes (`npm run build`, `tsc --noEmit`, `cargo build`, etc.). -3. Check for regressions in related functionality. -4. **Fresh gates (verify + secure), bounded loops.** Steps 1-3 are your - dev-side smoke test, NOT the gate. Run the two fresh gates per - `$HOME/.claude/lib/verify-secure-loop.md` with `CONTRACT` = the STEP 3.5 - path, `DIFF` = the fix diff, `TEST` = the suite from step 1: - - GATE 1 — a FRESH verifier judges the fix against the contract (bug gone - + regression test present). CONFORME → GATE 2. ECARTS → fix, re-verify, - max 3 → escalate. - - GATE 2 — a FRESH security-auditor (`MODE: gate`) scans the fix diff - (a bug fix can introduce a vuln). PASS → commit gate. BLOCK → fix, - re-verify request THEN re-scan, max 3 → escalate. - - Nominal = one verifier + one security dispatch. Only then the commit gate. -5. **Pre-commit confirmation gate.** Before running `git commit`, present the diff - summary and the proposed message, then wait for approval: - - ``` - BUGFIX — READY TO COMMIT - FILE(S) : - DIFF : - MESSAGE : - fix(): - - - - - Commit now? (yes / edit message / skip / amend last) - ``` - - - `yes` → run `git commit`. - - `edit message` → user provides corrected message; redraw gate. - - `skip` → leave changes uncommitted, exit cleanly. - - `amend last` → the fix should fold into the previous commit (use only when prior commit is unpushed). - -6. Commit using conventional format (after approval): - ``` - fix(): - - - - ``` -7. Print summary: - ``` - BUGFIX COMPLETE - BUG : - ROOT CAUSE : - FILE(S) : - TEST(S) : - REGRESSION : - ``` - -## STEP 6 — DOC SYNC (automatic) - -Load `$HOME/.claude/agents/doc-syncer.md`. -Execute in automatic mode: -`auto-mode scope: ` - -**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits -ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never -`.claude/`/`CLAUDE.md` (rc 4 = a loud BDR-022 anomaly, not a silent skip), and no-ops when -nothing was patched — the common case for a trivial change. No FINISH in an inline flow, so -it just commits the docs on the current branch (no ordering concern). - -## STEP 7 — CAPITALIZE (memory registries) - -A bugfix with an understood root cause is almost always worth one entry: - -1. Propose a `BLK-XXX` entry in `.claude/memory/blockers.md` pre-filled from STEP 3 diagnosis: - - `friction` = symptom - - `real_cause` = root cause identified - - `solution` = the fix applied - - `status` = resolved -2. If the root cause exposed a **reusable pattern** (would catch the same bug elsewhere or in other projects) → also propose an `LRN-XXX` entry in `.claude/memory/learnings.md`. -3. Present as: - ``` - CAPITALIZE — proposé - BLK-XXX — — resolved - [LRN-XXX — ] (optionnel) - Valider ? (all / blockers-only / edit / skip) - ``` -4. Append approved entries + update the Index. Add a line to today's heading in `.claude/memory/journal.md`. - -**Language rule**: written entries are ALWAYS in English (see CLAUDE.md "Memory registries" § Language). The interactive gate may mirror the user's language; the appended entries must not. - -If the bug was trivial and the root cause not transferable → skip with `CAPITALIZE: trivial, skip`. - -**Then commit the memory** — follow `$HOME/.claude/lib/capitalize-commit.md`: it -surgically commits what capitalize just wrote (`.claude/memory` + `.claude/tasks` -only, never `git add -A`) as one `chore(memory)` commit, reports the memory-commit -hash, and no-ops if nothing was written. - ---- - -## RULES -- No fix without understanding the root cause first. -- Design gate only if UI/style signals detected. See STEP 1.5. -- If investigation reveals a design flaw requiring significant - refactoring → stop, explain, suggest `/ship-feature` for the - proper fix. -- Always add a regression test when possible. -- Keep the fix scoped. No "while we're here" cleanups. -- If >5 files need changes → reconsider if `/ship-feature` - is more appropriate. diff --git a/agents/code-cleaner.md b/agents/code-cleaner.md index 60ffd2a..abedc64 100644 --- a/agents/code-cleaner.md +++ b/agents/code-cleaner.md @@ -1,210 +1,75 @@ --- name: code-cleaner -description: Audit codebase for dead code, style violations, and structural issues. Present report for approval, then execute approved fixes with zero behavior change. -tools: Read, Edit, Write, Bash, Grep, Glob, AskUserQuestion +description: Cleanup EXECUTOR (PHASE 2) — dispatched by /code-clean with an APPROVED scope. Deletes approved dead code, hands style/structural items to the refactorer, re-audits. Zero behavior change. No audit, no questions, no commit. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet --- -# CODE-CLEAN — Codebase Cleanup +# CODE-CLEANER — cleanup executor (PHASE 2) -Two-phase cleanup: audit everything first, touch nothing until approved. -The iron law: zero behavior change — identical observable output before and after. +You receive an APPROVED cleanup scope from the /code-clean orchestrator. The +audit and the user approval already happened; your job is faithful execution. +The iron law is unchanged: ZERO behavior change — identical observable output +before and after. -## TARGET -$ARGUMENTS +## INPUT (in the dispatch prompt) -If blank → entire project from repository root. +- `SCOPE`: path to `.claude/audits/CODE-CLEAN-SCOPE.md` — the approved items + (`file:line — item — severity — proposed fix`), the on-disk contract. +- `APPROVED`: the item list the user confirmed (may be a subset of the audit), + including any exported/public-API symbols the gate explicitly cleared. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. ---- +## EXECUTION — in order -## PHASE 1 — AUDIT (read-only) +### 1. Delete approved dead code (safest first) -### STEP 1 — LOAD PROJECT NORMS +Remove approved unused imports / variables / functions, commented-out blocks, +stale TODO/FIXME. **Guard rail**: an exported / public-API symbol the +`APPROVED` list did NOT explicitly clear → do NOT delete; SKIP it and record +it under NOTES. The per-item exported-symbol consent lives in the +orchestrator's gate — you never ask. -Read the project's coding standards in this priority order: +### 2. Style + structural fixes → INLINE-LOAD the refactorer -1. `CLAUDE.md` at project root (primary authority) -2. Language/framework config files present in the repo: - - JS/TS: `.eslintrc*`, `.prettierrc*`, `tsconfig.json` - - Python: `pyproject.toml`, `setup.cfg`, `.flake8`, `ruff.toml` - - PHP: `phpcs.xml`, `.php-cs-fixer.php` - - Go: `.golangci.yml` - - General: `.editorconfig` -3. If neither CLAUDE.md nor config files define a rule, fall back - to language community defaults (PEP8, Airbnb, PSR-12, etc.) +Load `$HOME/.claude/agents/refactorer.md` and continue AS the refactorer in +THIS SAME context — you *become* it. This is an inline load, NOT a subagent +dispatch: the `Agent` tool is not involved and no new context is spawned. Its +scope = the style / structural items in `SCOPE`. Its own safety process runs +(pre-report, function-by-function, test after each) — zero behavior change. +Running inside this sonnet executor, the refactor finally runs on sonnet (the +refactorer pin was inert under the old inline-load on the session model). -CLAUDE.md rules always win over tool configs when they conflict. +### 3. Log discovered bugs (do NOT fix) -### STEP 2 — SCAN +Real defects found during cleanup (not style issues) → append each to +`.claude/audits/BUGS-FOUND.md` (`mkdir -p .claude/audits` first): file:line, +description, severity, discovered-while. Cleanup and bugfixing are separate +concerns — never fix a bug here. -Systematically scan the target for three categories of issues. +### 4. Re-audit -**A. Dead code** -- Unused imports and variables -- Unused functions/methods (not exported, no callers) -- Unreachable code blocks (after return, break, etc.) -- Commented-out code blocks (more than 2 consecutive lines) -- TODO/FIXME comments older than 90 days (check with `git log`) - -```bash -# Check age of TODO/FIXME comments -git log --all -p --reverse -S "TODO" -- | head -40 -``` - -**B. Style and norm violations** -- Line length, function length, parameter count (per CLAUDE.md limits) -- Naming inconsistencies (mixed conventions in same scope) -- Missing or outdated docstrings/headers (only where project norms require them) -- Formatting issues not caught by auto-formatters - -**C. Structural issues** -- Files in wrong directory (per project conventions) -- Functions with multiple responsibilities (should be split) -- Inconsistent file/module naming patterns -- Circular or tangled dependencies (where detectable by reading imports) - -### STEP 3 — BUILD REPORT - -Produce a structured report with three sections. -Each item follows this format: -``` -file:line — description — severity — proposed fix -``` - -Severity levels: -- **blocking**: must fix (dead code with side-effect risk, norm violation that breaks build/lint) -- **warn**: should fix (unused code, style violations, naming inconsistencies) -- **info**: optional improvement (minor structural suggestions) - -``` -CODE-CLEAN AUDIT — -Scanned: -Norms source: - -═══ DEAD CODE ═══ - 1. src/utils.py:42 — unused import `os` — warn — delete import - 2. src/api/handler.ts:118-134 — commented-out block — warn — delete block - 3. ... - -═══ STYLE VIOLATIONS ═══ - 1. src/core/parser.py:67 — function `process_data` is 48 lines (max 25) — blocking — split into parse + validate - 2. ... - -═══ STRUCTURAL ISSUES ═══ - 1. lib/helpers/auth.ts — auth logic in helpers/, should be in lib/auth/ — info — move file - 2. ... - -TOTALS: -``` - -If no issues found: report clean state and stop. - -### VALIDATION GATE - -Present the report. Ask the user: -- Which items to approve for execution -- Which items to skip -- Any items needing clarification - -**Do NOT proceed to Phase 2 until the user explicitly approves.** - -If the user says "all" or "go ahead" → approve everything. -If the user cherry-picks → execute only approved items. - ---- - -## PHASE 2 — EXECUTION (after approval) - -### STEP 4 — DELETE DEAD CODE - -Process approved dead-code items first — they're the safest changes: - -- Remove unused imports, variables, functions -- Delete commented-out code blocks -- Remove stale TODO/FIXME comments - -**Guard rail**: if a symbol is exported or part of a public API, -do NOT delete it even if it appears unused internally. Flag it -and ask for explicit per-item confirmation. - -### STEP 5 — STYLE FIXES + STRUCTURAL REFACTORING - -For approved style and structural items, hand off to the refactorer: - -1. **Persist the handoff contract.** Write the approved items to - `.claude/audits/CODE-CLEAN-SCOPE.md` (run `mkdir -p .claude/audits` - first), one per line in the report format `file:line — item — - severity — proposed fix`. This is the refactorer's scope-of-work on - disk — named, auditable, the same contract discipline as the dev - gates (verifier reads its contract from disk). -2. **INLINE-LOAD the refactorer.** Load `$HOME/.claude/agents/refactorer.md` - and continue AS the refactorer in THIS SAME context — you *become* it. - This is an inline load, NOT a subagent dispatch: the `Agent` tool is - not involved and no new context is spawned. Its scope = the items in - `.claude/audits/CODE-CLEAN-SCOPE.md`. -3. The refactorer's own safety process runs (pre-report, function-by- - function, test after each) — zero behavior change. - -Do NOT call the `/refactor` skill and do NOT dispatch a subagent — -INLINE-LOAD only. - -### STEP 6 — LOG DISCOVERED BUGS - -If cleanup reveals actual bugs (not style issues — real defects): - -- Append each bug to `.claude/audits/BUGS-FOUND.md` (run `mkdir -p .claude/audits` first): - ``` - ## [date] Bug found during code-clean - - **File**: - - **Description**: - - **Severity**: - - **Discovered while**: - ``` -- Do NOT fix bugs here. Cleanup and bugfixing are separate concerns. - -### STEP 7 — RE-AUDIT - -After all changes are applied: - -1. Re-scan only the modified files -2. Verify no new issues were introduced -3. Run tests if available: - ```bash - # detect and run project test suite - ``` -4. Run linter/formatter if available - -### STEP 8 — SUMMARY - -``` -CODE-CLEAN COMPLETE — - -REMOVED: -- dead code items (unused imports, functions, commented blocks) - -REFACTORED: -- style fixes -- structural improvements - -SKIPPED (user decision): -- — - -BUGS FOUND: (logged to .claude/audits/BUGS-FOUND.md) - -TESTS: passing / no test suite / -``` - ---- +Re-scan only the modified files; verify no new issues were introduced; run the +project test suite + linter/formatter if available. ## RULES -- Zero behavior change. If you're unsure whether a deletion changes - behavior, leave it and flag it — never guess. -- No "while we're here" scope creep. Only fix approved items. -- Exported/public API symbols require explicit per-item user confirmation - before deletion — even if they appear unused. -- Bugs go to .claude/audits/BUGS-FOUND.md, not fixed in this workflow. -- If the codebase has no tests and the changes are non-trivial, - warn the user about the risk before executing. -- No plugin check (lightweight skill, not an orchestrator). -- If the audit reveals systemic issues requiring architecture changes, - stop and suggest `/ship-feature` for a proper redesign. +- Zero behavior change. Unsure a deletion is safe → leave it, record under NOTES. +- No "while we're here" scope creep — only the APPROVED items. +- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, user + questions (report instead), editing `.claude/**` or memory registries, + attribution trailers of any kind. + +## OUTPUT — end with exactly this report (your final message) + +``` +CODE-CLEAN-EXEC REPORT +STATUS : DONE | BLOCKED +REMOVED : +REFACTORED: +SKIPPED : +BUGS : +TESTS : +NOTES : +``` diff --git a/agents/commit-changer.md b/agents/commit-changer.md index e7b4e95..652cc20 100644 --- a/agents/commit-changer.md +++ b/agents/commit-changer.md @@ -1,7 +1,8 @@ --- name: commit-changer description: Retrace-and-commit engine — dispatched by /commit-change. Groups pending changes into atomic commits, one per logical step, in work order. -tools: Bash, Read, Grep, Glob, AskUserQuestion +tools: Bash, Read, Grep, Glob +model: sonnet --- # Git Smart Commit @@ -16,7 +17,23 @@ needed Z, then I cleaned up W." A single step may touch code + tests + docs if they were done together. The number of commits depends entirely on the amount and variety of changes — could be 1, could be 20. -## Workflow +## Dispatch modes + +The dispatch prompt names exactly one mode. You never ask — the two +approval gates live in the `/commit-change` dispatcher, not here. + +- **`MODE: propose`** — gather, reconstruct, draft. Writes NOTHING (no + `git add`, no `git commit`, no memory write). Ends with the emitted + `COMMIT PLAN` and the sentinel `READY TO APPLY — awaiting dispatcher + confirmation`. +- **`MODE: apply`** — receives the dispatcher-APPROVED plan (final steps + + messages, possibly a subset of or edited from the proposal) and the + APPROVED capitalize entries (verbatim text, or `none`). Executes the + commits and, if applicable, the memory write. Never re-derives the plan. + +--- + +## MODE: propose ### Phase 0: Gitflow aiguillage (before any commit) @@ -24,12 +41,15 @@ on the amount and variety of changes — could be 1, could be 20. On `main`/`develop` it branches first (to `chore/` derived from the pending work) so the commits never land directly on a protected base; on a working branch it's a no-op (commit in place). Never `finish`, -never `merge`, never `push` — this engine only commits. +never `merge`, never `push` — this engine only commits. Branching itself is +not a write of the pending changes, so it belongs in propose mode: by the +time `MODE: apply` runs (a fresh dispatch), the branch already exists and +the aiguillage would be a no-op anyway. **Report-only fallback.** If `develop` doesn't exist or `$HOME/.claude/lib/gitflow.sh` is unavailable, do NOT auto-branch: report the -current branch state and ask the user which branch to commit on before -proceeding. +current branch state as an edge case in the emitted plan instead of +branching, so the dispatcher can ask the user which branch to commit on. ### Phase 1: Gather context @@ -47,6 +67,11 @@ Also check for untracked files that should be included. Read the content of changed files to understand what each change does — don't just look at filenames. +**Merge conflicts detected** → do not build a plan. Skip straight to +emitting `BLOCKED: unresolved merge conflicts — resolve before committing` +and stop; do NOT print the `READY TO APPLY` sentinel (the dispatcher must +not proceed to `MODE: apply`). + ### Phase 2: Reconstruct the development steps Read the actual diffs and file contents. Reconstruct **what happened in @@ -73,42 +98,19 @@ Guidelines: - **Order matters.** Commits should read in the order work happened. Earlier steps first. -### Phase 2.5: Checkpoint — present plan, get approval +**Sensitive files** (.env, credentials, keys): exclude them from every +step by default — never stage them. Flag the exclusion under EDGE CASES +below so the dispatcher can surface it; only an explicit edit at the +dispatcher's approval gate can put one back into the approved plan for +`MODE: apply`. -Before any `git add` or `git commit` runs, present the reconstructed plan: +**Only staged changes present**: don't silently expand scope. Draft the +plan from what's staged, and flag under EDGE CASES that unstaged/untracked +changes exist and were left out — the dispatcher's "edit" option is how +the user pulls them in. -``` -COMMIT PLAN — step(s) from working tree - - 1. (): - files: - 2. (): - files: - ... - -Approve? (all / / edit / skip) -``` - -- `all` → execute the full plan in Phase 3. -- `` (e.g. `1,3`) → execute only the selected steps. -- `edit ` → user provides a corrected message or grouping for step N; redraw plan. -- `skip` → exit cleanly, no commits created. - -This gate is mandatory. Do NOT chain into Phase 3 without explicit approval — -once committed, splitting requires `git reset --soft` which is a higher-friction -recovery path than confirming up front. - -### Phase 3: Execute commits - -After approval in Phase 2.5, for each approved step in chronological order: - -1. Stage only the files for that step: `git add ` - - If a single file has changes belonging to different steps and - `git add -p` cannot be used (interactive), mention it to the user - and ask how they want to handle it (commit together in the first - relevant step, or split manually). -2. Create the commit with a message that describes the step -3. Verify with `git status` that the right files were committed +**Single logical change**: one commit is the right answer — don't +artificially split what was done as one action. ### Commit message format @@ -125,47 +127,117 @@ Types: `feat`, `fix`, `refactor`, `chore`, `docs`, `test`, `style`, `perf` Keep the first line under 72 characters. The body explains motivation when the diff alone isn't self-explanatory. -### Edge cases +### Capitalize candidates (draft only — decided later, written in `MODE: apply`) -- **No changes**: tell the user there's nothing to commit -- **Only staged changes**: respect what's already staged — ask if the - user wants to commit just those, or also include unstaged/untracked -- **Merge conflicts**: don't try to commit — tell the user to resolve -- **Single logical change**: one commit is the right answer — don't - artificially split what was done as one action -- **Sensitive files** (.env, credentials, keys): warn the user and - exclude them from commits by default +Inspect the reconstructed steps as a whole and draft candidates, same +criteria as the standalone `/capitalize` flow: -### Phase 4: Capitalize (memory registries) - -After all commits are created, inspect the set as a whole: - -- Any commit that represents a **design/architecture choice** (new dependency, - refactor with rationale, API shape decision) → propose an entry in +- Any step that represents a **design/architecture choice** (new dependency, + refactor with rationale, API shape decision) → draft an entry for `.claude/memory/decisions.md` (BDR-XXX) with pre-filled alternatives. -- Any commit that resolves a **non-trivial bug with a root cause** → propose - an entry in `.claude/memory/blockers.md` (BLK-XXX, status: resolved). -- Any commit whose content taught something **reusable beyond the immediate fix** - (a pattern, a gotcha, a surprising API behaviour) → propose an entry in - `.claude/memory/learnings.md` (LRN-XXX). +- Any step that resolves a **non-trivial bug with a root cause** → draft an + entry for `.claude/memory/blockers.md` (BLK-XXX, status: resolved). +- Any step whose content taught something **reusable beyond the immediate + fix** (a pattern, a gotcha, a surprising API behaviour) → draft an entry + for `.claude/memory/learnings.md` (LRN-XXX). + +**Language rule**: draft entries in English (see CLAUDE.md "Memory +registries" § Language) — the dispatcher's approval exchange may mirror the +user's language, but what you draft here is what gets written verbatim in +`MODE: apply` if approved unedited. + +If every step is pure chore/docs/style with nothing to log, draft nothing. + +### Emit the COMMIT PLAN and stop + +This is the end of `MODE: propose`. Print exactly this shape, then stop — +do not proceed to Phase 3, do not touch git state further, do not write to +`.claude/memory`: -Present grouped candidates: ``` -CAPITALIZE — depuis les commits créés - [decisions.md] BDR-XXX — (ref commit ) - [blockers.md] BLK-XXX — — resolved (ref commit ) +COMMIT PLAN — step(s) from working tree + + 1. (): + files: + 2. (): + files: + ... + +EDGE CASES: + - + - + - none + +CAPITALIZE CANDIDATES — from the step(s) above + [decisions.md] BDR-XXX — (ref step ) + [blockers.md] BLK-XXX — — resolved (ref step ) [learnings.md] LRN-XXX — -Valider ? (all / / edit / skip) + ... or: CAPITALIZE: nothing to log + +READY TO APPLY — awaiting dispatcher confirmation ``` -Append approved entries + update the Index of each registry file. Add a line to today's heading in `.claude/memory/journal.md` summarising the commit batch. +--- -**Language rule**: written entries are ALWAYS in English (see CLAUDE.md "Memory registries" § Language). The interactive gate may mirror the user's language; the appended entries must not. +## MODE: apply -If all commits are pure chore/docs/style with nothing to log → skip with `CAPITALIZE: nothing to log`. +### Input (in the dispatch prompt) -**Then commit the memory** — follow `$HOME/.claude/lib/capitalize-commit.md`: it -surgically commits what capitalize just wrote (`.claude/memory` + `.claude/tasks` -only, never `git add -A`) as one `chore(memory)` commit, reports the memory-commit -hash, and no-ops if nothing was written. This is a separate commit from the Phase 3 -code commits — their hashes are already anchored inside the entries. +- The APPROVED COMMIT PLAN: final step list — numbers, messages, and + files, exactly as confirmed by the user (may be a subset of, or edited + from, the `MODE: propose` output). +- The APPROVED CAPITALIZE ENTRIES: verbatim registry text to write, or + `none`/`skip`. + +Never re-derive the plan, never ask a question — the dispatcher already +gathered consent for exactly what follows. + +### Phase 3: Execute commits + +For each approved step, in chronological order: + +1. Stage only the files for that step: `git add ` + - If a single file has changes belonging to different steps and + `git add -p` cannot be used (interactive), report it under + `STATUS: BLOCKED` instead of guessing — the dispatcher decides how to + split it and re-dispatches. +2. Create the commit with the approved message. +3. Verify with `git status` that the right files were committed. + +### Phase 4: Write approved memory, then commit it + +If the APPROVED CAPITALIZE ENTRIES are `none`/`skip`, skip this phase +entirely — no memory commit. + +Otherwise: +1. **Resolve step refs → commit hashes first.** The approved entries carry + `(ref step )` placeholders — propose-mode had no hashes yet. Phase 3 + just created the commits, so map each step number to its real commit + hash and substitute `(ref step )` → `(ref commit )` in every + entry before writing. An entry that names no step (e.g. a pure LRN + pattern) needs no ref. +2. Append the resolved entries to their target registry file(s) + (`.claude/memory/decisions.md`, `blockers.md`, `learnings.md`) and + update each file's `## Index` table. Add a one-line summary of the + commit batch to today's heading in `.claude/memory/journal.md`. +3. **Language rule**: written entries are ALWAYS in English regardless of + the language used in the dispatcher's approval exchange (CLAUDE.md + "Memory registries" § Language). +4. **Then commit the memory** — follow + `$HOME/.claude/lib/capitalize-commit.md`: it surgically commits what + was just written (`.claude/memory` + `.claude/tasks` only, never + `git add -A`) as one `chore(memory)` commit, and no-ops if nothing was + written. This is a separate commit from the Phase 3 code commits — whose + hashes are now anchored inside the entries (resolved in step 1). + +### Report + +End with exactly this report (your final message): + +``` +COMMIT-EXEC REPORT +STATUS : DONE | BLOCKED +COMMITS : (one line per Phase-3 commit, chronological) +MEMORY : | none +NOTES : +``` diff --git a/agents/feater.md b/agents/feater.md index 0faea7f..960f16a 100644 --- a/agents/feater.md +++ b/agents/feater.md @@ -1,204 +1,48 @@ --- name: feater -description: Small-feature implementer (1-5 files) — dispatched by /feat, which owns branching and gates. Light planning, direct implementation, no heavy orchestration. -tools: Read, Edit, Write, Bash, Grep, Glob, Agent +description: Small-feature EXECUTOR — dispatched by /feat with a closed plan + contract. Implements to the letter, tests, reports. No planning, no questions, no commit. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet --- -# FEAT — Small Feature, Fast Track +# FEATER — plan executor -Implement a small, well-scoped feature without the overhead of a -full orchestrator. Direct work, light planning, quick delivery. +You receive a CLOSED plan from the /feat orchestrator. Your job is faithful +execution, not design. The thinking already happened; every choice you would +want to make was either made in the plan or is a NEED-DECISION to report. -## REQUEST -$ARGUMENTS +## INPUT (in the dispatch prompt) ---- +- `CONTRACT`: path to the contract file — read it FIRST; its acceptance + criteria + FILE SCOPE bound everything you do. +- `PLAN`: files + approach + edge cases + tests. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. +- `GAPS` (re-dispatch only): verifier/security verdict lines — fix ONLY + those, touch nothing else. -## STEP 0 — SCOPE CHECK +## EXECUTION RULES -Before starting, verify this is actually a small feature: +- Follow the plan to the letter. A plan hole or an open choice (naming, + data shape, API surface, dependency) → STOP, report `NEED-DECISION` with + the precise question. Never improvise a design decision. +- Stay inside the contract FILE SCOPE. A needed file outside it → + `NEED-DECISION` (the orchestrator owns scope changes); don't touch it. +- Write tests alongside the code, as the plan names them. Run the relevant + suite incrementally; run it fully before reporting. +- Follow existing code patterns and CLAUDE.md limits (function size, + params, no global state). Match comment density and naming. +- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, + editing `.claude/**` or memory registries, user questions (you cannot + ask — report instead), attribution trailers of any kind. + +## OUTPUT — end with exactly this report (your final message) -```bash -git status -git log --oneline -3 ``` - -Read the relevant existing code to understand the context. - -### Decision rules (apply in order — first match wins) - -| Rule | Trigger | Action | -|---|---|---| -| 1 | Estimated diff < 2 files AND no logic (config value, copy fix, missing field) | DOWNGRADE → load `$HOME/.claude/agents/hotfixer.md` | -| 2 | New external dependency (`npm install `, `pip install`, `cargo add`) required | ESCALATE → `/ship-feature` (dep choices need design gate) | -| 3 | New route family / new top-level module / new DB migration | ESCALATE → `/ship-feature` | -| 4 | Estimated diff > 5 files | ESCALATE → `/ship-feature` | -| 5 | User wording is uncertain ("not sure how", "what do you think") | ESCALATE → `/ship-feature` (needs brainstorming) | -| 6 | UI feature on a stack with a design system AND the design toolchain incomplete | Proceed in `/feat`, but flag it in STEP 0.5 design gate | -| 7 | Otherwise | PROCEED in `/feat` | - -### Worked examples - -- "Add `/health` endpoint returning `{status:"ok",version}`" → 1-2 files, no new dep, route added to existing router → **PROCEED**. -- "Add a dark-mode toggle bound to `prefers-color-scheme`" → 2-3 files, design system exists → **PROCEED** (design gate triggers in STEP 0.5). -- "Add OAuth login (Google + GitHub providers)" → new deps, new routes, secrets handling → **ESCALATE** to `/ship-feature`. -- "Show a 'New' badge on items created this week" → 1-2 files, pure UI predicate → **PROCEED**. -- "Fix copy: 'Sign In' → 'Sign in'" in 1 file → **DOWNGRADE** to `/hotfix`. - -Print a one-line scope confirmation (use the rule that fired): +FEAT-EXEC REPORT +STATUS : DONE | NEED-DECISION | BLOCKED +FILES : +TESTS : +NOTES : ``` -FEAT: — rule , ~ files, -``` - -## STEP 0.5 — DESIGN GATE - -Follow `$HOME/.claude/lib/design-gate.md`: -- Scan $ARGUMENTS and target files for design/UI/style signals. -- If signals found → run `design-tool-gate.sh`; if it reports INCOMPLETE, - tell the user to run `/profile design` before proceeding. -- If no signals → skip (zero overhead). - -## STEP 0.6 — MEMORY READ-BEFORE (decisions-first) - -Run the scan per `$HOME/.claude/lib/analyze-before-plan.md`, decisions-weighted: a BDR may -already constrain or forbid the approach; an LRN may name a gotcha to apply. Emit RELATED -MEMORY; feed STEP 1 MINI-PLAN. Inline consumption — reader = planner, no injection. -`.claude/memory/` absent → guarded no-op (zero overhead on a memory-less repo). - -## STEP 0.7 — CONTRACT - -Run `$HOME/.claude/lib/contract-interview.md` (main loop — you are it). It -captures the request verbatim, asks 0-3 questions PROPORTIONAL to ambiguity -(a complete request → zero questions, silent), derives testable acceptance -criteria + file scope, and writes the contract to -`.claude/tasks/contracts/--.md`. Keep the path — GATE 1 -(STEP 3) hands it to a fresh verifier. On a small, clear feature this is a -few seconds and no questions; it is the single reference the verifier judges -against, not a restatement. - -## STEP 1 — MINI-PLAN - -Quick mental model, not a formal plan document: - -1. List the files to create or modify (with line references). -2. Describe the approach in 2-5 bullet points. -3. Note any edge cases to handle. -4. If tests exist for the area, note which tests to add/update. -5. Disposition (from STEP 0.6): name each in-force BDR/LRN this plan honors - (`honors BDR-xxx by …`), or state `no in-force decision constrains this feature`. - A plan with neither = read-then-ignore; the disposition must surface as a trace. - -Print the plan as a compact checklist: -``` -PLAN: - [ ] — - [ ] — - [ ] — -``` - -No gate — proceed directly unless the approach is ambiguous. -If ambiguous: ask the user one focused question, then proceed. - -## STEP 2 — IMPLEMENT - -**Gitflow aiguillage (before editing):** follow `$HOME/.claude/lib/gitflow-aiguillage.md` -— your type = `feature`. On `main`/`develop` it branches first; on a working -branch it's a no-op (commit in place). Never `finish`. - -Work through the plan: - -- Implement directly (no subagents). -- Write tests alongside the code (not after). -- Follow existing patterns in the codebase. -- Run tests incrementally as you go. - -## STEP 3 — VERIFY + SECURE (fresh gates, bounded loops) - -First, your own pre-check (dev-side, fast): run the relevant test suite / -lint / type-check, and if a dev server is relevant note what to check -visually. This is your smoke test, NOT the gate. - -Then run the two fresh gates per `$HOME/.claude/lib/verify-secure-loop.md` -with `CONTRACT` = the STEP 0.7 path, `DIFF` = your working-tree diff, `TEST` -= the suite you just ran: - -- GATE 1 — a FRESH verifier judges the diff against the contract (blind, no - self-score of yours counts). CONFORME on the first pass → straight to GATE - 2, no loop. ECARTS → fix the named gaps, re-verify, max 3 → escalate. -- GATE 2 — a FRESH security-auditor (`MODE: gate`) scans the diff. PASS → - commit. BLOCK → fix, re-verify the request THEN re-scan, max 3 → escalate. - -Nominal (clear request, conform first pass, clean diff) = exactly one -verifier + one security dispatch. The loop only costs when it loops. - -## STEP 4 — COMMIT - -Commit using conventional format: -``` -feat(): - - -``` - -If the feature touched multiple concerns (e.g., feature + config + -test), consider splitting into 2-3 atomic commits — load -`$HOME/.claude/agents/commit-changer.md` and follow its grouping logic. - -Print summary: -``` -FEAT COMPLETE -FEATURE : -FILE(S) : -TEST(S) : -VERIFIED : -``` - -## STEP 5 — DOC SYNC (automatic) - -Load `$HOME/.claude/agents/doc-syncer.md`. -Execute in automatic mode: -`auto-mode scope: ` - -**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits -ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never -`.claude/`/`CLAUDE.md` (rc 4 = a loud BDR-022 anomaly, not a silent skip), and no-ops when -nothing was patched — the common case for a trivial change. No FINISH in an inline flow, so -it just commits the docs on the current branch (no ordering concern). - -## STEP 6 — CAPITALIZE (memory registries) - -A small feature may or may not involve a design choice. Scan the work for: - -- **Non-trivial design choice** (even small: a library pick, a naming convention, a data-model tradeoff) → propose `BDR-XXX` in `.claude/memory/decisions.md` with alternatives considered. -- **Reusable pattern or gotcha encountered** → propose `LRN-XXX` in `.claude/memory/learnings.md`. - -Present the candidates grouped: -``` -CAPITALIZE — proposé - [decisions.md] BDR-XXX — (optionnel) - [learnings.md] LRN-XXX — (optionnel) -Valider ? (all / / edit / skip) -``` - -Always append a 1-line entry to today's heading in `.claude/memory/journal.md`. - -**Language rule**: written entries are ALWAYS in English (see CLAUDE.md "Memory registries" § Language). The interactive gate may mirror the user's language; the appended entries must not. - -If no substantive capture candidate → skip with `CAPITALIZE: nothing to log`. - -**Then commit the memory** — follow `$HOME/.claude/lib/capitalize-commit.md`: it -surgically commits what capitalize just wrote (`.claude/memory` + `.claude/tasks` -only, never `git add -A`) as one `chore(memory)` commit, reports the memory-commit -hash, and no-ops if nothing was written. - ---- - -## RULES -- Max 5 files. If more needed → `/ship-feature`. -- Design gate only (not full plugin check). See STEP 0.5. -- No brainstorm/design phase (if needed → `/ship-feature`). -- No subagents — direct implementation. -- Keep scope tight. If scope creep happens mid-work, stop - and suggest splitting into `/feat` + follow-up task. -- Follow existing code patterns. Don't introduce new patterns - for a small feature. diff --git a/agents/hotfixer.md b/agents/hotfixer.md index 0db2d15..c531917 100644 --- a/agents/hotfixer.md +++ b/agents/hotfixer.md @@ -1,91 +1,48 @@ --- name: hotfixer description: Quick-fix executor — dispatched by /hotfix, which owns the routing and gitflow gate. Max 2 files, obvious root cause only (typo, CSS value, config, off-by-one, missing import). -tools: Read, Edit, Write, Bash, Grep, Glob, Agent +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet --- -# HOTFIX — Quick Superficial Fix +# HOTFIXER — closed-fix executor / L1 fix-bundle applier -Fast-track fix for obvious bugs. No planning overhead, no plugin check. -The fix is inline (no dev subagents); a fresh security gate runs before -commit, and any gate failure reverts — never loops. Get in, fix, gate, -get out. +You apply a fix that was ALREADY decided upstream and prove it doesn't break +the build — you never investigate or design the fix. Two dispatch sources, +same job: -## REQUEST -$ARGUMENTS +- **/hotfix orchestrator** — root-cause analysis happened in its LOCATE step; + you get a CONTRACT + the located files + the proposed fix (see INPUT). +- **audit dispatchers (/seo, /geo, /web-validate)** — you are the L1 + fix-bundle applier; the dispatch prompt hands you a bundle item inline + (files, concern, current, expected fix) with NO CONTRACT. Apply exactly + that item, self-verify, do not commit. There is no FILE SCOPE contract on + this path — the named files in the item ARE the scope. ---- +## INPUT (in the dispatch prompt) -## STEP 1 — LOCATE +/hotfix path: +- `CONTRACT`: path to the contract file — read it FIRST; its acceptance + criteria + FILE SCOPE bound everything you do. +- `LOCATED`: the file(s) the orchestrator found + the confirmed root cause. +- `FIX`: the proposed minimal fix, already decided. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. -Find the bug. Use the description and any error message to go -straight to the source: +Applier path (/seo, /geo, /web-validate): no CONTRACT/LOCATED/FIX keys — the +bundle item in the prompt is the fix to apply. Skip the contract read; the +`## OUTPUT` report below is optional on this path (the dispatcher just needs +the edit applied + self-verified, not the report grammar). -```bash -git status -git log --oneline -3 -``` +## EXECUTION RULES -- Read the relevant file(s). Confirm the root cause is obvious - and superficial (typo, wrong value, missing import, etc.). -- If the bug turns out to be deeper than expected (unclear cause, - multiple files involved, logic error): STOP and say: - "This looks deeper than a hotfix. Load `$HOME/.claude/agents/bugfixer.md` - and run the BUGFIXER agent on this target." - -OPTIONAL — memory check (exempt by default; hotfix = obvious fix, mirror of its capitalize -skip). For a RECURRING or urgent bug only, a quick blockers-only glance may save time: - - [ -d .claude/memory ] && grep -nE '^## BLK-' .claude/memory/blockers.md # "déjà vu ?" - -If a prior BLK names this bug, jump to its solution. Not mandatory; no RELATED MEMORY -disposition required at hotfix weight. - -## STEP 1.7 — CONTRACT (silent autofill) - -Run `$HOME/.claude/lib/contract-interview.md` at hotfix weight: **zero -questions ever** (a hotfix is an obvious fix by definition). Autofill the -contract — REQUEST verbatim = the bug description as given; ACCEPTANCE -CRITERIA = "symptom gone; build/tests green"; FILE SCOPE = the 1-2 target -files. It writes `.claude/tasks/contracts/--.md`. This is -the reference for the security gate's scope and the escalation report if a -gate fails. No verifier is dispatched at hotfix weight — the STEP 3 -smoke-check already verifies these trivial criteria; the gate hotfix adds is -security (below). - -## STEP 1.5 — DESIGN GATE - -Follow `$HOME/.claude/lib/design-gate.md`: -- Scan $ARGUMENTS and target files for design/UI/style signals (CSS, component, styling, animation). -- If signals found → run `design-tool-gate.sh`; if it reports INCOMPLETE, - tell the user to run `/profile design` before proceeding. -- If no signals → skip (zero overhead). - -## STEP 2 — PRE-FLIGHT + FIX - -**Gitflow aiguillage (before editing):** follow `$HOME/.claude/lib/gitflow-aiguillage.md` -— your type = `hotfix`. On `main`/`develop` it branches first; on a working -branch it's a no-op (commit in place). Never `finish`. - -### Pre-flight (mandatory) - -Before editing, snapshot current state so revert is possible: - -```bash -git diff HEAD --stat # confirm working tree is clean OR carries only the - # in-progress hotfix area; if unrelated dirty files are - # present, ask user whether to stash them first -git rev-parse HEAD # capture the SHA to revert to on failure -``` - -If the working tree contains unrelated uncommitted changes the user has not -mentioned: STOP and ask `"working tree dirty: stash and continue, or abort?"`. - -### Fix - -Apply the minimal change that fixes the bug: - -- Edit only what is necessary. No refactoring, no cleanup. +- Apply the minimal change that fixes the bug. Edit only what is necessary + — no refactoring, no cleanup, no "while we're here" improvements. +- Stay inside the scope you were given. On the /hotfix path that is the + contract FILE SCOPE (max 2 files) — a fix that needs more → `STATUS + BLOCKED`, report why (the orchestrator escalates to `/bugfix`), never + expand scope yourself. On the applier path it is the files named in the + bundle item — apply only those. - If tests exist for the affected code, run them. Detection cascade: ```bash # JS/TS @@ -101,85 +58,25 @@ Apply the minimal change that fixes the bug: test -f Makefile && grep -qE '^test:' Makefile && echo "make test" ``` Run whichever one resolves; if none → continue to smoke check below. -- Smoke check (always, even when no tests): try the build/typecheck command for - the stack — `npm run build`, `tsc --noEmit`, `cargo build`, `go build ./...`, - `python -c "import "` — to confirm the fix did not break compilation. +- Smoke check (always, even when no tests ran): try the build/typecheck + command for the stack — `npm run build`, `tsc --noEmit`, `cargo build`, + `go build ./...`, `python -c "import "` — to confirm the fix did not + break compilation. +- Report the SMOKE result verbatim, pass or fail. You do not decide + pass/fail consequences — the orchestrator's STEP 4 reads your SMOKE line + and owns the revert decision. +- FORBIDDEN: `git commit`, branch ops, push, merge, dispatching the + security gate (the orchestrator owns it), `git restore`/revert of any + kind (the orchestrator owns the pre-flight SHA), user questions (you + cannot ask — report BLOCKED instead), attribution trailers of any kind. -## STEP 3 — VERIFY + COMMIT +## OUTPUT — end with exactly this report (your final message) -1. Verify the fix: - - Run the test suite or the specific test if available. - - If no tests: smoke check from STEP 2 must have passed. -2. **Failure branch** — if tests fail OR smoke check fails after the fix: - - Print the failure output verbatim (under 30 lines). - - Run `git restore .` to revert the working-tree edits to the pre-flight SHA. - (Files were not yet staged — restore is safe.) - - STOP and tell user: `"Hotfix introduced a regression. Reverted. Escalate to /bugfix or /analyze for deeper investigation."` - - Do NOT commit a broken fix. -3. **Security gate (fresh auditor) — failure REVERTS, never loops.** Dispatch - a FRESH security-auditor (`subagent_type: security-auditor`, or load - `agents/security-auditor.md`) with `MODE: gate`, `SCOPE:` the working-tree - diff vs the pre-flight SHA. Parse its `SECURITY — VERDICT:` line: - - `PASS` (or `DEGRADED` with no BLOCK) → proceed to commit. - - `BLOCK(n)` → this is hotfix: do NOT loop. Run `git restore .` to the - pre-flight SHA, print the `BLOCKING` list, and STOP: - `"Hotfix introduced a security finding. Reverted. Escalate to /bugfix - for a fix under the full verify+security loop."` The hotfix model is - one attempt; any gate failure (smoke OR security) reverts and escalates. - - Structural failure (mute / unparsable / no VERDICT line) → treat as a - failed gate: retry ONCE fresh; a 2nd structural failure → revert + - escalate. A mute auditor is never a PASS. -4. Commit using conventional format (only after verify AND security pass): - ``` - fix(): - ``` -5. Print summary: - ``` - HOTFIX APPLIED - FILE(S) : - FIX : - VERIFIED: - SECURITY: - ``` - -## STEP 4 — DOC SYNC (automatic) - -Load `$HOME/.claude/agents/doc-syncer.md`. -Execute in automatic mode: -`auto-mode scope: ` - -**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits -ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never -`.claude/`/`CLAUDE.md` (rc 4 = a loud BDR-022 anomaly, not a silent skip), and no-ops when -nothing was patched — the common case for a trivial hotfix. No FINISH in an inline flow, so -it just commits the docs on the current branch (no ordering concern). - -## STEP 5 — CAPITALIZE (memory registries, lightweight) - -Hotfixes are often trivial (typo, config, import) — skip by default. But if the fix revealed something non-obvious: - -- Wrong default that should never have been merged → propose `LRN-XXX` in `.claude/memory/learnings.md`. -- Bug that cost real time to locate despite being "superficial" → propose `BLK-XXX` in `.claude/memory/blockers.md` (status: resolved). - -Default behaviour: `CAPITALIZE: hotfix trivial, skip` (no prompt, no output). -Ask the user only when there is an actual candidate to propose. - -Always append a 1-line entry to today's heading in `.claude/memory/journal.md` (even trivial hotfix — journal is timeline, not signal). - -**Language rule**: the journal line and any proposed BLK/LRN entries are ALWAYS written in English (see CLAUDE.md "Memory registries" § Language). - -**Then commit the memory** — follow `$HOME/.claude/lib/capitalize-commit.md`: it -surgically commits what capitalize just wrote (`.claude/memory` + `.claude/tasks` -only, never `git add -A`) as one `chore(memory)` commit, reports the memory-commit -hash, and no-ops if nothing was written. The always-on journal line means a -trivial hotfix still produces a `chore(memory): journal — …` commit (Frame 2 / F3). - ---- - -## RULES -- Max 2 files changed. If more needed → `/bugfix`. -- No refactoring. No "while we're here" improvements. -- Design gate only if CSS/style signals detected. See STEP 1.5. -- If root cause is unclear → escalate to `/bugfix`. -- If fix touches >5 lines of logic → reconsider if this is - truly a hotfix. +``` +HOTFIX-EXEC REPORT +STATUS : DONE | BLOCKED +FILE(S) : +FIX : +SMOKE : +NOTES : +``` diff --git a/agents/release-executor.md b/agents/release-executor.md new file mode 100644 index 0000000..fe68feb --- /dev/null +++ b/agents/release-executor.md @@ -0,0 +1,99 @@ +--- +name: release-executor +description: Mechanical release executor — dispatched by /release-candidate for its two spans (prep, finish+tag). Never decides the version number or the when-to-release call, never pushes. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet +--- + +# RELEASE-EXECUTOR — mechanical release spans + +You execute the mechanical parts of a gitflow release. The `/release-candidate` +dispatcher owns every judgment call — the version number, the "is it time to +release" decision, and both pushes — and owns the human gate that sits BETWEEN +your two spans. You are dispatched fresh, once per span, never both in one +call: after `SPAN: prep` reports, the dispatcher stops for a human go before +it ever dispatches `SPAN: finish`. + +## Dispatch spans + +The dispatch prompt names exactly one span; do only that span's work, then +stop and report — never chain into the other span yourself. + +- `SPAN: prep ` — branch, version bump, CHANGELOG, test gate, commit. + No merge, no tag, no push. +- `SPAN: finish ` — gitflow fan-out, then tag. Never push. + +--- + +## SPAN: prep + +### Input +``: the version number, already decided by the dispatcher before +dispatch — you never derive it, never second-guess it, never bump it. + +### Steps +1. `bash "$HOME/.claude/lib/gitflow.sh" start release ` — forks from + `develop` onto `release/`. A non-zero exit (dirty tree, missing + base) → STOP, `STATUS: BLOCKED` with the error verbatim; don't improvise + a workaround. +2. Set `version.txt` to `` (single line, trailing newline). +3. Rewrite `CHANGELOG.md`: the `## [Unreleased]` header becomes + `## [] — `; re-open a fresh, empty + `## [Unreleased]` above it. If `` is a MAJOR bump (X incremented), + the finalized section must spell out the breaking change explicitly + (`### Changed`/`### Removed`/a `BREAKING` line). If the existing + Unreleased content doesn't already say what breaks, do not invent + wording — report `STATUS: NEED-DECISION` instead. +4. Apply any release-candidate fixes the dispatcher named inline in the + dispatch prompt (same commit as the prep, below). None named → skip. +5. **Run the test suite**: `make test` if a `Makefile` defines `test`, else + the stack's normal suite. This is the RC gate — never let a release + proceed on red. Record the verbatim result line for the report; a + failing suite is still `STATUS: DONE` for this span (the dispatcher, not + you, decides what a red suite means for the release) — just report it + truthfully. +6. Commit the prep on the release branch: + `chore(release): — version.txt + CHANGELOG`. + +### Forbidden in this span +`gitflow finish`, `git tag`, `git push`, deciding the version number, the +when-to-release decision, attribution trailers of any kind. + +--- + +## SPAN: finish + +### Preconditions +Verify with `git branch --show-current` that you are on `release/` +before finishing. A mismatch means the prep span didn't land as expected or +the dispatcher named the wrong version — STOP, `STATUS: BLOCKED`, report the +actual branch; never finish whatever happens to be checked out. + +### Steps +1. `bash "$HOME/.claude/lib/gitflow.sh" finish` — fans out: merges + `release/` into `main`, merges into `develop`, deletes the release + branch. A merge conflict → STOP, `STATUS: BLOCKED` with the conflict + output verbatim; do not attempt to resolve it yourself. +2. **Tag AFTER finish, on `main`** — never before: + `git tag -a v main -m "release "` (annotated, so it lands on + main's release-merge commit). + +### Forbidden in this span +`git push` (any remote, any ref — the dispatcher owns the push gate), +deciding the version number, the when-to-release decision, attribution +trailers of any kind. + +--- + +## OUTPUT — end with exactly this report (your final message) + +``` +RELEASE-EXEC REPORT +SPAN : prep | finish +STATUS : DONE | NEED-DECISION | BLOCKED +BRANCH : for prep | main for finish> +TAG : | n/a — prep never tags> +TESTS : +NOTES : +``` diff --git a/docs/superpowers/plans/2026-07-15-model-routing.md b/docs/superpowers/plans/2026-07-15-model-routing.md new file mode 100644 index 0000000..8b8a854 --- /dev/null +++ b/docs/superpowers/plans/2026-07-15-model-routing.md @@ -0,0 +1,1775 @@ +# Model Routing Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Reflection (planning, audits, loop decisions) stays on the session big model behind a blocking gate; execution (code from a closed plan, fix-bundle application) runs on sonnet-pinned subagents. + +**Architecture:** A deterministic witness (`lib/model-check.sh`) + a blocking include (`lib/model-gate.md`) wired into 12 reflection orchestrators; frontmatter `model:` pins on executor agents; `/feat` re-architected from inline playbook to "plan inline → dispatch sonnet executor"; SDD implementation subagents and web-validate fix application routed to sonnet. + +**Tech Stack:** bash (shellcheck-clean), Claude Code SKILL.md/agent.md markdown, agent frontmatter `model:` field, Makefile test loop. + +**Spec:** `docs/superpowers/specs/2026-07-15-model-routing-design.md` (approved 2026-07-15). + +## Global Constraints + +- Work on branch `feature/model-routing` (already checked out). Commit per task. NEVER merge/finish — human gate. +- NO commit attribution trailers of any kind (Co-Authored-By, Claude-Session) — user ban, guards will red. +- `make test` must be green at every commit (run from repo root `/home/bchanot/Documents/claude`). +- New/edited `.sh` files: `shellcheck ` clean and `bash -n ` clean. +- The `config-protection` PreToolUse hook BLOCKS Edit/Write on `lib/tests/*`, `hooks/*`, `settings.json`, `lib/gitflow.sh`. Before EACH Edit/Write to `lib/tests/*` in this plan, write the one-shot bypass sentinel (consumed per use): `printf 'model-routing plan: ' > .claude/.config-edit-ok` +- Agent frontmatter must stay `yaml.safe_load`-parseable (job9 gate): if a value contains `: `, quote it. +- Memory registries: append-only, caveman format, English. +- SPEC §5 (client-handover conversion) is DEFERRED to a separate plan — do NOT touch `agents/client-handover-writer.md` or `skills/client-handover/SKILL.md` in this plan. + +--- + +### Task 1: `lib/model-check.sh` witness + flip-tests + +**Files:** +- Create: `lib/model-check.sh` +- Test: `lib/tests/model-check.test.sh` (guarded path — sentinel required) + +**Interfaces:** +- Consumes: `$HOME/.claude/settings.json` `"model"` key; env override `MODEL_CHECK_SETTINGS=` for fixtures. +- Produces: stdout `:` where class ∈ `big|small|unknown`; exit `0`=big, `2`=small, `3`=unknown. Task 2's `lib/model-gate.md` calls `bash "$HOME/.claude/lib/model-check.sh"` and branches on these exact codes. + +- [ ] **Step 1: Write the failing test** + +```bash +printf 'model-routing plan: create model-check flip-tests' > .claude/.config-edit-ok +``` + +Then create `lib/tests/model-check.test.sh` with exactly: + +```bash +#!/usr/bin/env bash +# lib/tests/model-check.test.sh — flip-tests for lib/model-check.sh (LRN-096) +set -u +S="$(cd "$(dirname "$0")/../.." && pwd)/lib/model-check.sh" +pass=0; fail=0 +check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); else fail=$((fail+1)); + printf 'FAIL %s: got[%s] want[%s]\n' "$1" "$2" "$3"; fi; } +T="$(mktemp -d)"; trap 'rm -rf "$T"' EXIT + +fx() { printf '{"model": "%s"}' "$1" > "$T/s.json"; } +run() { MODEL_CHECK_SETTINGS="$T/s.json" bash "$S" >"$T/out" 2>&1; echo "$?"; } + +fx 'claude-fable-5[1m]'; check T1-fable-exit "$(run)" 0 +check T1-fable-class "$(cut -d: -f1 <"$T/out")" big +fx 'claude-opus-4-8'; check T2-opus "$(run)" 0 +fx 'claude-sonnet-5'; check T3-sonnet "$(run)" 2 +fx 'claude-haiku-4-5-20251001'; check T4-haiku "$(run)" 2 +fx 'opusplan'; check T5-opusplan "$(run)" 3 +fx 'gpt-9-mega'; check T6-foreign "$(run)" 3 +printf '{"no_model": true}' > "$T/s.json"; check T7-no-key "$(run)" 3 +printf '{broken' > "$T/s.json"; check T8-malformed "$(run)" 3 +check T9-missing-file "$(MODEL_CHECK_SETTINGS="$T/absent.json" bash "$S" >/dev/null 2>&1; echo $?)" 3 + +printf 'model-check: %d pass, %d fail\n' "$pass" "$fail" +[ "$fail" -eq 0 ] +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `bash lib/tests/model-check.test.sh` +Expected: FAIL on every check (script missing → bash exits non-zero, got[127]-style mismatches), final line `model-check: 1 pass, 9 fail` or similar non-zero fail count, exit 1. (T1-fable-class may pass vacuously on empty output only if cut returns empty — any red is enough: the suite CAN fail.) + +- [ ] **Step 3: Write the implementation** + +Create `lib/model-check.sh` with exactly: + +```bash +#!/usr/bin/env bash +# lib/model-check.sh — classify the persisted session model: big | small | unknown +# +# Witness for lib/model-gate.md (reflection requires a big model). Reads the +# "model" key of the user-scope settings (the file /model rewrites — LRN-098). +# Override the source with MODEL_CHECK_SETTINGS (tests use fixtures). +# +# stdout : : (raw = value found, empty if none) +# exit : 0 = big (fable/opus) · 2 = small (sonnet/haiku) · 3 = unknown +set -u + +SETTINGS="${MODEL_CHECK_SETTINGS:-$HOME/.claude/settings.json}" + +raw="" +if [ -f "$SETTINGS" ]; then + raw="$(python3 - "$SETTINGS" 2>/dev/null <<'PY' +import json, sys +try: + v = json.load(open(sys.argv[1])).get("model", "") + print(v if isinstance(v, str) else "") +except Exception: + print("") +PY +)" +fi + +norm="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')" +case "$norm" in + *opusplan*) printf 'unknown:%s\n' "$raw"; exit 3 ;; # opus-for-plan, sonnet otherwise — ambiguous + *fable*|*opus*) printf 'big:%s\n' "$raw"; exit 0 ;; + *sonnet*|*haiku*) printf 'small:%s\n' "$raw"; exit 2 ;; + *) printf 'unknown:%s\n' "$raw"; exit 3 ;; +esac +``` + +(The heredoc passes the settings path as `sys.argv[1]` — never pipe INTO a heredoc'd interpreter, LRN-012.) + +- [ ] **Step 4: Run test to verify it passes** + +Run: `bash lib/tests/model-check.test.sh` +Expected: `model-check: 10 pass, 0 fail`, exit 0. + +- [ ] **Step 5: Lint** + +Run: `shellcheck lib/model-check.sh lib/tests/model-check.test.sh && bash -n lib/model-check.sh` +Expected: no output (clean), exit 0. + +- [ ] **Step 6: Full suite + commit** + +Run: `make test` +Expected: every suite line green, exit 0. + +```bash +git add lib/model-check.sh lib/tests/model-check.test.sh +git commit -m "feat(model-routing): model-check witness (big/small/unknown) + flip-tests" +``` + +--- + +### Task 2: `lib/model-gate.md` blocking include + +**Files:** +- Create: `lib/model-gate.md` + +**Interfaces:** +- Consumes: `lib/model-check.sh` exit codes (Task 1). +- Produces: the include that Tasks 3 and 5 reference verbatim as `` `$HOME/.claude/lib/model-gate.md` ``. + +- [ ] **Step 1: Create the include** + +Create `lib/model-gate.md` with exactly: + +```markdown +# Model gate — reflection requires a big model (BLOCKING) + +Shared include. Runs FIRST in any orchestrator whose reflection — +brainstorming, planning, contract, audit judgment, loop decisions — +executes inline or in inherit-model subagents. Sonnet-pinned executors are +not what this gate protects; it protects the thinking around them (BDR-066). + +## 1. Self-check + +Your system prompt names the model powering this session. Fable or Opus → +big. Sonnet, Haiku, anything else → small. + +## 2. Witness — deterministic check + + bash "$HOME/.claude/lib/model-check.sh" + +Output `:`; exit 0 = big, 2 = small, 3 = unknown. The witness +reads the PERSISTED model (settings.json — the file `/model` rewrites, +LRN-098). It can lag reality (session launched with `--model`, settings not +yet rewritten) — that is why the self-check exists alongside it. + +## 3. Verdict + +| self-check | witness | action | +|---|---|---| +| big | big (0) | proceed, SILENT — the nominal path prints nothing | +| small | any | **STOP** | +| big | small (2) | disagreement — **STOP**, surface BOTH values; the user confirms or relaunches | +| big | unknown (3) | fail-visible: print `model gate: witness unknown () — self-check says ` and ask the user to confirm before continuing (BDR-025: unknown never silently passes) | + +**STOP means**: print exactly + + ⛔ MODEL GATE — session on . Reflection steps of this skill + require Fable or Opus. Switch with /model, then relaunch the skill. + +then end the turn. No later step runs, no agent is dispatched, nothing is +edited. +``` + +- [ ] **Step 2: Commit** + +```bash +git add lib/model-gate.md +git commit -m "feat(model-routing): blocking model-gate include (self-check + witness)" +``` + +--- + +### Task 3: Wire the gate into the 12 reflection orchestrators + +**Files:** +- Modify: `skills/ship-feature/SKILL.md`, `skills/init-project/SKILL.md`, `skills/onboard/SKILL.md`, `skills/seo/SKILL.md`, `skills/geo/SKILL.md`, `skills/web-validate/SKILL.md`, `skills/harden/SKILL.md`, `skills/audit-delta/SKILL.md`, `skills/tour/SKILL.md` (orchestrator idiom), `skills/feat/SKILL.md`, `skills/bugfix/SKILL.md`, `skills/code-clean/SKILL.md` (thin-wrapper idiom) + +**Interfaces:** +- Consumes: `lib/model-gate.md` (Task 2). +- Produces: the string `lib/model-gate.md` present in each of the 12 files — Task 8's census greps exactly this. + +- [ ] **Step 1: Insert the orchestrator gate block (9 files)** + +For each of the 9 orchestrator skills, Edit with `old_string` = the file's unique H1 line (below), `new_string` = the same H1 line followed by a blank line and this exact block: + +```markdown +## MODEL GATE (blocking — run before any other step) + +Run `$HOME/.claude/lib/model-gate.md`. Reflection here (planning, audit +judgment, loop decisions) requires Fable/Opus. Verdict `small` → STOP: the +gate prints the remedy; end the turn — no later step, no dispatch. Nominal +(big) path is silent. +``` + +H1 anchors (verbatim, one per file): +- `skills/ship-feature/SKILL.md` → `# ORCHESTRATOR: SHIP FEATURE` +- `skills/init-project/SKILL.md` → `# ORCHESTRATOR: INIT PROJECT` +- `skills/onboard/SKILL.md` → `# ORCHESTRATOR: ONBOARD` +- `skills/seo/SKILL.md` → `# /seo — parallel SEO + GEO dispatcher` +- `skills/geo/SKILL.md` → `# /geo — GEO (AI-search) audit + fix dispatcher` +- `skills/web-validate/SKILL.md` → `# /web-validate — web standards audit (W3C + WCAG)` +- `skills/harden/SKILL.md` → `# /harden — web hardening audit` +- `skills/audit-delta/SKILL.md` → `# /audit-delta — Incremental multi-axis code audit` +- `skills/tour/SKILL.md` → `# /tour — grouped multi-axis sweep (clean + security + reconcile + doc)` + +- [ ] **Step 2: Insert the thin-wrapper gate paragraph (3 files)** + +For `skills/feat/SKILL.md`, `skills/bugfix/SKILL.md`, `skills/code-clean/SKILL.md`: Edit with `old_string` = `Load and follow strictly:` and `new_string` = + +```markdown +MODEL GATE (blocking): run `$HOME/.claude/lib/model-gate.md` BEFORE loading +the agent below. Verdict `small` → STOP — print the gate's remedy, end the +turn, do not load the agent. + +Load and follow strictly: +``` + +(`Load and follow strictly:` occurs once per file — safe anchor.) + +- [ ] **Step 3: Verify the wiring by census** + +Run: `for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean; do grep -L 'lib/model-gate.md' "skills/$s/SKILL.md"; done` +Expected: no output (grep -L lists files MISSING the pattern — empty = all wired). + +Run: `for s in hotfix commit-change doc status release-candidate; do grep -l 'lib/model-gate.md' "skills/$s/SKILL.md"; done` +Expected: no output (excluded skills stay unwired). + +- [ ] **Step 4: Full suite + commit** + +Run: `make test` +Expected: green, exit 0. + +```bash +git add skills/ship-feature/SKILL.md skills/init-project/SKILL.md skills/onboard/SKILL.md skills/seo/SKILL.md skills/geo/SKILL.md skills/web-validate/SKILL.md skills/harden/SKILL.md skills/audit-delta/SKILL.md skills/tour/SKILL.md skills/feat/SKILL.md skills/bugfix/SKILL.md skills/code-clean/SKILL.md +git commit -m "feat(model-routing): wire blocking model gate into 12 reflection orchestrators" +``` + +--- + +### Task 4: Frontmatter pins — hotfixer sonnet, analyzer un-pinned + +**Files:** +- Modify: `agents/hotfixer.md:1-5` (frontmatter) +- Modify: `agents/analyzer.md:1-7` (frontmatter) + +**Interfaces:** +- Produces: `model: sonnet` line in hotfixer frontmatter (Task 7's applier dispatches and seo/geo L1 appliers ride on it); NO `model:` line in analyzer frontmatter (inherits session). Task 8's census greps both. + +- [ ] **Step 1: Pin hotfixer** + +Edit `agents/hotfixer.md`, `old_string`: + +``` +tools: Read, Edit, Write, Bash, Grep, Glob, Agent +--- +``` + +`new_string`: + +``` +tools: Read, Edit, Write, Bash, Grep, Glob, Agent +model: sonnet +--- +``` + +- [ ] **Step 2: Un-pin analyzer** + +Edit `agents/analyzer.md`, `old_string`: + +``` +tools: Read, Grep, Glob, Bash +model: haiku +memory: project +``` + +`new_string`: + +``` +tools: Read, Grep, Glob, Bash +memory: project +``` + +- [ ] **Step 3: Verify YAML stays parseable** + +Run: `python3 -c "import yaml,sys; [yaml.safe_load(open(f).read().split('---')[1]) for f in ['agents/hotfixer.md','agents/analyzer.md']]; print('YAML OK')"` +Expected: `YAML OK`. + +- [ ] **Step 4: Full suite + commit** + +Run: `make test` +Expected: green (includes the job9 review guards). + +```bash +git add agents/hotfixer.md agents/analyzer.md +git commit -m "feat(model-routing): pin hotfixer sonnet (executor), un-pin analyzer (inherits session)" +``` + +--- + +### Task 5: `/feat` re-architecture — reflection inline, execution dispatched + +**Files:** +- Modify (full rewrite): `skills/feat/SKILL.md` +- Modify (full rewrite): `agents/feater.md` +- Modify (3 surgical edits): `lib/verify-secure-loop.md` + +**Interfaces:** +- Consumes: `lib/model-gate.md` (Task 2), `lib/verify-secure-loop.md`, `lib/contract-interview.md`, `lib/gitflow-aiguillage.md`, `lib/analyze-before-plan.md`, `lib/design-gate.md` (all existing). +- Produces: `Agent(subagent_type="feater")` dispatch in feat/SKILL.md; feater `FEAT-EXEC REPORT` grammar `STATUS : DONE | NEED-DECISION | BLOCKED`; `model: sonnet` in feater frontmatter. Task 8's census greps `subagent_type="feater"`, `verify-secure-loop.md`, feater `model: sonnet`, feater has NO `AskUserQuestion`. + +- [ ] **Step 1: Rewrite `skills/feat/SKILL.md`** + +Replace the ENTIRE file content with: + +````markdown +--- +name: feat +description: | + Small feature implementation (1-5 files). Reflection inline (scope, + plan, contract — session model), execution dispatched to the + sonnet-pinned feater executor. For features that don't need the full + /ship-feature pipeline (no design brainstorm, no plugin check gate). + Trigger: "feat", "small feature", "add this", "petite feature", + "quick feature", "ajoute ca", "implement this small thing". + For multi-file features needing design → use /ship-feature. + For bug fixes → use /hotfix or /bugfix. +argument-hint: +allowed-tools: + - Read + - Edit + - Write + - Bash + - Grep + - Glob + - Agent +--- + +# /feat — small-feature orchestrator (reflection inline, execution dispatched) + +MODEL GATE (blocking): run `$HOME/.claude/lib/model-gate.md` BEFORE any +step below. Verdict `small` → STOP — print the gate's remedy, end the +turn, dispatch nothing. + +## REQUEST +$ARGUMENTS + +--- + +## STEP 0 — SCOPE CHECK + +Before starting, verify this is actually a small feature: + +```bash +git status +git log --oneline -3 +``` + +Read the relevant existing code to understand the context. + +### Decision rules (apply in order — first match wins) + +| Rule | Trigger | Action | +|---|---|---| +| 1 | Estimated diff < 2 files AND no logic (config value, copy fix, missing field) | DOWNGRADE → load `$HOME/.claude/agents/hotfixer.md` | +| 2 | New external dependency (`npm install `, `pip install`, `cargo add`) required | ESCALATE → `/ship-feature` (dep choices need design gate) | +| 3 | New route family / new top-level module / new DB migration | ESCALATE → `/ship-feature` | +| 4 | Estimated diff > 5 files | ESCALATE → `/ship-feature` | +| 5 | User wording is uncertain ("not sure how", "what do you think") | ESCALATE → `/ship-feature` (needs brainstorming) | +| 6 | UI feature on a stack with a design system AND the design toolchain incomplete | Proceed in `/feat`, but flag it in STEP 0.5 design gate | +| 7 | Otherwise | PROCEED in `/feat` | + +### Worked examples + +- "Add `/health` endpoint returning `{status:"ok",version}`" → 1-2 files, no new dep, route added to existing router → **PROCEED**. +- "Add a dark-mode toggle bound to `prefers-color-scheme`" → 2-3 files, design system exists → **PROCEED** (design gate triggers in STEP 0.5). +- "Add OAuth login (Google + GitHub providers)" → new deps, new routes, secrets handling → **ESCALATE** to `/ship-feature`. +- "Show a 'New' badge on items created this week" → 1-2 files, pure UI predicate → **PROCEED**. +- "Fix copy: 'Sign In' → 'Sign in'" in 1 file → **DOWNGRADE** to `/hotfix`. + +Print a one-line scope confirmation (use the rule that fired): +``` +FEAT: — rule , ~ files, +``` + +## STEP 0.5 — DESIGN GATE + +Follow `$HOME/.claude/lib/design-gate.md`: +- Scan $ARGUMENTS and target files for design/UI/style signals. +- If signals found → run `design-tool-gate.sh`; if it reports INCOMPLETE, + tell the user to run `/profile design` before proceeding. +- If no signals → skip (zero overhead). + +## STEP 0.6 — MEMORY READ-BEFORE (decisions-first) + +Run the scan per `$HOME/.claude/lib/analyze-before-plan.md`, decisions-weighted: a BDR may +already constrain or forbid the approach; an LRN may name a gotcha to apply. Emit RELATED +MEMORY; feed STEP 1 PLAN. Inline consumption — reader = planner, no injection. +`.claude/memory/` absent → guarded no-op (zero overhead on a memory-less repo). + +## STEP 0.7 — CONTRACT + +Run `$HOME/.claude/lib/contract-interview.md` (main loop — you are it). It +captures the request verbatim, asks 0-3 questions PROPORTIONAL to ambiguity +(a complete request → zero questions, silent), derives testable acceptance +criteria + file scope, and writes the contract to +`.claude/tasks/contracts/--.md`. Keep the path — the +executor reads it first and GATE 1 (STEP 4) hands it to a fresh verifier. + +## STEP 1 — PLAN (dispatch-ready) + +The executor follows this plan to the letter and CANNOT ask questions — +close every decision here: + +1. Files to create or modify (with line references). +2. Approach in 2-5 bullets — name every choice (naming, data shape, API + surface); an open choice left here comes back as a NEED-DECISION + round-trip. +3. Edge cases to handle. +4. Tests to add/update (exact files). +5. Disposition (from STEP 0.6): name each in-force BDR/LRN this plan honors + (`honors BDR-xxx by …`), or state `no in-force decision constrains this feature`. + A plan with neither = read-then-ignore; the disposition must surface as a trace. + +Print the plan as a compact checklist: +``` +PLAN: + [ ] — + [ ] — + [ ] — +``` + +If the approach is ambiguous: ask the user ONE focused question BEFORE +dispatching — never after (the executor cannot relay questions). + +## STEP 2 — BRANCH + +**Gitflow aiguillage (before dispatch):** follow `$HOME/.claude/lib/gitflow-aiguillage.md` +— your type = `feature`. On `main`/`develop` it branches first; on a working +branch it's a no-op (commit in place). Never `finish`. + +## STEP 3 — DISPATCH EXECUTOR + +Dispatch the executor — sonnet by frontmatter pin, do not override: + +``` +Agent(subagent_type="feater") +prompt: "CONTRACT: +PLAN: +BRANCH: +Implement the plan to the letter. Tests alongside code. No commit, no +branch ops, no new dependencies, no files outside the contract FILE SCOPE. +Finish with the FEAT-EXEC REPORT." +``` + +Parse the `FEAT-EXEC REPORT`: +- `STATUS : DONE` → STEP 4. +- `STATUS : NEED-DECISION` → make the decision HERE (that is reflection), + append it to the plan, re-dispatch a FRESH feater with plan + decision. + Max 2 decision round-trips → escalate to the user. +- `STATUS : BLOCKED` → surface the blocker to the user, stop. + +## STEP 4 — VERIFY + SECURE (fresh gates, bounded loops) + +Run the two fresh gates per `$HOME/.claude/lib/verify-secure-loop.md` with +`CONTRACT` = the STEP 0.7 path, `DIFF` = the working-tree diff the executor +produced, `TEST` = the suite named in its report: + +- GATE 1 — a FRESH verifier judges the diff against the contract (blind). + CONFORME on the first pass → straight to GATE 2, no loop. ECARTS → the + "dev" of the loop is the dispatched executor: re-dispatch a FRESH feater + with the CONTRACT path + the exact gap lines, nothing else. Max 3 → + escalate. +- GATE 2 — a FRESH security-auditor (`MODE: gate`) scans the diff. PASS → + STEP 5. BLOCK → re-dispatch a FRESH feater with the BLOCKING list + the + CONTRACT path; re-verify the request THEN re-scan, max 3 → escalate. + +Loop decisions stay HERE, in the main loop (LRN-083). Nominal (clear +request, conform first pass, clean diff) = one executor + one verifier + +one security dispatch. + +## STEP 5 — COMMIT + +Commit using conventional format: +``` +feat(): + + +``` + +If the feature touched multiple concerns (e.g., feature + config + +test), consider splitting into 2-3 atomic commits — load +`$HOME/.claude/agents/commit-changer.md` and follow its grouping logic. + +Print summary: +``` +FEAT COMPLETE +FEATURE : +FILE(S) : +TEST(S) : +VERIFIED : +``` + +## STEP 6 — DOC SYNC (automatic) + +Load `$HOME/.claude/agents/doc-syncer.md`. +Execute in automatic mode: +`auto-mode scope: ` + +**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits +ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never +`.claude/`/`CLAUDE.md` (rc 4 = a loud BDR-022 anomaly, not a silent skip), and no-ops when +nothing was patched — the common case for a trivial change. No FINISH in an inline flow, so +it just commits the docs on the current branch (no ordering concern). + +## STEP 7 — CAPITALIZE (memory registries) + +A small feature may or may not involve a design choice. Scan the work for: + +- **Non-trivial design choice** (even small: a library pick, a naming convention, a data-model tradeoff) → propose `BDR-XXX` in `.claude/memory/decisions.md` with alternatives considered. +- **Reusable pattern or gotcha encountered** → propose `LRN-XXX` in `.claude/memory/learnings.md`. + +Present the candidates grouped: +``` +CAPITALIZE — proposé + [decisions.md] BDR-XXX — (optionnel) + [learnings.md] LRN-XXX — (optionnel) +Valider ? (all / / edit / skip) +``` + +Always append a 1-line entry to today's heading in `.claude/memory/journal.md`. + +**Language rule**: written entries are ALWAYS in English (see CLAUDE.md "Memory registries" § Language). The interactive gate may mirror the user's language; the appended entries must not. + +If no substantive capture candidate → skip with `CAPITALIZE: nothing to log`. + +**Then commit the memory** — follow `$HOME/.claude/lib/capitalize-commit.md`: it +surgically commits what capitalize just wrote (`.claude/memory` + `.claude/tasks` +only, never `git add -A`) as one `chore(memory)` commit, reports the memory-commit +hash, and no-ops if nothing was written. + +--- + +## RULES +- Max 5 files. If more needed → `/ship-feature`. +- Reflection (scope, plan, contract, loop decisions) NEVER leaves this main + loop; execution NEVER stays in it — the executor is the sonnet-pinned + feater subagent (BDR-066). +- The executor is dispatched FRESH on every round-trip — feedback travels + as contract path + named gaps/decisions, never as transcript. +- Design gate only (not full plugin check). See STEP 0.5. +- No brainstorm/design phase (if needed → `/ship-feature`). +- Keep scope tight. If scope creep happens mid-work, stop + and suggest splitting into `/feat` + follow-up task. +- Follow existing code patterns. Don't introduce new patterns + for a small feature. +```` + +(Note: this rewrite REPLACES the Task 3 thin-wrapper gate paragraph for feat — the gate line is now native under the H1. The census greps `lib/model-gate.md`, satisfied either way.) + +- [ ] **Step 2: Rewrite `agents/feater.md`** + +Replace the ENTIRE file content with: + +````markdown +--- +name: feater +description: Small-feature EXECUTOR — dispatched by /feat with a closed plan + contract. Implements to the letter, tests, reports. No planning, no questions, no commit. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet +--- + +# FEATER — plan executor + +You receive a CLOSED plan from the /feat orchestrator. Your job is faithful +execution, not design. The thinking already happened; every choice you would +want to make was either made in the plan or is a NEED-DECISION to report. + +## INPUT (in the dispatch prompt) + +- `CONTRACT`: path to the contract file — read it FIRST; its acceptance + criteria + FILE SCOPE bound everything you do. +- `PLAN`: files + approach + edge cases + tests. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. +- `GAPS` (re-dispatch only): verifier/security verdict lines — fix ONLY + those, touch nothing else. + +## EXECUTION RULES + +- Follow the plan to the letter. A plan hole or an open choice (naming, + data shape, API surface, dependency) → STOP, report `NEED-DECISION` with + the precise question. Never improvise a design decision. +- Stay inside the contract FILE SCOPE. A needed file outside it → + `NEED-DECISION` (the orchestrator owns scope changes); don't touch it. +- Write tests alongside the code, as the plan names them. Run the relevant + suite incrementally; run it fully before reporting. +- Follow existing code patterns and CLAUDE.md limits (function size, + params, no global state). Match comment density and naming. +- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, + editing `.claude/**` or memory registries, user questions (you cannot + ask — report instead), attribution trailers of any kind. + +## OUTPUT — end with exactly this report (your final message) + +``` +FEAT-EXEC REPORT +STATUS : DONE | NEED-DECISION | BLOCKED +FILES : +TESTS : +NOTES : +``` +```` + +- [ ] **Step 3: Update `lib/verify-secure-loop.md` (3 surgical edits)** + +Edit 1 — header, `old_string`: + +``` +finished diff into a verified, security-cleared change through two fresh +gates and bounded loops. The dev stays inline (LRN-083: subagents = +execution + report; loop decisions live here, in the main loop). +``` + +`new_string`: + +``` +finished diff into a verified, security-cleared change through two fresh +gates and bounded loops. Loop decisions live here, in the main loop +(LRN-083: subagents = execution + report). The dev step is either inline +(bugfix) or a dispatched sonnet executor (/feat's feater): "hand the dev" +below means fix inline, or re-dispatch a FRESH executor with exactly those +inputs. +``` + +Edit 2 — GATE 1 ECARTS bullet, `old_string`: + +``` + lines (NOT-MET / out-of-scope), nothing else. Dev fixes inline, then + re-dispatch a FRESH verifier. +``` + +`new_string`: + +``` + lines (NOT-MET / out-of-scope), nothing else. Inline dev fixes in place; + a dispatched dev is re-dispatched FRESH with those inputs only. Then + re-dispatch a FRESH verifier. +``` + +Edit 3 — GATE 2 BLOCK bullet, `old_string`: + +``` +- `BLOCK(n)` → hand the dev the `BLOCKING` list + the CONTRACT path. Dev + fixes inline. Then **re-verify the REQUEST first** (GATE 1, fresh +``` + +`new_string`: + +``` +- `BLOCK(n)` → hand the dev the `BLOCKING` list + the CONTRACT path (inline + fix, or FRESH executor re-dispatch). Then **re-verify the REQUEST first** (GATE 1, fresh +``` + +- [ ] **Step 4: Structural verification** + +Run: `grep -c 'subagent_type="feater"' skills/feat/SKILL.md; grep -c 'verify-secure-loop.md' skills/feat/SKILL.md; grep -c 'model: sonnet' agents/feater.md; grep -c 'tools: Read, Edit, Write, Bash, Grep, Glob$' agents/feater.md; grep -c 'AskUserQuestion' agents/feater.md; true` +Expected: `1` / `1` (or more) / `1` / `1` (exact tools line — no Agent tool) / `0` (no AskUserQuestion anywhere). + +Run: `python3 -c "import yaml; yaml.safe_load(open('agents/feater.md').read().split('---')[1]); print('YAML OK')"` +Expected: `YAML OK`. + +- [ ] **Step 5: Full suite + commit** + +Run: `make test` +Expected: green. + +```bash +git add skills/feat/SKILL.md agents/feater.md lib/verify-secure-loop.md +git commit -m "feat(model-routing): /feat re-architecture — reflection inline, feater = sonnet executor (partial supersede BDR-050)" +``` + +--- + +### Task 6: Pin SDD implementation subagents to sonnet (ship-feature, init-project) + +**Files:** +- Modify: `skills/ship-feature/SKILL.md:144-148` +- Modify: `skills/init-project/SKILL.md:166-170` + +**Interfaces:** +- Produces: the literal `model: "sonnet"` in both files — Task 8's census greps it. + +- [ ] **Step 1: ship-feature STEP 4** + +Edit `skills/ship-feature/SKILL.md`, `old_string`: + +``` +`finishing-a-development-branch` step — this orchestrator owns integration via +`gitflow finish` (STEP 9). When SDD's flow reaches "Use +finishing-a-development-branch", stop and return. +``` + +`new_string`: + +``` +`finishing-a-development-branch` step — this orchestrator owns integration via +`gitflow finish` (STEP 9). When SDD's flow reaches "Use +finishing-a-development-branch", stop and return. + +**Model routing (BDR-066):** every subagent dispatched under SDD — per-task +implementers AND its reviewers — MUST carry `model: "sonnet"` in the Agent +call. The plan is closed; execution and plan-conformity review are sonnet +work. Reflection (task decomposition, review verdict arbitration) stays in +this loop. +``` + +- [ ] **Step 2: init-project STEP 8** + +Edit `skills/init-project/SKILL.md`, `old_string`: + +``` +`finishing-a-development-branch` step — this orchestrator owns integration via +`gitflow finish` (STEP 11). When SDD's flow reaches "Use +finishing-a-development-branch", stop and return. +``` + +`new_string`: + +``` +`finishing-a-development-branch` step — this orchestrator owns integration via +`gitflow finish` (STEP 11). When SDD's flow reaches "Use +finishing-a-development-branch", stop and return. + +**Model routing (BDR-066):** every subagent dispatched under SDD — per-task +implementers AND its reviewers — MUST carry `model: "sonnet"` in the Agent +call. The plan is closed; execution and plan-conformity review are sonnet +work. Reflection (task decomposition, review verdict arbitration) stays in +this loop. +``` + +- [ ] **Step 3: Verify + commit** + +Run: `grep -c 'model: "sonnet"' skills/ship-feature/SKILL.md skills/init-project/SKILL.md` +Expected: `1` for each file. + +Run: `make test` — Expected: green. + +```bash +git add skills/ship-feature/SKILL.md skills/init-project/SKILL.md +git commit -m "feat(model-routing): SDD implementation + review subagents dispatched model sonnet" +``` + +--- + +### Task 7: web-validate fixes via hotfixer L1 applier + +**Files:** +- Modify: `skills/web-validate/SKILL.md:274-277` (STEP 3, options A and B) + +**Interfaces:** +- Consumes: hotfixer sonnet pin (Task 4); mirrors the geo L1 applier idiom (`skills/geo/SKILL.md:72-77`). +- Produces: `subagent_type="hotfixer"` in web-validate — Task 8's census greps it. + +- [ ] **Step 1: Replace inline-Edit application with L1 dispatch** + +Edit `skills/web-validate/SKILL.md`, `old_string`: + +``` +4. On `A` : apply each bundle via `Edit` (targeted `old_string` / + `new_string`). Never use `Write` on shared templates (risk of + overwriting /seo or /geo content — meta tags, JSON-LD). +5. On `B` : for each diff, show and ask yes/no/skip. +``` + +`new_string`: + +```` +4. On `A` : dispatch each file-group's applier at L1 (execution = sonnet; + this loop only orchestrates), serially — one applier at a time, appliers + share files: + + ``` + Agent(subagent_type="hotfixer") + prompt: ". + Context: web-validate fix bundle, user-approved scope — no + confirmation needed. Apply via targeted Edit (old_string/new_string); + NEVER Write whole files (shared templates carry /seo and /geo + content — meta tags, JSON-LD). Do NOT commit — apply and self-verify + only." + ``` + +5. On `B` : for each diff, show and ask yes/no/skip; apply approved diffs + as in `A` (hotfixer dispatch). +```` + +- [ ] **Step 2: Verify + commit** + +Run: `grep -c 'subagent_type="hotfixer"' skills/web-validate/SKILL.md` +Expected: `1`. + +Run: `make test` — Expected: green. + +```bash +git add skills/web-validate/SKILL.md +git commit -m "feat(model-routing): web-validate fix bundle applied via hotfixer at L1 (BDR-061 alignment)" +``` + +--- + +### Task 8: Census guard `lib/tests/model-routing.test.sh` + flip-test + +**Files:** +- Test: `lib/tests/model-routing.test.sh` (guarded path — sentinel required) + +**Interfaces:** +- Consumes: every string produced by Tasks 3-7 (see greps below). Auto-discovered by the Makefile `test` glob `lib/tests/*.test.sh` — no runner edit needed. + +- [ ] **Step 1: Write the census test** + +```bash +printf 'model-routing plan: add census guard test' > .claude/.config-edit-ok +``` + +Then create `lib/tests/model-routing.test.sh` with exactly: + +```bash +#!/usr/bin/env bash +# lib/tests/model-routing.test.sh — census: gate wiring + pins + executor shape (BDR-066) +set -u +R="$(cd "$(dirname "$0")/../.." && pwd)" +pass=0; fail=0 +ok() { pass=$((pass+1)); } +ko() { fail=$((fail+1)); printf 'FAIL %s\n' "$1"; } +has() { if grep -qF "$2" "$R/$1"; then ok; else ko "$1 missing: $2"; fi; } +lacks() { if grep -qF "$2" "$R/$1"; then ko "$1 must NOT contain: $2"; else ok; fi; } +fm_lacks() { if awk 'NR<=10' "$R/$1" | grep -qF "$2"; then ko "$1 frontmatter must NOT contain: $2"; else ok; fi; } + +# 1) gate wired in the 12 reflection orchestrators +for s in ship-feature init-project feat bugfix onboard seo geo web-validate harden audit-delta tour code-clean; do + has "skills/$s/SKILL.md" 'lib/model-gate.md' +done +# 2) gate NOT wired in the excluded skills (encodes the spec exclusion list) +for s in hotfix commit-change doc status release-candidate; do + lacks "skills/$s/SKILL.md" 'lib/model-gate.md' +done +# 3) executor + gate pins +has "agents/feater.md" 'model: sonnet' +has "agents/hotfixer.md" 'model: sonnet' +has "agents/verifier.md" 'model: sonnet' +has "agents/security-auditor.md" 'model: sonnet' +fm_lacks "agents/analyzer.md" 'model:' +# 4) /feat executor shape +has "skills/feat/SKILL.md" 'subagent_type="feater"' +has "skills/feat/SKILL.md" 'verify-secure-loop.md' +lacks "agents/feater.md" 'AskUserQuestion' +# 5) SDD execution pinned +has "skills/ship-feature/SKILL.md" 'model: "sonnet"' +has "skills/init-project/SKILL.md" 'model: "sonnet"' +# 6) web-validate applies via L1 applier +has "skills/web-validate/SKILL.md" 'subagent_type="hotfixer"' + +printf 'model-routing census: %d pass, %d fail\n' "$pass" "$fail" +[ "$fail" -eq 0 ] +``` + +- [ ] **Step 2: Run — expect green (everything already wired by Tasks 3-7)** + +Run: `bash lib/tests/model-routing.test.sh` +Expected: `model-routing census: 28 pass, 0 fail`, exit 0. (Count: 12 wired + 5 excluded + 5 pins + 3 feat-shape + 2 SDD + 1 web-validate.) + +- [ ] **Step 3: Flip-test the guard (LRN-096 — prove it CAN fail)** + +```bash +sed -i 's|lib/model-gate.md|lib/model-gate-REMOVED.md|' skills/tour/SKILL.md +bash lib/tests/model-routing.test.sh; echo "exit=$?" +git checkout -- skills/tour/SKILL.md +bash lib/tests/model-routing.test.sh; echo "exit=$?" +``` + +Expected: first run prints `FAIL skills/tour/SKILL.md missing: lib/model-gate.md` and `exit=1`; second run prints `28 pass, 0 fail` and `exit=0`. + +- [ ] **Step 4: Lint + full suite + commit** + +Run: `shellcheck lib/tests/model-routing.test.sh && make test` +Expected: clean + green. + +```bash +git add lib/tests/model-routing.test.sh +git commit -m "test(model-routing): census guard — gate wiring, pins, executor shape (flip-tested)" +``` + +--- + +### Task 9: README + CHANGELOG + +**Files:** +- Modify: `README.md` (agent/model documentation) +- Modify: `CHANGELOG.md` (Unreleased section) + +- [ ] **Step 1: Locate the README insertion point** + +Run: `grep -niE 'agents?/|sonnet|haiku|model' README.md | head -20` + +If README has a table listing agents (a row per agent), refresh/add its model info from the table below. If not, insert a new subsection `### Agent model routing (BDR-066)` immediately after the section that documents `agents/` (fallback: before the "Skills" section), with exactly: + +```markdown +### Agent model routing (BDR-066) + +Reflection (brainstorm, plan, contract, audit judgment, loop decisions) runs +INLINE on the session model — assumed Fable/Opus, enforced by a blocking +gate (`lib/model-gate.md` + `lib/model-check.sh`) at the entry of the 12 +reflection orchestrators. Execution runs on pinned subagents: + +| Agent | Model | Tier | +|---|---|---| +| feater, hotfixer | sonnet (pinned) | executors — code from a closed plan, fix-bundle appliers | +| verifier, security-auditor | sonnet (pinned) | fresh gates (≤3×/loop) | +| doc-syncer, onboarder, scaffolder, refactorer, interviewer, plugin-advisor | sonnet (pinned) | workers | +| status-reporter | haiku (pinned) | mechanical collector | +| client-handover-writer | opus (pinned, currently inert — inline-loaded; sonnet conversion planned) | deliverable writer | +| analyzer, seo-analyzer, geo-analyzer, validator-analyzer, code-cleaner, bugfixer, commit-changer | inherit session (Fable/Opus) | reflection / audit / inline playbooks | +``` + +- [ ] **Step 2: CHANGELOG** + +Run: `grep -n 'Unreleased' CHANGELOG.md` + +Under the `## [Unreleased]` heading (create `### Added` / `### Changed` subsections if absent), add: + +```markdown +### Added +- Model routing (BDR-066): blocking model gate (`lib/model-gate.md` + + `lib/model-check.sh`, flip-tested) wired into 12 reflection orchestrators; + census guard `lib/tests/model-routing.test.sh`. +- `/feat` re-architected: reflection inline (scope/plan/contract), execution + dispatched to the sonnet-pinned `feater` executor; verify+secure loop + decided in the main loop with fresh executor re-dispatches. + +### Changed +- `hotfixer` pinned `model: sonnet` (seo/geo/web-validate L1 applier); + `analyzer` haiku pin removed (inherits the session model). +- ship-feature / init-project: SDD implementation + review subagents + dispatched with `model: "sonnet"`. +- web-validate `--fix`: bundle applied via `hotfixer` at L1 instead of + inline Edit (BDR-061 alignment). +``` + +- [ ] **Step 3: Commit** + +Run: `make test` — Expected: green. + +```bash +git add README.md CHANGELOG.md +git commit -m "docs(model-routing): README agent-model table + CHANGELOG entry" +``` + +--- + +### Task 10: Capitalize memory + TODO follow-up + +**Files:** +- Modify: `.claude/memory/decisions.md` (append BDR-066 + Index row) +- Modify: `.claude/memory/journal.md` (1 line under a `## 2026-07-15` heading) +- Modify: `.claude/tasks/TODO.md` (chantier section + plan-2 backlog) + +- [ ] **Step 1: Append BDR-066 to `.claude/memory/decisions.md`** + +Add to the Index table (after the BDR-065 row): + +```markdown +| BDR-066 | 2026-07-15 | Model routing: reflection inline (session big model) + sonnet-pinned executors + blocking gate | accepted | +``` + +Append at end of file: + +```markdown +## BDR-066 — Model routing: reflection inline (session big model), executors pinned sonnet, blocking gate + +- **Date**: 2026-07-15 +- **Status**: accepted (partial supersede of BDR-050: /feat dev no longer inline; bugfix/hotfix dev-inline CONSERVED) +- **Decision**: reflection (brainstorm, plan, contract, audit judgment, loop decisions) runs on session model (Fable; Opus fallback) — inline or inherit subagents, never pinned down. Execution (code from closed plan, fix-bundle application) runs sonnet-pinned subagents: feater + hotfixer pinned sonnet; SDD implementation+review subagents dispatched `model: "sonnet"` (ship-feature/init-project); web-validate fixes via hotfixer L1 (was inline Edit). analyzer haiku pin REMOVED (digest feeds plan = reflection tier). verifier + security-auditor STAY sonnet (job9 confirmed — procedural gates, ≤3×/loop). Blocking gate `lib/model-gate.md` (self-check + witness `lib/model-check.sh`) wired in 12 reflection orchestrators; small → STOP, unknown → fail-visible; census guard `lib/tests/model-routing.test.sh` flip-tested. +- **Why**: big-model quota burned on mechanical execution (Fable exhausted mid-job8); plan closed at dispatch → executor needs obedience not judgment; fresh sonnet gates catch executor drift. +- **Alternatives rejected**: opus pins on audit agents (session-independent) — rejected: session assumed big + blocking gate as backstop, one tier fewer; advisory gate — rejected by user, blocking; split bugfix/hotfix too — rejected: bugfix investigation interleaved w/ fix, hotfix gain marginal vs dispatch overhead. +- **Caveats**: client-handover-writer conversion (inline-load → sonnet dispatch, 11 human-gate sites to relocate) DEFERRED to own plan — its opus pin stays inert meanwhile; feater cannot ask → NEED-DECISION report = escalation valve, plan must close decisions; witness reads settings.json — lags `--model`-launched sessions (self-check compensates). +- **Reference**: spec `docs/superpowers/specs/2026-07-15-model-routing-design.md` + plan `docs/superpowers/plans/2026-07-15-model-routing.md` (transient, BDR-065 lifecycle), branch `feature/model-routing`. +``` + +- [ ] **Step 2: Journal line** + +Append under a `## 2026-07-15` heading (create it if absent) in `.claude/memory/journal.md`: + +```markdown +- model routing shipped on feature/model-routing: BDR-066 (reflection inline big / executors sonnet / blocking gate), /feat re-arch, census guard. client-handover conversion deferred to plan 2. +``` + +- [ ] **Step 3: TODO follow-up entry** + +Add at the top of `.claude/tasks/TODO.md` (above the 2026-07-08 section): + +```markdown +## 2026-07-15 — model routing (feature/model-routing) +Spec + plan in docs/superpowers/ (transient, BDR-065). BDR-066. Branch +unmerged — human gate. +- [x] gate lib/model-check.sh + lib/model-gate.md (flip-tested) wired ×12 +- [x] pins: hotfixer/feater sonnet, analyzer un-pinned; SDD model:"sonnet"; + web-validate → hotfixer L1; census guard model-routing.test.sh +- [x] /feat re-arch: reflection inline → feater sonnet executor (partial + supersede BDR-050) +- [ ] DOGFOOD (manual, next sessions): /feat live run — plan closes + decisions, dispatch carries sonnet, verify loop in main loop; gate + STOP on a sonnet session (LRN-079 class, not automatable here) +- [ ] PLAN 2 — client-handover conversion (spec §5): inline-load → sonnet + dispatch, relocate 11 human-gate sites to dispatcher (inventory in + plan-1 session), or lighter variant: dispatch only the redaction + phase. Decide shape at plan time. +``` + +- [ ] **Step 4: Commit memory scoped** + +```bash +git add .claude/memory/decisions.md .claude/memory/journal.md .claude/tasks/TODO.md +git commit -m "chore(memory): BDR-066 model routing + journal + TODO follow-ups" +``` + +- [ ] **Step 5: Final gate** + +Run: `make test` +Expected: green, exit 0. Then report the full commit list (`git log --oneline develop..HEAD`) for the human merge gate. Do NOT run `gitflow finish`. + +--- + +# WAVE 2 — pure-execution + reflection-split skills (user directive 2026-07-15) + +The wave-1 exclusion list left `hotfix, commit-change, doc, status, release-candidate` +inheriting the session model — i.e. running EXECUTION on the big model, the +waste the split exists to kill. User verdicts (2026-07-15): +- **doc / status** = pure non-interactive execution → convert inline-load to a + dispatched subagent so its pin takes effect. doc-syncer stays sonnet; + status-reporter stays **haiku** (right tier for a read-only collector; the + win is getting it off the big model, not the tier). +- **hotfix** = reflection (locate root cause + propose fix) + execution → split + like /feat: reflection inline (+ MODEL GATE), execution dispatched to the + sonnet hotfixer executor. hotfix JOINS the gated group (12→13). +- **commit-change** = grouping (judgment) + committing (execution), interactive + → dispatch EVERYTHING (grouping included) to a sonnet commit-changer, relocate + the two approval gates to the dispatcher (propose→confirm→execute, seo-applier + shape). No MODEL GATE (no inline reflection — grouping runs on sonnet). +- **release-candidate** = create a sonnet `release-executor` agent for the + mechanical spans (version.txt, CHANGELOG rewrite, gitflow start/finish, tag), + relocate the two human gates (when-to-release, push) to the dispatcher. No + MODEL GATE (user's explicit choice — force dispatch, not gate). + +Post-wave-2 gate exclusion list = `commit-change, doc, status, release-candidate` +(hotfix removed — now wired). + +## Global Constraints (wave 2) + +Same as wave 1: branch `feature/model-routing`, no merge, no attribution +trailers, `make test` green per commit, shellcheck clean, config-protection +sentinel before each `lib/tests/*` write, YAML `safe_load`-parseable frontmatter. + +--- + +### Task 11: doc + status → dispatched execution + +**Files:** +- Modify: `skills/doc/SKILL.md` (add `Agent` to allowed-tools; body → dispatch) +- Modify: `skills/status/SKILL.md` (add `Agent` to allowed-tools; body → dispatch) + +**Interfaces:** doc-syncer.md is already `model: sonnet`; status-reporter.md is +already `model: haiku` — no agent edits. Only the skills change from inline-load +to `Agent(subagent_type=…)` so the pins take effect. + +- [ ] **Step 1: doc → dispatch.** In `skills/doc/SKILL.md`, add ` - Agent` to the + `allowed-tools` list, and replace the body block + ``` + Load and follow strictly: + - $HOME/.claude/agents/doc-syncer.md + + Execute the DOC SYNCER on this project. + + Context from the user (if any): + $ARGUMENTS + ``` + with: + ``` + Dispatch the doc-syncer as a subagent so its `model: sonnet` pin takes + effect (doc-sync = execution, not the session's big model): + + Agent(subagent_type="doc-syncer") + prompt: "Audit + sync public docs for this project. Context from the user: + $ARGUMENTS. Report PATCHED_FILES and a summary — do NOT commit." + + Then commit the patched docs from THIS loop per `$HOME/.claude/lib/doc-commit.md` + (surgical: only doc-syncer's PATCHED_FILES, never `.claude/`/`CLAUDE.md`, + no-op if nothing patched). + ``` + +- [ ] **Step 2: status → dispatch.** In `skills/status/SKILL.md`, add `Agent` to + `allowed-tools` (`Read, Bash, Glob, Grep, Agent`), and replace the body + `Load and follow strictly:\n- $HOME/.claude/agents/status-reporter.md\n\nProduce the full PROJECT STATUS report for the current working directory.` + with a dispatch: + ``` + Dispatch the status-reporter as a subagent so its `model: haiku` pin takes + effect (read-only collection = cheapest tier, off the big session model): + + Agent(subagent_type="status-reporter") + prompt: "Produce the full PROJECT STATUS report for the current working + directory. $ARGUMENTS" + ``` + Keep the existing "Fallback when agent file missing" section intact (it still + applies — if the dispatch target is unreachable, emit the missing-agent line + and STOP). + +- [ ] **Step 3: Verify + commit.** `grep -c 'subagent_type="doc-syncer"' skills/doc/SKILL.md` + → 1; `grep -c 'subagent_type="status-reporter"' skills/status/SKILL.md` → 1. + `make test` green. + ```bash + git add skills/doc/SKILL.md skills/status/SKILL.md + git commit -m "feat(model-routing): doc/status dispatch their agent (sonnet/haiku pins take effect)" + ``` + +--- + +### Task 12: hotfix — reflection inline + dispatched sonnet executor (/feat pattern) + +**Files:** +- Modify (rewrite): `skills/hotfix/SKILL.md` — becomes the reflection orchestrator +- Modify (rewrite): `agents/hotfixer.md` — becomes pure executor +- Modify: `lib/tests/loops-light.test.sh` — repoint hotfix structure locks (guarded) + +**Pattern:** mirror the shipped `/feat` split (skills/feat/SKILL.md + agents/feater.md). + +- [ ] **Step 1: Rewrite `skills/hotfix/SKILL.md` as the orchestrator.** Keep `Agent` + in allowed-tools. Structure: + - `# /hotfix — quick-fix orchestrator (reflection inline, execution dispatched)` + - `MODEL GATE (blocking): run $HOME/.claude/lib/model-gate.md BEFORE any step. small → STOP.` + (hotfix now has a reflection phase → it joins the gated group.) + - STEP 1 LOCATE (reflection, inline): find the bug from the description, read + the file(s), CONFIRM the root cause is obvious/superficial, escalate to + `/bugfix` if deeper. Optional blockers-only memory glance (as today). + - STEP 1.5 DESIGN GATE (`lib/design-gate.md`, as today). + - STEP 1.7 CONTRACT (silent autofill, `lib/contract-interview.md`, zero + questions, as today). + - STEP 2 PRE-FLIGHT (inline): gitflow aiguillage (type `hotfix`); snapshot + `git rev-parse HEAD` (the revert SHA) + dirty-tree check (as today's STEP 2 + pre-flight). + - STEP 3 DISPATCH EXECUTOR: `Agent(subagent_type="hotfixer")` with the + contract path, the located file(s), the proposed minimal fix, and the branch. + Parse a `HOTFIX-EXEC REPORT` with `STATUS : DONE | BLOCKED`. + - STEP 4 VERIFY + SECURE + COMMIT (main loop, LRN-083): on executor DONE, the + smoke result is in its report; then the security gate — dispatch a FRESH + security-auditor (`MODE: gate`, SCOPE = diff vs the pre-flight SHA). **hotfix + keeps revert-not-loop**: smoke FAIL or security BLOCK → `git restore .` to the + pre-flight SHA + STOP + "escalate to /bugfix" (verbatim from today's STEP 3). + No verifier at hotfix weight. Commit only after smoke + security pass. + - STEP 5 DOC SYNC + STEP 6 CAPITALIZE: identical to today's STEP 4/5 (doc-sync + auto-mode + `doc-commit.md`; lightweight capitalize + always-on journal + + `capitalize-commit.md`). + - RULES: max 2 files; execution never stays inline, reflection never leaves it + (BDR-066); executor dispatched fresh; revert-not-loop preserved. + +- [ ] **Step 2: Rewrite `agents/hotfixer.md` as the executor.** Frontmatter: + `tools: Read, Edit, Write, Bash, Grep, Glob` (DROP `Agent` — no nested dispatch; + security moved to the orchestrator), `model: sonnet`. Body: receive + CONTRACT + located file(s) + proposed fix + BRANCH (verify with + `git branch --show-current`, never switch). Apply the minimal edit (no + refactoring), run the stack smoke/test cascade (keep today's detection cascade), + report. FORBIDDEN: git commit, branch ops, security dispatch, user questions, + attribution trailers. End with: + ``` + HOTFIX-EXEC REPORT + STATUS : DONE | BLOCKED + FILE(S) : + FIX : + SMOKE : + NOTES : + ``` + +- [ ] **Step 3: Repoint `lib/tests/loops-light.test.sh` hotfix locks** (guarded — + sentinel first). The hotfix block currently checks `agents/hotfixer.md` for + orchestration clauses now moved to the skill. Introduce `HSKL="$REPO/skills/hotfix/SKILL.md"` + and repoint: contract/silent → HSKL `STEP 1.7 — CONTRACT`; security gate + + `failure REVERTS, never loops` + `No verifier is dispatched at hotfix weight` + → HSKL; `hotfix skill has Agent` (HSK ` - Agent`) unchanged. The + `hotfix has Agent tool` lock on hotfixer INVERTS (hotfixer no longer has Agent) + → change to assert hotfixer LACKS Agent and carries `model: sonnet` + the + `HOTFIX-EXEC REPORT` grammar. Add a `hotfix dispatches hotfixer` lock + (`subagent_type="hotfixer"` in HSKL). Keep include/feat/bugfix blocks untouched. + Add a negative-match helper `tn()` (mirror `tf`, invert the grep) if asserting + Agent-absence. + +- [ ] **Step 4: Wire hotfix into the census + gate lists.** In + `lib/tests/model-routing.test.sh` (guarded — sentinel first): MOVE `hotfix` + from the excluded loop to the wired loop (`has "skills/hotfix/SKILL.md" 'lib/model-gate.md'`). + Update the expected count in the run message accordingly. + +- [ ] **Step 5: Verify + commit.** `bash lib/tests/loops-light.test.sh` green; + `bash lib/tests/model-routing.test.sh` green; YAML check both rewritten files; + `make test` green. + ```bash + git add skills/hotfix/SKILL.md agents/hotfixer.md lib/tests/loops-light.test.sh lib/tests/model-routing.test.sh + git commit -m "feat(model-routing): /hotfix split — reflection inline + gate, hotfixer = sonnet executor" + ``` + +--- + +### Task 13: commit-change — dispatch grouping+commit to sonnet, relocate approval gates + +**Files:** +- Modify (rewrite): `skills/commit-change/SKILL.md` — dispatcher owns the two gates +- Modify (rewrite): `agents/commit-changer.md` — sonnet, propose/execute phases, no AskUserQuestion + +**Pattern:** seo-applier shape (subagent proposes → dispatcher confirms → subagent executes). + +- [ ] **Step 1: Rewrite `agents/commit-changer.md`.** Frontmatter: + `tools: Bash, Read, Grep, Glob` (DROP `AskUserQuestion` — gates move to the + dispatcher), `model: sonnet`. Body: two modes driven by the dispatch prompt. + - `MODE: propose` → Phase 0 (gitflow aiguillage, type chore — bash), Phase 1 + (gather), Phase 2 (reconstruct steps), Phase 2.5 → EMIT the `COMMIT PLAN` + block + any edge-case flags (sensitive files, staged-only, conflicts) + + Phase-4 capitalize candidates, then STOP with + `READY TO APPLY — awaiting dispatcher confirmation`. Writes NOTHING. + - `MODE: apply` → receive the APPROVED plan (steps + messages) + approved + capitalize entries; execute Phase 3 (stage-per-step + commit) and write the + approved memory via `capitalize-commit.md`; report the commit hashes. + +- [ ] **Step 2: Rewrite `skills/commit-change/SKILL.md` as dispatcher.** Keep + `Agent` + `AskUserQuestion` in allowed-tools. Flow: pre-flight (detached HEAD / + conflicts / identity — STOP as today) → `Agent(subagent_type="commit-changer")` + with `MODE: propose` → show the returned COMMIT PLAN, `AskUserQuestion` + (all / numbers / edit / skip) → show capitalize candidates, `AskUserQuestion` + (all / IDs / skip) → `Agent(subagent_type="commit-changer")` with `MODE: apply` + + the approved plan + approved entries → report hashes. NO MODEL GATE (grouping + runs on the sonnet subagent — no inline reflection to protect). + +- [ ] **Step 3: Verify + commit.** `grep -c 'subagent_type="commit-changer"' skills/commit-change/SKILL.md` + ≥ 1; `grep -c 'model: sonnet' agents/commit-changer.md` → 1; + `grep -c 'AskUserQuestion' agents/commit-changer.md` → 0; YAML check; `make test` green. + ```bash + git add skills/commit-change/SKILL.md agents/commit-changer.md + git commit -m "feat(model-routing): /commit-change dispatch to sonnet commit-changer, gates relocated to dispatcher" + ``` + +--- + +### Task 14: release-candidate — sonnet release-executor, human gates relocated + +**Files:** +- Create: `agents/release-executor.md` — sonnet, mechanical release spans +- Modify (rewrite): `skills/release-candidate/SKILL.md` — dispatcher owns the two human gates + +- [ ] **Step 1: Create `agents/release-executor.md`.** Frontmatter: + `tools: Read, Edit, Write, Bash, Grep, Glob`, `model: sonnet`. Two-span + executor driven by the dispatch prompt (a human gate sits BETWEEN the spans, so + it cannot be one dispatch): + - `SPAN: prep ` → `gitflow start release `, set `version.txt`, + rewrite CHANGELOG (`## [Unreleased]` → `## [] — `, re-open empty + Unreleased; a MAJOR must spell out breaking), run the test suite (RC gate — + never release red), commit the prep on the release branch. Report the branch + + test result. No merge, no tag, no push. + - `SPAN: finish ` → `gitflow finish` (fan-out), `git tag -a v main + -m "release "` AFTER finish. Report. NEVER push (dispatcher's gate). + - FORBIDDEN: deciding the version number (dispatcher/user owns it), the + when-to-release decision, `git push`, attribution trailers. + +- [ ] **Step 2: Rewrite `skills/release-candidate/SKILL.md` as dispatcher.** Add + `allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Agent, AskUserQuestion` to + the frontmatter (it currently has none). Keep all the Overview/Versioning/Common- + mistakes doctrine. Flow: preconditions (clean tree, identity, develop ahead of + main) → the version-number decision stays HERE (judgment: derives from change + nature; decide before running) → `Agent(subagent_type="release-executor")` + `SPAN: prep ` → **HUMAN GATE — when to release** (`AskUserQuestion`, + explicit go, never on "tests pass") → `Agent(subagent_type="release-executor")` + `SPAN: finish ` → **push GATE (ASK)** (`AskUserQuestion`; on go only, + LRN-069): `git push origin main develop && git push origin v` from THIS + loop. No MODEL GATE. + +- [ ] **Step 3: Verify + commit.** `RC_WORK=$(mktemp -d) RC_TAG=1 bash lib/tests/run-release-candidate.sh` + → 5/5 (the release mechanics test is unchanged — the lib still fans out + the + dispatcher still tags); `grep -c 'subagent_type="release-executor"' skills/release-candidate/SKILL.md` + ≥ 1; YAML check the new agent; `make test` green. + ```bash + git add agents/release-executor.md skills/release-candidate/SKILL.md + git commit -m "feat(model-routing): /release-candidate dispatches sonnet release-executor, human gates in dispatcher" + ``` + +--- + +### Task 15: census + docs + memory for wave 2 + +**Files:** +- Modify: `lib/tests/model-routing.test.sh` (guarded) — wave-2 assertions +- Modify: `README.md`, `CHANGELOG.md`, `.claude/memory/decisions.md`, `.claude/tasks/TODO.md` + +- [ ] **Step 1: Extend the census** (`lib/tests/model-routing.test.sh`, guarded — + sentinel first). The excluded loop drops `hotfix` (moved to wired by Task 12 Step 4) + and now reads `for s in commit-change doc status release-candidate`. Add + execution-dispatch asserts: `has skills/doc/SKILL.md 'subagent_type="doc-syncer"'`; + `has skills/status/SKILL.md 'subagent_type="status-reporter"'`; + `has skills/commit-change/SKILL.md 'subagent_type="commit-changer"'`; + `has skills/release-candidate/SKILL.md 'subagent_type="release-executor"'`; + pins `has agents/commit-changer.md 'model: sonnet'`, + `has agents/release-executor.md 'model: sonnet'`; and executor-shape + `lacks agents/commit-changer.md 'AskUserQuestion'`. Update the printed expected + count. Flip-test one new assertion (LRN-096). + +- [ ] **Step 2: README + CHANGELOG.** Update the BDR-066 agent-model table: + hotfixer stays sonnet (now an effective executor), commit-changer → sonnet, + release-executor (new) → sonnet, status-reporter → haiku (now effective via + dispatch). Move doc/status/commit-change/release-candidate out of the "inherit" + row into a new "execution — dispatched" line. CHANGELOG Unreleased: add the + wave-2 bullets (doc/status/hotfix/commit-change/release-candidate routing). + +- [ ] **Step 3: Capitalize.** Append to the BDR-066 entry a `**Wave 2**` bullet: + doc/status dispatched (sonnet/haiku pins effective); hotfix split like /feat + (joins gated group); commit-change dispatched sonnet with relocated gates; + release-candidate sonnet release-executor with relocated human gates; exclusion + list now commit-change/doc/status/release-candidate. Journal line + + TODO tick under the 2026-07-15 section. + ```bash + git add lib/tests/model-routing.test.sh README.md CHANGELOG.md .claude/memory/decisions.md .claude/memory/journal.md .claude/tasks/TODO.md + git commit -m "chore(model-routing): wave-2 census + docs + BDR-066 update" + ``` + +- [ ] **Step 4: Final wave-2 review** — dispatch a whole-branch reviewer (opus) over + the wave-2 range; confirm both consumers of verify-secure-loop still coherent, + hotfix revert-not-loop preserved, no execution left on the big model in the + five converted skills. Report the full `git log --oneline develop..HEAD`. Do NOT + merge. + +--- + +# WAVE 3 — reflection-split the last two inline execution-carrying agents (user directive 2026-07-15) + +`/bugfix` and `/code-clean` are still thin wrappers that inline-load an agent +doing BOTH reflection and execution on the big session model — the exact +pre-split state `/feat` (Task 5) and `/hotfix` (Task 12) were in. Split each +like the shipped pattern: reflection inline (session model, behind the MODEL +GATE both skills already carry), execution dispatched to a sonnet executor. + +**Honest tradeoff (recorded in the wave-3 BDR bullet):** bugfix's investigation +and fix are tightly coupled; handing a context-free sonnet executor a closed +FIX PLAN is the same bet `/feat` makes — mitigated by the structured DIAGNOSIS ++ the verify loop catching drift. Further supersedes the BDR-050 "bugfix stays +inline" carve-out (hotfix already reversed in wave 2). code-clean's win is +larger than it looks: today it INLINE-LOADS the refactorer (so the refactor +runs on the big model, sonnet pin inert) — after the split the refactor runs +inside the sonnet executor for the first time. + +Gate membership is UNCHANGED: both skills keep reflection (investigation / +audit), so both STAY in the wired gate list — this wave only adds +executor-shape asserts, it does not move either skill between the wired and +excluded lists. + +## Global Constraints (wave 3) + +Same as waves 1–2: branch `feature/model-routing`, no merge, no attribution +trailers, `make test` green per commit, shellcheck clean, config-protection +sentinel before each `lib/tests/*` write (controller applies guarded test +edits — subagents cannot create the sentinel), YAML `safe_load`-parseable +frontmatter. + +--- + +### Task 16: `/bugfix` split — reflection inline + dispatched sonnet executor + +**Files:** +- Modify (rewrite): `skills/bugfix/SKILL.md` — thin wrapper → reflection orchestrator +- Modify (rewrite): `agents/bugfixer.md` — full agent → pure sonnet executor +- Modify (surgical): `lib/verify-secure-loop.md` — bugfix's dev is now dispatched too +- Modify: `lib/tests/loops-light.test.sh` — repoint bugfix locks (guarded — CONTROLLER applies) + +**Pattern:** mirror the shipped `/hotfix` split (skills/hotfix/SKILL.md — it is +the closest template: reflection orchestrator + a security gate whose decisions +live in the main loop) and `/feat` (agents/feater.md — the pure-executor shape). +The difference from hotfix: bugfix keeps the FULL verify+secure loop (fresh +verifier + fresh security, bounded 3×, per `lib/verify-secure-loop.md`) and the +interactive pre-commit + capitalize gates — hotfix has none of those. + +- [ ] **Step 1: Rewrite `skills/bugfix/SKILL.md` as the reflection orchestrator.** + Keep `Agent` in allowed-tools; the frontmatter description block is unchanged. + Keep the existing `MODEL GATE (blocking)` line verbatim (bugfix stays gated). + Absorb, INLINE (session model), what were bugfixer STEPs 1–3.5 — reflection: + - STEP 1 GATHER CONTEXT (git status/log; what/where/when). + - STEP 1.5 DESIGN GATE (`$HOME/.claude/lib/design-gate.md`, unchanged). + - STEP 2 INVESTIGATE (trace symptom → root cause, blast radius). + - STEP 2.5 MEMORY READ-BEFORE (`$HOME/.claude/lib/analyze-before-plan.md`, + blockers-weighted; keep the TEETH clause — DIAGNOSIS must name any binding + prior or state none bears). + - STEP 3 DIAGNOSE + PLAN — emit the `BUGFIX — DIAGNOSIS` block (BUG / ROOT + CAUSE / EVIDENCE / BLAST RADIUS / FIX PLAN / RISK) verbatim from today's + bugfixer STEP 3. Keep the significance gate: trivial → proceed; significant + (>10 lines / multi-file / behavior change) → wait for user approval; + root-cause unclear → list ranked hypotheses, ask before proceeding. + - STEP 3.5 CONTRACT (`$HOME/.claude/lib/contract-interview.md`, main loop; + DIAGNOSIS feeds it — REQUEST verbatim = the bug report, ACCEPTANCE = + symptom reproduced-then-gone + regression test present+passing, FILE SCOPE + = the FIX PLAN files; keep the contract path for STEP 5). + - STEP 4 BRANCH: gitflow aiguillage (`$HOME/.claude/lib/gitflow-aiguillage.md`, + type `bugfix`; never finish). + - STEP 5 DISPATCH EXECUTOR: + ``` + Agent(subagent_type="bugfixer") + prompt: "CONTRACT: + DIAGNOSIS: + FIX PLAN: + BRANCH: + Apply the fix to the letter + the regression test. No commit, no branch + ops, no security dispatch. Finish with the BUGFIX-EXEC REPORT." + ``` + Parse `BUGFIX-EXEC REPORT`: `STATUS : DONE` → STEP 6; `NEED-DECISION` → + decide HERE (reflection), append to the plan, re-dispatch a FRESH bugfixer, + max 2 round-trips → escalate; `BLOCKED` → surface + stop. + - STEP 6 VERIFY + SECURE + PRE-COMMIT GATE + COMMIT (main loop, LRN-083): + run the two fresh gates per `$HOME/.claude/lib/verify-secure-loop.md` with + `CONTRACT` = STEP 3.5 path, `DIFF` = the executor's working-tree diff, + `TEST` = the suite from its report (the loop's "dev" is the dispatched + bugfixer — re-dispatched FRESH on ECARTS/BLOCK). After both gates pass, + keep today's interactive `BUGFIX — READY TO COMMIT` pre-commit gate + (diff-stat + message → yes / edit message / skip / amend last), then commit + with the conventional `fix():` message, then print `BUGFIX COMPLETE`. + - STEP 7 DOC SYNC (doc-syncer auto-mode + `$HOME/.claude/lib/doc-commit.md`, + verbatim from today's bugfixer STEP 6). + - STEP 8 CAPITALIZE (BLK-XXX pre-filled from DIAGNOSIS + optional LRN; + interactive gate; `$HOME/.claude/lib/capitalize-commit.md`; verbatim from + today's bugfixer STEP 7). + - RULES: no fix without root cause first; execution never stays inline, + reflection never leaves it (BDR-066); executor dispatched fresh; keep + regression-test + scoped-fix + escalate-to-/ship-feature-if->5-files rules. + +- [ ] **Step 2: Rewrite `agents/bugfixer.md` as the pure executor.** Replace the + ENTIRE file with exactly: + +````markdown +--- +name: bugfixer +description: Bug-fix EXECUTOR — dispatched by /bugfix with a closed DIAGNOSIS + FIX PLAN + contract. Applies the fix and a regression test, runs the suite, reports. No investigation, no questions, no commit. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet +--- + +# BUGFIXER — fix executor + +You receive a CLOSED diagnosis + fix plan from the /bugfix orchestrator. The +investigation already happened; your job is faithful execution, not analysis. +Every choice was made in the plan or is a NEED-DECISION to report. + +## INPUT (in the dispatch prompt) + +- `CONTRACT`: path to the contract file — read it FIRST; its acceptance + criteria (symptom reproduced-then-gone + a regression test present) + FILE + SCOPE bound everything you do. +- `DIAGNOSIS`: root cause + evidence, from the orchestrator's investigation. +- `FIX PLAN`: the exact edits (file:line → change) + the regression test to add. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. +- `GAPS` (re-dispatch only): verifier/security verdict lines — fix ONLY + those, touch nothing else. + +## EXECUTION RULES + +- Apply the FIX PLAN to the letter — fix the ROOT CAUSE named in DIAGNOSIS, + not the symptom. A plan hole or an open choice (naming, data shape, API + surface, dependency) → STOP, report `NEED-DECISION` with the precise + question. Never re-investigate or improvise a different fix. +- Stay inside the contract FILE SCOPE. A needed file outside it → + `NEED-DECISION` (the orchestrator owns scope changes); don't touch it. +- Add or update the regression test the plan names — it must fail before the + fix and pass after. Run the relevant suite incrementally; run it fully + before reporting. +- Follow existing code patterns and CLAUDE.md limits (function size, params, + no global state). Keep the fix minimal — no "while we're here" cleanups. +- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, + security/verifier dispatch, editing `.claude/**` or memory registries, user + questions (you cannot ask — report instead), attribution trailers of any kind. + +## OUTPUT — end with exactly this report (your final message) + +``` +BUGFIX-EXEC REPORT +STATUS : DONE | NEED-DECISION | BLOCKED +FILE(S) : +TEST(S) : +SMOKE : +NOTES : +``` +```` + +- [ ] **Step 3: Update `lib/verify-secure-loop.md` (both consumers now dispatched).** + The header line `(feat, bugfix)` stays. In the intro, the sentence that says + the dev step is "either inline (bugfix) or a dispatched sonnet executor + (/feat's feater)" is now stale — BOTH are dispatched. Edit it to: the dev + step is a dispatched sonnet executor (feat's `feater`, bugfix's `bugfixer`); + "hand the dev" below means re-dispatch a FRESH executor with exactly those + inputs. Keep GATE 1 / GATE 2 / order-invariant bodies unchanged (they already + read "inline dev fixes in place; a dispatched dev is re-dispatched FRESH" — + the inline branch simply no longer has a consumer, harmless). + +- [ ] **Step 4 (CONTROLLER — guarded): repoint `lib/tests/loops-light.test.sh` + bugfix locks.** Sentinel first: + `printf 'model-routing plan: repoint bugfix structure locks to the skill orchestrator' > .claude/.config-edit-ok` + Introduce `BSK="$REPO/skills/bugfix/SKILL.md"`. The `bugfixer.md (bugfix wiring)` + block currently greps `$BUG` for orchestration clauses now moved to the skill — + repoint them to `$BSK`: `STEP 3.5 — CONTRACT`, `feeds it: REQUEST verbatim`, + `Fresh gates (verify + secure)` (or the skill's actual STEP-6 wording — match + it), `lib/verify-secure-loop.md`. Add a new `bugfixer.md (executor — sonnet, + no Agent)` block mirroring the hotfixer one: `tn` bugfixer LACKS `Agent`, + `tf` `model: sonnet`, `tf` `BUGFIX-EXEC REPORT`. Add `tf "bugfix dispatches + bugfixer" "$BSK" 'subagent_type="bugfixer"'`. Keep include/feat/hotfix blocks + untouched. + +- [ ] **Step 5: Verify + commit.** `bash lib/tests/loops-light.test.sh` green; + YAML check both rewritten files + (`python3 -c "import yaml; [yaml.safe_load(open(f).read().split('---')[1]) for f in ['agents/bugfixer.md','skills/bugfix/SKILL.md']]; print('YAML OK')"`); + `make test` green. + ```bash + git add skills/bugfix/SKILL.md agents/bugfixer.md lib/verify-secure-loop.md lib/tests/loops-light.test.sh + git commit -m "feat(model-routing): /bugfix split — reflection inline, bugfixer = sonnet executor (supersedes BDR-050 bugfix carve-out)" + ``` + +--- + +### Task 17: `/code-clean` split — audit + gate inline + dispatched sonnet executor + +**Files:** +- Modify (rewrite): `skills/code-clean/SKILL.md` — thin wrapper → audit orchestrator +- Modify (rewrite): `agents/code-cleaner.md` — full agent → pure PHASE-2 sonnet executor + +**Pattern:** mirror `/feat` (skill = orchestrator holding reflection + interactive +gate; agent = pure executor). The interactive VALIDATION GATE must stay in the +orchestrator (a dispatched subagent cannot ask). code-cleaner gains `model: sonnet`. + +- [ ] **Step 1: Rewrite `skills/code-clean/SKILL.md` as the audit orchestrator.** + Add `Agent` to allowed-tools (keep `AskUserQuestion`, `Read/Edit/Write/Bash/ + Grep/Glob`). Keep the existing `MODEL GATE (blocking)` line verbatim (audit = + reflection, stays gated). Absorb code-cleaner's PHASE 1 INLINE (session model): + - `# /code-clean — cleanup orchestrator (audit inline, execution dispatched)` + - STEP 1 LOAD PROJECT NORMS (CLAUDE.md > lang configs > community defaults). + - STEP 2 SCAN (A dead code / B style / C structural — verbatim from today's + code-cleaner PHASE 1 STEP 2, keep the TODO-age bash). + - STEP 3 BUILD REPORT (the `CODE-CLEAN AUDIT` block, severity levels). + - STEP 4 VALIDATION GATE (interactive, `AskUserQuestion`): present the report; + approve all / cherry-pick / clarify. Do NOT proceed until explicit approval. + Exported/public-API symbols flagged in the audit are resolved HERE, per-item + (this is where the today's guard-rail consent lives — the executor never asks). + - STEP 5 PERSIST SCOPE + DISPATCH: write the approved items to + `.claude/audits/CODE-CLEAN-SCOPE.md` (`mkdir -p .claude/audits` first), one + per line `file:line — item — severity — proposed fix`, then: + ``` + Agent(subagent_type="code-cleaner") + prompt: "SCOPE: .claude/audits/CODE-CLEAN-SCOPE.md + APPROVED: + BRANCH: + Execute PHASE 2 on the approved scope only. Zero behavior change. No commit. + Finish with the CODE-CLEAN-EXEC REPORT." + ``` + Parse `CODE-CLEAN-EXEC REPORT`: `DONE` → STEP 6; `BLOCKED` → surface + stop. + - STEP 6 SUMMARY: present the `CODE-CLEAN COMPLETE` block (removed / refactored + / skipped / bugs-found / tests) from the executor's report. No commit here + (code-clean has never auto-committed — leave the working tree for the user + or a follow-up `/commit-change`; keep today's behavior). + - RULES: zero behavior change; no scope creep; exported symbols need explicit + per-item consent AT THE GATE; bugs → BUGS-FOUND.md not fixed; no plugin + check (lightweight); systemic issues → suggest `/ship-feature`. + +- [ ] **Step 2: Rewrite `agents/code-cleaner.md` as the PHASE-2 executor.** Replace + the ENTIRE file with exactly: + +````markdown +--- +name: code-cleaner +description: Cleanup EXECUTOR (PHASE 2) — dispatched by /code-clean with an APPROVED scope. Deletes approved dead code, hands style/structural items to the refactorer, re-audits. Zero behavior change. No audit, no questions, no commit. +tools: Read, Edit, Write, Bash, Grep, Glob +model: sonnet +--- + +# CODE-CLEANER — cleanup executor (PHASE 2) + +You receive an APPROVED cleanup scope from the /code-clean orchestrator. The +audit and the user approval already happened; your job is faithful execution. +The iron law is unchanged: ZERO behavior change — identical observable output +before and after. + +## INPUT (in the dispatch prompt) + +- `SCOPE`: path to `.claude/audits/CODE-CLEAN-SCOPE.md` — the approved items + (`file:line — item — severity — proposed fix`), the on-disk contract. +- `APPROVED`: the item list the user confirmed (may be a subset of the audit), + including any exported/public-API symbols the gate explicitly cleared. +- `BRANCH`: verify with `git branch --show-current`; mismatch → STATUS + BLOCKED — never create or switch branches. + +## EXECUTION — in order + +### 1. Delete approved dead code (safest first) + +Remove approved unused imports / variables / functions, commented-out blocks, +stale TODO/FIXME. **Guard rail**: an exported / public-API symbol the +`APPROVED` list did NOT explicitly clear → do NOT delete; SKIP it and record +it under NOTES. The per-item exported-symbol consent lives in the +orchestrator's gate — you never ask. + +### 2. Style + structural fixes → INLINE-LOAD the refactorer + +Load `$HOME/.claude/agents/refactorer.md` and continue AS the refactorer in +THIS SAME context — you *become* it. This is an inline load, NOT a subagent +dispatch: the `Agent` tool is not involved and no new context is spawned. Its +scope = the style / structural items in `SCOPE`. Its own safety process runs +(pre-report, function-by-function, test after each) — zero behavior change. +Running inside this sonnet executor, the refactor finally runs on sonnet (the +refactorer pin was inert under the old inline-load on the session model). + +### 3. Log discovered bugs (do NOT fix) + +Real defects found during cleanup (not style issues) → append each to +`.claude/audits/BUGS-FOUND.md` (`mkdir -p .claude/audits` first): file:line, +description, severity, discovered-while. Cleanup and bugfixing are separate +concerns — never fix a bug here. + +### 4. Re-audit + +Re-scan only the modified files; verify no new issues were introduced; run the +project test suite + linter/formatter if available. + +## RULES + +- Zero behavior change. Unsure a deletion is safe → leave it, record under NOTES. +- No "while we're here" scope creep — only the APPROVED items. +- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies, user + questions (report instead), editing `.claude/**` or memory registries, + attribution trailers of any kind. + +## OUTPUT — end with exactly this report (your final message) + +``` +CODE-CLEAN-EXEC REPORT +STATUS : DONE | BLOCKED +REMOVED : +REFACTORED: +SKIPPED : +BUGS : +TESTS : +NOTES : +``` +```` + +- [ ] **Step 3: Verify + commit.** + `grep -c 'subagent_type="code-cleaner"' skills/code-clean/SKILL.md` → 1; + `grep -c 'model: sonnet' agents/code-cleaner.md` → 1; + `grep -c 'AskUserQuestion' agents/code-cleaner.md` → 0; + YAML check both files; `make test` green. + ```bash + git add skills/code-clean/SKILL.md agents/code-cleaner.md + git commit -m "feat(model-routing): /code-clean split — audit+gate inline, code-cleaner = sonnet PHASE-2 executor" + ``` + +--- + +### Task 18: wave-3 census + docs + memory + +**Files:** +- Modify: `lib/tests/model-routing.test.sh` (guarded — CONTROLLER applies) — wave-3 asserts +- Modify: `README.md`, `CHANGELOG.md`, `.claude/memory/decisions.md`, + `.claude/memory/journal.md`, `.claude/tasks/TODO.md` + +- [ ] **Step 1 (CONTROLLER — guarded): extend the census.** Sentinel first: + `printf 'model-routing plan: wave-3 executor-shape asserts (bugfix, code-clean)' > .claude/.config-edit-ok` + In `lib/tests/model-routing.test.sh`, add a `# 8) wave-3 — bugfix/code-clean + reflection-split executors` section: + `has skills/bugfix/SKILL.md 'subagent_type="bugfixer"'`; + `has agents/bugfixer.md 'model: sonnet'`; + `lacks agents/bugfixer.md 'AskUserQuestion'`; + `has skills/code-clean/SKILL.md 'subagent_type="code-cleaner"'`; + `has agents/code-cleaner.md 'model: sonnet'`; + `lacks agents/code-cleaner.md 'AskUserQuestion'`. + (bugfix + code-clean stay in the existing `# 1)` wired-gate loop — do NOT move + them.) Update the printed expected count. Flip-test one new assertion (LRN-096: + e.g. temporarily break the bugfixer dispatch string, confirm red, restore). + +- [ ] **Step 2: README + CHANGELOG.** In the BDR-066 agent-model table, MOVE + `bugfixer` and `code-cleaner` out of the "inherit session" row into the + executor/dispatched rows (bugfixer → sonnet executor; code-cleaner → sonnet + PHASE-2 executor). The "inherit session" row keeps analyzer + seo/geo/validator + analyzers (+ commit-changer stays wherever wave-2 placed it). CHANGELOG + Unreleased `### Changed`: add the wave-3 bullet (bugfix/code-clean split — + reflection inline, executors sonnet; refactor now runs on sonnet inside the + code-clean executor). + +- [ ] **Step 3: Capitalize.** Append a `**Wave 3**` bullet to the BDR-066 entry + in `.claude/memory/decisions.md`: bugfix + code-clean reflection-split + (executors sonnet); supersedes the BDR-050 "bugfix inline" carve-out (hotfix + went in wave 2, bugfix now); code-clean refactor finally on sonnet (inline-load + pin was inert). Note the accepted tradeoff (bugfix investigation↔fix coupling, + mitigated by DIAGNOSIS + verify loop). Journal line under 2026-07-15 + TODO + tick. + ```bash + git add lib/tests/model-routing.test.sh README.md CHANGELOG.md .claude/memory/decisions.md .claude/memory/journal.md .claude/tasks/TODO.md + git commit -m "chore(model-routing): wave-3 census + docs + BDR-066 update (bugfix/code-clean split)" + ``` + +- [ ] **Step 4: Final wave-3 review** — dispatch a whole-branch reviewer (opus) + over the wave-3 range; confirm: bugfix keeps root-cause-first + the pre-commit + gate + verify+secure loop with the executor as the loop's dev; code-clean keeps + the interactive validation gate + exported-symbol per-item consent at the gate + (not in the executor); zero execution left on the big model in either skill; + both executors have no `AskUserQuestion` and are `model: sonnet`. Report the + full `git log --oneline develop..HEAD`. Do NOT merge. + +--- + +# WAVE 4 — client-handover whole-writer dispatch (spec §5, user directive 2026-07-15) + +**Status: NOT YET SPEC'd — needs a dedicated design pass.** The user chose the +"dispatch the whole writer" variant of spec §5 (over the lighter redaction-only +split). This converts `agents/client-handover-writer.md` (1774 lines) from an +inline-loaded session-model agent into a dispatched sonnet subagent. It is the +single largest conversion in this effort and requires designing a resumable-gate +protocol before task decomposition. Key constraints already established: + +- The writer has ~8–11 mid-pipeline `AskUserQuestion` gates (STEP 4 fix-loop + escalation, STEP 5 push + push-failed, STEP 6 deploy pause + deployed-URL, + STEP 11 Q1/Q2, STEP 13 NAP asks, …). A dispatched subagent cannot ask. + Convert each to a `GATE NEEDED: ` yield: the writer STOPs and + returns it; the dispatcher (`skills/client-handover/SKILL.md`, main loop) + runs the `AskUserQuestion`; then RESUMES the writer via SendMessage with the + answer. Remove `AskUserQuestion` from the writer's tools. +- **CORRECTNESS (spec §5 OPEN VERIFY POINT — resolved: force big):** the + writer's nested audit dispatches (STEP 3 baseline SEO/HARDEN/CSO, STEP 4 fix + loops, STEP 7 web-validate — all `general-purpose`) MUST carry an explicit + big-model `model` param so audits do NOT inherit the sonnet parent. Running + audits on sonnet would silently violate the "audits on the big model" rule. + The fix-application re-dispatches (execution) stay sonnet. +- Dispatcher collects params inline (URL, logo, options), then + `Agent(subagent_type="client-handover-writer")`; writer keeps `Agent` (nested + dispatches) + gains no `AskUserQuestion`. +- Add the MODEL GATE to `skills/client-handover/SKILL.md` (it orchestrates + audits = reflection) and add it to the census wired list. +- Census + README/CHANGELOG + BDR-066 wave-4 bullet + journal + TODO. + +Tasks 19+ to be written after reading the writer's STEP 12–14 (doc synthesis + +render + remaining gates, lines 1123–1774) and mapping every gate to a yield id. diff --git a/docs/superpowers/specs/2026-07-15-model-routing-design.md b/docs/superpowers/specs/2026-07-15-model-routing-design.md new file mode 100644 index 0000000..e1b1419 --- /dev/null +++ b/docs/superpowers/specs/2026-07-15-model-routing-design.md @@ -0,0 +1,143 @@ +# Model routing — reflection inline (big model) / execution pinned (Sonnet) — design + +**Date**: 2026-07-15 · **Status**: approved (user, 2026-07-15) · **Branch**: `feature/model-routing` +**Lifecycle**: transient planning artifact (BDR-065) — committed during the run, deleted post-merge. + +## Principle + +The session model is assumed to be a big reasoning model (Fable 5, or Opus when +Fable is unavailable). Everything that **thinks** — brainstorming, planning, +technical decisions, audits, loop decisions — runs INLINE in the main +conversation, or in subagents that inherit the session model. Everything that +**executes** a ready-made plan — writing code, applying fix bundles, commits, +deliverable rendering — runs on Sonnet-pinned subagents. A blocking gate +enforces the "session = big model" assumption at the entry of every reflection +orchestrator. + +User verdicts baked in (2026-07-14/15): +- Scope = hybrid: ship-feature/init-project execution → sonnet; `/feat` + re-architected (plan inline → dispatch executor); bugfix/hotfix stay fully + inline (BDR-050 conserved for them). +- Gate = BLOCKING, not advisory. +- Audit agents inherit the session model (no opus pin); the gate extends to + audit orchestrators. +- verifier + security-auditor KEEP `model: sonnet` (job9 decision confirmed). +- client-handover-writer → sonnet (requires converting its inline-load to a + true dispatch; human gates relocate to the main loop). + +## 1. Blocking model gate + +New `lib/model-check.sh`: resolves the current session model from +`settings.json` (physical path resolution — LRN-023 class), normalizes +(`claude-fable-5[1m]` → fable, `claude-opus-*` → opus, sonnet, haiku), prints +`big|small|unknown`. Exit 0 = big, 2 = small, 3 = unknown. + +New `lib/model-gate.md` snippet (same include pattern as `lib/design-gate.md`): +run the check; `small` → STOP the skill: "session model is — reflection +requires Fable/Opus. Switch with /model, then relaunch." `unknown` → +fail-visible: show the raw value, ask the user to confirm or abort (BDR-025 +doctrine — unknown never silently passes). + +Wired as a STEP 0 line in the reflection orchestrators: +`ship-feature, init-project, feat, bugfix, onboard, seo, geo, web-validate, +harden, audit-delta, tour, code-clean`. +NOT wired in: `hotfix` (trivial by definition), `commit-change`, `doc`, +`status`, `release-candidate`. + +Caveats to prove at implementation time: +- `/model` mid-session rewrites settings.json (LRN-098 observed it once — + re-prove with a live flip-test before trusting the source). +- The helper itself must be flip-tested (LRN-096: an unproven guard is a + vacuous guard). + +## 2. Frontmatter pins (`agents/*.md`) + +| Agent | Before | After | Rationale | +|---|---|---|---| +| feater | (inherit) | **sonnet** | executor as subagent: seo/geo L1 applier + new /feat dispatch | +| hotfixer | (inherit) | **sonnet** | L1 applier (seo/geo/web-validate); /hotfix inline unaffected (pin inert on inline load) | +| client-handover-writer | opus | **sonnet** | deliverable executor; pin becomes EFFECTIVE only with §5 dispatch conversion (today's opus pin is inert — the agent is inline-loaded) | +| analyzer | haiku | **(none — inherit)** | analysis feeds the plan = reflection; runs big via the session model | +| verifier | sonnet | keep | F1 confirmed (job9) | +| security-auditor | sonnet | keep | F1 confirmed (job9) | +| seo-analyzer, geo-analyzer, validator-analyzer | (inherit) | keep (inherit) | audit = reflection = session model; covered by the gate | +| code-cleaner | (inherit) | keep (inherit) | audit phase = reflection; fixes hand off to refactorer (sonnet) via CODE-CLEAN-SCOPE.md (job9 H1) | +| doc-syncer, onboarder, scaffolder, refactorer, interviewer, plugin-advisor | sonnet | keep | workers/executors | +| status-reporter | haiku | keep | mechanical collector | +| bugfixer, commit-changer | (inherit) | keep | inline-only playbooks — a pin would be inert | + +## 3. `/feat` re-architecture (partial supersede of BDR-050 — feat only) + +`skills/feat/SKILL.md` absorbs the reflection: analyze-before-plan, design +gate, MINI-PLAN, contract (`lib/contract-interview.md`) — all inline. Then +dispatches `Agent(subagent_type="feater")` (sonnet via pin) with: the +contract, the plan, the branch name, repo conventions. + +`agents/feater.md` is rewritten as a pure executor: implement the plan to the +letter, run project checks, commit (no attribution trailers), return a +structured summary. No user interaction inside feater (subagents cannot ask) — +every decision must be closed pre-dispatch. + +The verify-secure loop moves out of feater.md into the /feat main loop +(LRN-083 invariant: loop decisions live in the main loop): fresh verifier → +ECARTS → re-dispatch feater with the verdict deltas, bounded 3×; then the +security gate. Escalation paths unchanged. + +## 4. SDD execution pinned (ship-feature STEP 4, init-project STEP 8) + +One instruction line in each SKILL.md: every implementation subagent +dispatched under `superpowers:subagent-driven-development` MUST carry +`model: "sonnet"` in the Agent call. No fork of the superpowers skill — the +main loop emits the Agent calls and controls the params. + +## 5. client-handover conversion (inline-load → true dispatch) + +`skills/client-handover/SKILL.md`: collect params inline (URL, logo, options), +then `Agent(subagent_type="client-handover-writer")` — the sonnet pin becomes +effective. Human gates (per-axis threshold escalation, overrides) RELOCATE to +the main loop: the writer returns a structured `GATE NEEDED` status instead of +asking; the dispatcher asks the user and re-dispatches (or continues via +SendMessage) with the decision. `AskUserQuestion` is removed from the writer's +tools. + +OPEN VERIFY POINT: the writer's own nested dispatches (seo/harden re-runs as +general-purpose subagents) — verify at implementation what nested children +inherit (session model vs parent model). If they inherit the sonnet parent, +the re-run audits violate the principle → force the model explicitly in those +nested dispatches or lift them to the main loop. + +## 6. web-validate fixes → L1 applier + +STEP 3 stops applying fixes via inline Edit; dispatches `hotfixer` (sonnet) +with the fix bundle — same pattern as seo/geo (BDR-061 alignment). + +## 7. Memory / doc / tests + +- New BDR: model-routing principle (reflection inline big / executors sonnet / + blocking gate); partial supersede of BDR-050 (feat only); records F1 + (verifier/security stay sonnet) and the analyzer haiku→inherit change. +- README: agent-model table refresh. CHANGELOG Unreleased entry. +- Tests: flip-tests for `model-check.sh` (fable[1m] / opus / sonnet / garbage + fixtures); gate STOP proven on a small-model fixture (LRN-096); /feat smoke + on a throwaway repo (LRN-079): plan inline → dispatch carries sonnet → + verify loop decided in main loop; grep census: no executor dispatch without + an effective pin. + +## Out of scope / accepted deviations + +- `/doc` and `/commit-change` stay inline on the session model (judgment and + execution interleaved; converting them buys little). Revisit under quota + pressure. +- bugfix/hotfix fully inline (BDR-050 conserved). +- No per-agent "fable-else-opus" fallback exists in the harness — the session + model IS the fallback mechanism; the gate is its backstop. + +## Risks + +- Model strings in settings.json may change shape with CC updates → + model-check must return `unknown` (fail-visible), never guess. +- feater as a subagent loses main-conversation context → the plan becomes the + contract; weak plans cost verify-loop iterations. Mitigation: + contract-interview stays mandatory in /feat. +- Nested model inheritance under client-handover-writer unknown → §5 verify + point. diff --git a/lib/model-check.sh b/lib/model-check.sh new file mode 100644 index 0000000..1cd3cf5 --- /dev/null +++ b/lib/model-check.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# lib/model-check.sh — classify the persisted session model: big | small | unknown +# +# Witness for lib/model-gate.md (reflection requires a big model). Reads the +# "model" key of the user-scope settings (the file /model rewrites — LRN-098). +# Override the source with MODEL_CHECK_SETTINGS (tests use fixtures). +# +# stdout : : (raw = value found, empty if none) +# exit : 0 = big (fable/opus) · 2 = small (sonnet/haiku) · 3 = unknown +set -u + +SETTINGS="${MODEL_CHECK_SETTINGS:-$HOME/.claude/settings.json}" + +raw="" +if [ -f "$SETTINGS" ]; then + raw="$(python3 - "$SETTINGS" 2>/dev/null <<'PY' +import json, sys +try: + v = json.load(open(sys.argv[1])).get("model", "") + print(v if isinstance(v, str) else "") +except Exception: + print("") +PY +)" +fi + +norm="$(printf '%s' "$raw" | tr '[:upper:]' '[:lower:]')" +case "$norm" in + *opusplan*) printf 'unknown:%s\n' "$raw"; exit 3 ;; # opus-for-plan, sonnet otherwise — ambiguous + *fable*|*opus*) printf 'big:%s\n' "$raw"; exit 0 ;; + *sonnet*|*haiku*) printf 'small:%s\n' "$raw"; exit 2 ;; + *) printf 'unknown:%s\n' "$raw"; exit 3 ;; +esac diff --git a/lib/model-gate.md b/lib/model-gate.md new file mode 100644 index 0000000..56b4b06 --- /dev/null +++ b/lib/model-gate.md @@ -0,0 +1,37 @@ +# Model gate — reflection requires a big model (BLOCKING) + +Shared include. Runs FIRST in any orchestrator whose reflection — +brainstorming, planning, contract, audit judgment, loop decisions — +executes inline or in inherit-model subagents. Sonnet-pinned executors are +not what this gate protects; it protects the thinking around them (BDR-066). + +## 1. Self-check + +Your system prompt names the model powering this session. Fable or Opus → +big. Sonnet, Haiku, anything else → small. + +## 2. Witness — deterministic check + + bash "$HOME/.claude/lib/model-check.sh" + +Output `:`; exit 0 = big, 2 = small, 3 = unknown. The witness +reads the PERSISTED model (settings.json — the file `/model` rewrites, +LRN-098). It can lag reality (session launched with `--model`, settings not +yet rewritten) — that is why the self-check exists alongside it. + +## 3. Verdict + +| self-check | witness | action | +|---|---|---| +| big | big (0) | proceed, SILENT — the nominal path prints nothing | +| small | any | **STOP** | +| big | small (2) | disagreement — **STOP**, surface BOTH values; the user confirms or relaunches | +| big | unknown (3) | fail-visible: print `model gate: witness unknown () — self-check says ` and ask the user to confirm before continuing (BDR-025: unknown never silently passes) | + +**STOP means**: print exactly + + ⛔ MODEL GATE — session on . Reflection steps of this skill + require Fable or Opus. Switch with /model, then relaunch the skill. + +then end the turn. No later step runs, no agent is dispatched, nothing is +edited. diff --git a/lib/tests/loops-light.test.sh b/lib/tests/loops-light.test.sh index 0e95826..61e0de4 100644 --- a/lib/tests/loops-light.test.sh +++ b/lib/tests/loops-light.test.sh @@ -9,10 +9,12 @@ set -u REPO="$(cd "$(dirname "$0")/../.." && pwd)" INC="$REPO/lib/verify-secure-loop.md" -FEA="$REPO/agents/feater.md" +FSK="$REPO/skills/feat/SKILL.md" BUG="$REPO/agents/bugfixer.md" +BSK="$REPO/skills/bugfix/SKILL.md" HOT="$REPO/agents/hotfixer.md" HSK="$REPO/skills/hotfix/SKILL.md" +HSKL="$REPO/skills/hotfix/SKILL.md" PASS=0; FAIL=0 tf() { # tf