Compare commits
67
Commits
23c8c290d7
...
v1.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d8962824c0 | ||
|
|
817a866b7c | ||
|
|
2940134c86 | ||
|
|
78a25aeb5e | ||
|
|
9b89da29be | ||
|
|
95ddd28992 | ||
|
|
1ef6e6e694 | ||
|
|
6c489ebcfb | ||
|
|
33f9529b9e | ||
|
|
648bc6e90d | ||
|
|
f82ea1e4f8 | ||
|
|
75c81f3f9c | ||
|
|
533fcc841e | ||
|
|
db6f476685 | ||
|
|
90850096ef | ||
|
|
1cb77c3f57 | ||
|
|
0a8ecf6c34 | ||
|
|
711eacd900 | ||
|
|
ce5b7fb3f4 | ||
|
|
10589d484b | ||
|
|
dc90aae9bd | ||
|
|
37c79f0524 | ||
|
|
e75ea79ae6 | ||
|
|
655e364e80 | ||
|
|
ecbe8abde7 | ||
|
|
8008d8233c | ||
|
|
3c243ece97 | ||
|
|
3166c1161e | ||
|
|
e5a62cc049 | ||
|
|
b3a03fd974 | ||
|
|
aeb7bc05d8 | ||
|
|
45e679ac23 | ||
|
|
51b65727e7 | ||
|
|
2d38ffd843 | ||
|
|
56571805a1 | ||
|
|
8ee7d19d70 | ||
|
|
b7026e4bda | ||
|
|
6838d5a8fa | ||
|
|
444c79acb2 | ||
|
|
07253e093c | ||
|
|
6c59a424ae | ||
|
|
9e4ebb4cf4 | ||
|
|
6886622ecf | ||
|
|
d2a10de08b | ||
|
|
d3d5e3802c | ||
|
|
5e8bb0c22e | ||
|
|
e4d2629c88 | ||
|
|
18075a38db | ||
|
|
74528a6910 | ||
|
|
896d3faaf9 | ||
|
|
3f7c754239 | ||
|
|
1c2d30dbf0 | ||
|
|
17fbe51aa1 | ||
|
|
3eaf31ca09 | ||
|
|
354ff2644f | ||
|
|
9bc6ab7e07 | ||
|
|
727a41ad71 | ||
|
|
311ea14789 | ||
|
|
a68f26ca9c | ||
|
|
d5d1584c1c | ||
|
|
2aa95636ee | ||
|
|
6bfc0543e5 | ||
|
|
0e1b89c71a | ||
|
|
2f8dc6be1a | ||
|
|
dc4f78b1f0 | ||
|
|
709facfb52 | ||
|
|
d3d72fd3ca |
@@ -208,3 +208,10 @@ rules:
|
|||||||
- **Real cause**: two viable-looking paths, both dead. (API KEY) is per-user not per-site (docs), but IS the account identity → one key per client account, exactly what the user feared; non-scoped, no expiry, passed in query string. (OAuth) is the right delegation model (like GSC) but a swamp: Redirect URI rejects ALL local forms (http/https/127.0.0.1 — user-tested); refresh tokens are ROTATED + single-use, self-described non-compliant with OAuth 2.0 → store rewrite every call, AND our parallel seo‖geo dispatch would race the rotation → `invalid_grant` + dead token; undocumented "Could not extract expected anti-forgery token" on refresh, unanswered on MS Q&A; docs contradict themselves on grant_type + token endpoint; no library. MS's own advisor recommends falling back to the API key.
|
- **Real cause**: two viable-looking paths, both dead. (API KEY) is per-user not per-site (docs), but IS the account identity → one key per client account, exactly what the user feared; non-scoped, no expiry, passed in query string. (OAuth) is the right delegation model (like GSC) but a swamp: Redirect URI rejects ALL local forms (http/https/127.0.0.1 — user-tested); refresh tokens are ROTATED + single-use, self-described non-compliant with OAuth 2.0 → store rewrite every call, AND our parallel seo‖geo dispatch would race the rotation → `invalid_grant` + dead token; undocumented "Could not extract expected anti-forgery token" on refresh, unanswered on MS Q&A; docs contradict themselves on grant_type + token endpoint; no library. MS's own advisor recommends falling back to the API key.
|
||||||
- **Verified live**: the Webmaster API itself is ALIVE (`GetUserSites?apikey=INVALID` → HTTP 400 `{"ErrorCode":3,"Message":"InvalidApiKey"}`, 0.4s) — distinct from Bing SEARCH API (retired 2025-08-11). So the block is auth/model, not availability.
|
- **Verified live**: the Webmaster API itself is ALIVE (`GetUserSites?apikey=INVALID` → HTTP 400 `{"ErrorCode":3,"Message":"InvalidApiKey"}`, 0.4s) — distinct from Bing SEARCH API (retired 2025-08-11). So the block is auth/model, not availability.
|
||||||
- **Status**: open/deferred. REVIVAL: a client already on Bing adds the user as Read-Only → test in ~10 min whether one API key sees DELEGATED sites (undocumented, nobody knows). If yes → W2 is cheap+clean (one key, client-owned verification, revocable, read-only, zero OAuth). Value RAISED by [[BDR-071]]: GetUrlLinks is now the only free viable backlink source (first-party only).
|
- **Status**: open/deferred. REVIVAL: a client already on Bing adds the user as Read-Only → test in ~10 min whether one API key sees DELEGATED sites (undocumented, nobody knows). If yes → W2 is cheap+clean (one key, client-owned verification, revocable, read-only, zero OAuth). Value RAISED by [[BDR-071]]: GetUrlLinks is now the only free viable backlink source (first-party only).
|
||||||
|
|
||||||
|
## BLK-018 — release-executor finish span blocked by permission classifier (human signal invisible to subagent) — 2026-07-20
|
||||||
|
- **Friction**: v1.3.1 release — `SPAN: finish` dispatch denied at tool-permission layer: classifier flagged "Merge Without Review" (`gitflow.sh finish` in subagent transcript carries no explicit human merge signal). Executor correctly refused workaround, reported BLOCKED. v1.2.0/v1.3.0 same span passed → classifier behavior change, not skill regression.
|
||||||
|
- **Real cause**: gitflow doctrine "finish only on explicit human signal" lives in DISPATCHER transcript (user ask + STEP 4 AskUserQuestion go); subagent transcript starts fresh → classifier sees consequential merge with zero authorization evidence. Structural: any human-gated action dispatched to a subagent loses its gate evidence.
|
||||||
|
- **Solution** (workaround): dispatcher ran `gitflow.sh finish` + tag inline after its own human gate — where the signal is real. Release completed clean (main `648bc6e`, tag v1.3.1).
|
||||||
|
- **Status**: open. Candidate fixes: (a) quote gate evidence verbatim in span prompt — untested vs classifier; (b) move finish+tag span permanently inline in /release-candidate — keeps prep span dispatched, costs the sonnet pin on ~5 mechanical commands, cheap; (c) permission rule allowing subagent `gitflow.sh finish` — weakens the guard, refused. Decide at next release.
|
||||||
|
- **Reference**: skill `release-candidate` STEP 5. Pattern adjacent [[LRN-089]] (ambient-state/context assumptions across boundaries). Journal 2026-07-20.
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ rules:
|
|||||||
| BDR-071 | 2026-07-17 | No viable free backlink source → Off-page axis stays brand-mentions-only (FINAL, not placeholder) | accepted |
|
| BDR-071 | 2026-07-17 | No viable free backlink source → Off-page axis stays brand-mentions-only (FINAL, not placeholder) | accepted |
|
||||||
| BDR-072 | 2026-07-17 | SPA: honest refuse (On-page N/A, not zero), no headless browser (R2 over R1) | accepted |
|
| BDR-072 | 2026-07-17 | SPA: honest refuse (On-page N/A, not zero), no headless browser (R2 over R1) | accepted |
|
||||||
| BDR-073 | 2026-07-17 | Scoring: LLM judges findings+severity, engine does the arithmetic (deterministic /20) | accepted |
|
| BDR-073 | 2026-07-17 | Scoring: LLM judges findings+severity, engine does the arithmetic (deterministic /20) | accepted |
|
||||||
|
| BDR-080 | 2026-07-21 | Bug routing inverted: /bugfix primary, /investigate explicit-only | accepted |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -980,6 +981,7 @@ 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.
|
- **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.
|
- **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]].
|
- **Reference**: project CLAUDE.md; cleanup commit this chore; precedent 8a1fac0. Linked [[BDR-064]], [[LRN-124]].
|
||||||
|
- **Amendment (2026-07-22)**: DELETE side now AUTOMATED — `lib/gitflow.sh` `_gitflow_purge_transient` at `gitflow finish` (feature/bugfix, pre-merge, on HEAD) git-rm's `docs/superpowers/{specs,plans}` + scoped commit → develop TIP clean, feature commits stay reachable (`git show <sha>:…` archive intact). Best-effort: NEVER aborts finish (nothing-tracked no-op / dirty-path skip / commit-fail index+tree restore). Opt-out `GITFLOW_PURGE_TRANSIENT=0`. Retires the manual chore that slipped (655e364). Universal via `~/.claude/lib`→repo symlink (ship-feature STEP 9 + init-project STEP 11 both finish through it). gitignore STILL rejected — unchanged: breaks superpowers' `git add` of the spec (silently skipped, no travel to SDD worktree). `.claude/tasks/{contracts,plans}` kept versioned (user call — durable, referenced by decisions.md). Tests: gitflow-test.sh T17 a-d. [[LRN-138]].
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -1046,3 +1048,28 @@ rules:
|
|||||||
- **Why**: /harden had a real scale (SKILL.md:435), /seo had NONE → every axis felt → two runs over identical code diverged, while /client-handover gates on 17/20. H2 sharpened it: once drift reports real change, a self-moving score is visibly noise. Same principle as engine-side cannibalisation grouping — never hand a model 1000 rows to add.
|
- **Why**: /harden had a real scale (SKILL.md:435), /seo had NONE → every axis felt → two runs over identical code diverged, while /client-handover gates on 17/20. H2 sharpened it: once drift reports real change, a self-moving score is visibly noise. Same principle as engine-side cannibalisation grouping — never hand a model 1000 rows to add.
|
||||||
- **Makes computable (was prose)**: "N/A is not a zero" (R2 on-page, I1 off-page) → axis excluded + weights renormalised, verified all-20 with 2 N/A → global 20.0. Prevalence: affected/sampled shift severity ONE step (≥50% escalate, single de-escalate).
|
- **Makes computable (was prose)**: "N/A is not a zero" (R2 on-page, I1 off-page) → axis excluded + weights renormalised, verified all-20 with 2 N/A → global 20.0. Prevalence: affected/sampled shift severity ONE step (≥50% escalate, single de-escalate).
|
||||||
- **Files**: lib/seo-data/score.py (4818c61).
|
- **Files**: lib/seo-data/score.py (4818c61).
|
||||||
|
|
||||||
|
### BDR-074 — Remove config-protection edit-block guardrail [accepted] (2026-07-17)
|
||||||
|
Deleted hooks/config-protection.sh + its settings.json PreToolUse registration + lib/tests/config-protection.test.sh. Hook blocked model Edit/Write on quality-gate files (settings.json, gitflow.sh, .githooks, doctor.sh, hooks, lib/tests, lint) via one-shot .claude/.config-edit-ok sentinel. Removed per user req — friction editing own config > guardrail value; user = human operator. Residual: gitflow pre-commit guard + Gitea branch protection still block direct code commits main/develop; only edit-time block gone. Alts rejected: warn-only (exit0+log), targeted relaxation. Supersedes any prior config-protection decision.
|
||||||
|
|
||||||
|
### BDR-075 — Framework-wide 3-way adversarial plan-challenge phase [accepted] (2026-07-17)
|
||||||
|
After a plan/reflection elaborated + before execution, 3 fresh blind sub-agents (correctness/robustness/simplicity) attack it; main loop RE-THINKS every aspect a BLOCKER lands (named change or [deferred]) + re-challenges once if plan materially changed. Reusable lib/challenge-plan.md + new agents/plan-challenger.md (read-only, big-model per [[BDR-066]] — audit judgment, NOT sonnet). Fail-safe (never fail open: mute→retry→escalate), severity-driven (any single-lens BLOCKER=must-address, NOT consensus — lenses orthogonal), advisory into existing human gate. KIND tunes lenses: build-plan/proposals/fix-bundle. Wired 11 orchestrators: ship-feature/init-project/feat/bugfix + onboard/audit-delta/code-clean + seo/geo/harden/web-validate. Excluded (no real plan): hotfix/tour/analyze/client-handover/release-candidate/spec. Audit found 0 repo-owned plan-challengers pre-existing (only vendored gstack autoplan, sequential+unwired). See [[EVAL-026]].
|
||||||
|
|
||||||
|
### BDR-075 amendment (2026-07-18) — hotfix INCLUDED via logic-only guard
|
||||||
|
Supersedes the "Excluded: hotfix" clause of [[BDR-075]]. hotfix now wired (STEP 1.8, Option B): GUARD skips purely cosmetic fixes (CSS/copy/typo), fires the 3-lens challenge ONLY when the fix touches control flow/behaviour (off-by-one, wrong operator, behaviour-changing config, execution-altering import); a BLOCKER → escalate to /bugfix (its STEP 3b runs the full phase). 12 orchestrators wired. Still excluded (no forward plan): tour/analyze/client-handover/release-candidate/spec. Per user (Option B). Branch feature/hotfix-challenge-guard, unmerged.
|
||||||
|
|
||||||
|
### BDR-076 — Dispatched judgment agents pinned OPUS; session model = orchestration + inline reflection ONLY [accepted] (2026-07-19)
|
||||||
|
Reverses the BDR-066 rejected alternative "opus pins on audit agents (session-independent)". Context changed: session default now Fable (Mythos tier, /model 2026-07-19) — inherit meant every dispatched audit/challenge burned Fable quota, exactly the waste BDR-066 killed for executors. New rule: Fable does ONLY main-loop orchestration + reflection (brainstorm, plan, contract, synthesis, gates); EVERY dispatched subagent pinned. Pinned `model: opus` (big tier, session-independent; NEVER sonnet — silent audit downgrade, the thing old §F5 guarded): analyzer, plan-challenger, seo-analyzer, geo-analyzer, validator-analyzer + onboard's 6 general-purpose audit dispatches (`model="opus"`) + tour Phase B. NOT pinned (justified deviation from approved "7 agents"): interviewer + client-handover-writer — inline-load only, never dispatched → frontmatter pin inert + misleading (BDR-066 wave-4 precedent: its inert opus pin was dropped); they ARE the main loop = Fable per the rule. Explore built-in stays inherit (wave-3 decision conserved: no owned prompt, search feeds inline reflection). Local session pin `opus-4-8[1m]` dropped from `.claude/settings.local.json` (gitignored) — Fable default from settings.json now applies in this repo too. model-gate.md unchanged (still guards inline reflection, Fable-or-Opus = big). Census: model-routing.test.sh §3 flip + §11 (61 pass), loops-light 35 pass, full `make test` green. User directives via gate: "Opus partout" + "Supprimer le pin". Branch feature/opus-pin-audit-agents, unmerged.
|
||||||
|
|
||||||
|
### BDR-077 — Model-tiering v2: 4-tier explicit routing, mode-based splits, no-inherit dispatches [accepted] (2026-07-19)
|
||||||
|
Supersedes BDR-076 scope + amends BDR-066. Doctrine: session model (Fable) = main-loop reflection/orchestration/planning/logic ONLY; main-loop retention criteria = interactive | conversation-context access | orchestration decision | dispatch overhead > step cost. NOTHING dispatched inherits: typed agents = frontmatter pin, built-ins = `model=` at every call site (`fable` for skill-runner reflection children, else complexity tier). Spike+smoke proven: `model:"fable"` resolves claude-fable-5 (enum-validated, loud fail, no silent fallback); call-site override BEATS a typed pin (sonnet-pinned verifier ran haiku). Fail-safe pin rule: mixed-mode agents keep the HIGH tier as pin, overrides go DOWN — forgotten override over-tiers (cost), never downgrades judgment. Mode-based splits (commit-changer precedent generalized; file splits rejected): doc-syncer audit(opus)/patch(sonnet) — ALSO fixed a latent defect: /doc dispatched an agent whose STEP 8 interactive gate could never fire; gates hoisted to a DISPATCHER PROTOCOL section; handover-doc-writer synthesize(opus)/render(sonnet) via run-scoped `.audit/handover-draft-<RUNID>.md` + DRAFT COMPLETE sentinel; seo/geo collect(sonnet)/judge(OPUS PIN)/template(sonnet) via `.audit/*-signals-<RUNID>.md` + COLLECTION COMPLETE + fail-closed judge + dispatcher ERROR contract (mute/ERROR judge NEVER carried into templating; retry once, escalate). File split only for a genuinely new role: plugin-probe (sonnet, facts-only) + plugin-advisor repinned opus reasoner (fail-closed on missing PROBE REPORT) + lib/plugin-gate.md (checkpoint + apply gate, doc-commit ×N include pattern). Inline→dispatch conversions: scaffolder, onboarder, doc-commit steps ×5 flows — their sonnet pins were INERT since creation, now live; CHANGE SUMMARY crosses the doc dispatch into doc-commit (LRN-126 wire). Tier moves: validator-analyzer opus→sonnet (deterministic runner); commit-changer propose=opus/apply=pin; ship-feature/init-project code-review dispatches = opus explicit (WAS an inherit leak); client-handover-writer's 7 skill-runners = model:"fable". Every wave shipped an IN-WAVE planted-input smoke as its merge gate — all PASSED disk-verified. Census §12-18 (125 pass; one vacuous line-wrapped lock self-caught = LRN-093 live). 6 waves, branches feature/model-tiering-w1..w6, merged on user standing signal. Plan: challenged 3 blind lenses + 1 confirmation (1 BLOCKER closed by spike, 8 MAJORs + 8 MINORs closed by named changes, 0 deferred). Refs: `.claude/tasks/plans/2026-07-19-model-tiering-v2-{analysis,plan}.md`.
|
||||||
|
|
||||||
|
### BDR-078 — ctx7 coverage: central fast-libs list + once-per-session reminder hook; every code path covered [accepted] (2026-07-20)
|
||||||
|
Refines BDR-053 (single surface). Audit 2026-07-20: coverage PARTIAL — find-docs fired on user doc-questions only; ship-feature 0c / init-project 5c pre-fetched; /feat //bugfix executors + ad-hoc coding NEVER consulted ctx7; fast-libs list hardcoded 3× (drift risk). 4 closures shipped: (a) find-docs description += BEFORE-writing-code trigger (fast-moving lib, even without doc question, unless fresh cache) + cache-first rule in body (tee fetched docs to .ctx7-cache/); (b) feater+bugfixer briefs += fast-lib docs rule — read fresh `.ctx7-cache/<lib>*.md`, else `npx ctx7@latest` fetch max 2 topics, else `ctx7 cache miss: <lib>` in NOTES + proceed (executors lack Skill tool → Bash path); (c) hooks/ctx7-reminder.sh UserPromptSubmit — ONE fire/session (sentinel on session_id), only when project manifest carries fast-libs; reports cache state; skips <task-notification> turns; always exit 0; (d) lib/fast-libs.sh = SINGLE SOURCE (detect / cache-status verbs, JS package.json anchored full-key match + Python requirements/pyproject, 7-day freshness, LC_ALL=C sort locale-independent) consumed by hook + 3 pipeline skills + 2 briefs. 2nd session surface DELIBERATE, not a BDR-053 reversal: 053 killed a 490-tok ALWAYS-ON rule duplicate; hook costs ~0 quiet, 1 line once when fast-libs present. Alternatives rejected: PreToolUse Edit/Write gate (fires per-edit = noise); description-only fix (probabilistic, executors unreachable). Tests: lib/tests/fast-libs.test.sh 11 checks (anchored/near-miss/py/none, cache fresh/stale/missing, hook fire/sentinel/quiet×2); shellcheck + full make test green. Branch feature/ctx7-coverage, unmerged (human gate).
|
||||||
|
Amendment (same session): skills/find-docs = machine-owned dist (gitignored, ctx7 regenerates on fresh clone) → durable copy of closure (a) lives in install-plugins.sh STEP ctx7 (idempotent grep-guarded python patch, fixture-verified); live SKILL.md carries the same edit uncommitted by design.
|
||||||
|
|
||||||
|
### BDR-079 — profile `set` symmetric on managed externals + MCPs [accepted] (2026-07-20)
|
||||||
|
Audit (user ask "profile toggles externals both ways?"): ASYMMETRIC. Enable side OK — gstack on-demand from submodule when pack off (shared `skills-disabled/gstack__*` convention with toggle-external.sh, interoperable), externals restored from parked, magic delegated to toggle-external. Disable side MISSING: `cmd_set` trimmed only gstack + MANAGED_PLUGINS → `set backend` left emil/frontend-design/design-motion/impeccable active + magic registered; SKILL.md claimed both-ways toggle (true only at enable). Shipped: (1) `MANAGED_EXTERNALS` (emil-design-eng, frontend-design, design-motion-principles, impeccable = exact union of profile `external` usage; darwin-skill excluded — not task-type-driven) + `MANAGED_MCPS` (magic) allowlists, same doctrine as MANAGED_PLUGINS; (2) cmd_set refactored to 4 trim helpers (`disable_{gstack,plugins,externals,mcps}_not_in`) — symmetric, nothing outside allowlists ever auto-touched; (3) enable_skill external += from-source fallback (`ln -sf skills-external/<name>`, mirrors toggle-external) — closes the "missing symlink" warn; (4) stale usage() NOTE ("NOT toggled automatically") + SKILL.md fixed. Hermetic test profile-set-managed.test.sh 16 checks: fixture repo (both *_REPO_OVERRIDE), fake `claude` shim on PATH logging calls + flat-file MCP registry — gstack on-demand, external from-source, park/restore round-trip, magic add/remove calls, non-managed untouched. shellcheck + make test green. Branch feature/profile-managed-externals, unmerged (human gate).
|
||||||
|
|
||||||
|
### BDR-080 — bug routing inverted: /bugfix primary, /investigate explicit-only [accepted] (2026-07-21)
|
||||||
|
Old routing "Bug → investigate (bugfix if gstack off)" + gstack ON by default → every bug took path bypassing own quality pipeline (gitflow aiguillage, contract, fresh verifier + security gates, doc-sync, `.claude/memory` registries) — /bugfix relegated to near-never fallback. Skill comparison: same core doctrine (root-cause iron law, hypothesis loop, regression test, 3-strike stop, >5-files alert) but incompatible wrappers — investigate monolithic (same context investigates+fixes+verifies, ~1075-line SKILL.md w/ gstack preamble/telemetry/onboarding, capitalizes to `~/.gstack` learnings.jsonl framework never reads at session start); bugfix orchestrator (reflection inline, sonnet bugfixer executor, fresh gates — BDR-066, LRN-083). Composition rejected: skills superpose in context, don't compose — invoking investigate inside bugfix = two full workflows, two completion protocols, two memory systems loaded at once. Decision: CLAUDE.global.md routing line inverted — bugfix primary; investigate ONLY on explicit ask for gstack ecosystem (cross-project learnings, /freeze scope lock, long no-commit investigation). Alternatives rejected: keep investigate primary (bypasses framework), embed investigate inside bugfix (context conflict, dual memory). Known drift noted at write time: Index table rows BDR-074..079 missing (pre-existing, /prune-memory scope).
|
||||||
|
|||||||
@@ -248,3 +248,6 @@ rules:
|
|||||||
- **method**: each verifiable claim confronted DURING execution with a primary source or a live test — CrUX API metric list, web.dev, Search Console API reference, HEAD on data.commoncrawl.org, real curl on 2 live sites (zenquality Astro, lavageangels356 native PHP), 2 real repos.
|
- **method**: each verifiable claim confronted DURING execution with a primary source or a live test — CrUX API metric list, web.dev, Search Console API reference, HEAD on data.commoncrawl.org, real curl on 2 live sites (zenquality Astro, lavageangels356 native PHP), 2 real repos.
|
||||||
- **anomalies**: 7/7 of the verifiable claims were false or overstated (VSI exists / Off-page zero-data / stats drive weights / GSC Links API / SPA §0 flag / Twitter 403 / Common Crawl viable). 6 plan corrections mid-execution: I1 over-correction, I6 wrong framing, W1 wrong shape (verb vs extend), C1a false premise (grep already skips gitignore), C1b needless guard, B1 non-viable at 17.3 GB. The REAL corrected every time; re-reading the spec never did.
|
- **anomalies**: 7/7 of the verifiable claims were false or overstated (VSI exists / Off-page zero-data / stats drive weights / GSC Links API / SPA §0 flag / Twitter 403 / Common Crawl viable). 6 plan corrections mid-execution: I1 over-correction, I6 wrong framing, W1 wrong shape (verb vs extend), C1a false premise (grep already skips gitignore), C1b needless guard, B1 non-viable at 17.3 GB. The REAL corrected every time; re-reading the spec never did.
|
||||||
- **action**: keep — see [[LRN-132]]. 4 features killed at measurement (B1/B2/B3 + W2 deferred) beat 4 false-signal features. The most trustworthy output of the session was the code NOT written. Method that worked: show/measure the real artifact before deciding, mirroring [[LRN-074]]'s watch-the-RED discipline applied to a plan.
|
- **action**: keep — see [[LRN-132]]. 4 features killed at measurement (B1/B2/B3 + W2 deferred) beat 4 false-signal features. The most trustworthy output of the session was the code NOT written. Method that worked: show/measure the real artifact before deciding, mirroring [[LRN-074]]'s watch-the-RED discipline applied to a plan.
|
||||||
|
|
||||||
|
### EVAL-026 — 3-way plan challenge caught 4 BLOCKERs dogfooding own plan (2026-07-17)
|
||||||
|
Dogfood: 3 blind lenses attacked the v1 plan for the plan-challenge feature itself. Verdicts CONCERNS(4)/FATAL(6)/FATAL(4). Caught 4 distinct BLOCKERs a single pass would blend: (1) v1 unbuildable — targeted init-project (inline-load, no dispatch) + false "plan on disk" premise for feat/bugfix (only contract persists); (2) failed-open silently dropping a lens while claiming "challenged" (inverts verify-secure-loop "a mute verifier is NEVER a PASS"); (3) consensus-weighting buries lone L2 security finding (lenses orthogonal); (4) sonnet challengers violate [[BDR-066]] (audit judgment=big model). Synthesis REJECTED 1 false positive (allowed-tools-blocks-dispatch — ship-feature has same frontmatter + dispatches fine). Each lens found a DIFFERENT class of flaw → evidence 3-independent > 1-multilens. Action: hardened v2 (severity-driven + fail-safe + re-think loop) shipped. Method validated itself before build.
|
||||||
|
|||||||
@@ -402,3 +402,28 @@ rules:
|
|||||||
- seo/geo parity vs github.com/AgriciDaniel/claude-seo (11.5k★, MIT): full 20-point plan built from a 3-subagent inventory, then executed. Verdict cherry-pick-never-install ([[BDR-070]]). 21 commits: Phase 1 (I1-I8 integrity, markdown specs) MERGED to develop (02c7a6f, 8 commits); Phases 2-7 on bugfix/seo-geo-integrity UNMERGED (13 commits, human gate). `fetch.sh` 5→11 verbs (richresults via inspect, sitemap, rendercheck, linkgraph, cannibal, drift, score); seo-data test suite 85→167 pass, 0 fail. Dogfooded on 2 live sites (zenquality Astro + lavageangels356 native PHP) — the second caught 2 bugs Astro hid (image:loc counted as page, flat-URL family heuristic).
|
- seo/geo parity vs github.com/AgriciDaniel/claude-seo (11.5k★, MIT): full 20-point plan built from a 3-subagent inventory, then executed. Verdict cherry-pick-never-install ([[BDR-070]]). 21 commits: Phase 1 (I1-I8 integrity, markdown specs) MERGED to develop (02c7a6f, 8 commits); Phases 2-7 on bugfix/seo-geo-integrity UNMERGED (13 commits, human gate). `fetch.sh` 5→11 verbs (richresults via inspect, sitemap, rendercheck, linkgraph, cannibal, drift, score); seo-data test suite 85→167 pass, 0 fail. Dogfooded on 2 live sites (zenquality Astro + lavageangels356 native PHP) — the second caught 2 bugs Astro hid (image:loc counted as page, flat-URL family heuristic).
|
||||||
- 4 features KILLED at measurement, not built: B1/B2 (Common Crawl edges = 17.3 GB, ref impl reads 2.9% and calls it a profile — [[BDR-071]]), B3 (GSC Links API doesn't exist), W2 (Bing OAuth swamp — [[BLK-017]]). 30/70 similarity refused (needs content extraction), Playwright refused (R2 [[BDR-072]]), defusedxml refused (DTD-reject keeps stdlib-only). The most trustworthy output was the code NOT written ([[EVAL-025]]).
|
- 4 features KILLED at measurement, not built: B1/B2 (Common Crawl edges = 17.3 GB, ref impl reads 2.9% and calls it a profile — [[BDR-071]]), B3 (GSC Links API doesn't exist), W2 (Bing OAuth swamp — [[BLK-017]]). 30/70 similarity refused (needs content extraction), Playwright refused (R2 [[BDR-072]]), defusedxml refused (DTD-reject keeps stdlib-only). The most trustworthy output was the code NOT written ([[EVAL-025]]).
|
||||||
- BDR-070/071/072/073 + LRN-131/132/133 + BLK-017 + EVAL-025 capitalized; checked 14 TODO done (I1-I5,W1,W3,C1-C3,B3,R2,H1,H2), W2+R1 left unchecked (deferred/rejected). 2 learnings dropped as dup of [[LRN-074]] (grep/find gitignore + detector-proof). Red thread [[LRN-133]]: an omission must stay legible. Verification discipline [[LRN-131]]/[[LRN-132]]: WebSearch ≠ verification, subagent summary = claim not fact (7 disproven, 3 self-reproduced).
|
- BDR-070/071/072/073 + LRN-131/132/133 + BLK-017 + EVAL-025 capitalized; checked 14 TODO done (I1-I5,W1,W3,C1-C3,B3,R2,H1,H2), W2+R1 left unchecked (deferred/rejected). 2 learnings dropped as dup of [[LRN-074]] (grep/find gitignore + detector-proof). Red thread [[LRN-133]]: an omission must stay legible. Verification discipline [[LRN-131]]/[[LRN-132]]: WebSearch ≠ verification, subagent summary = claim not fact (7 disproven, 3 self-reproduced).
|
||||||
|
- Removed config-protection edit-block guardrail (full removal, user req) → feature/drop-config-protection (0e1b89c). Residual gitflow+Gitea guards only. [[BDR-074]] [[LRN-136]].
|
||||||
|
- Built framework-wide 3-way plan-challenge phase → feature/plan-challenge-phase (6bfc054): lib/challenge-plan.md + agents/plan-challenger.md + 41-assertion lock, wired into 11 reflection orchestrators (build-plan/proposals/fix-bundle), excluded 6 no-plan skills. Full suite 16/16. [[BDR-075]].
|
||||||
|
- Dogfooded the challenge on its own v1 plan: 3 blind lenses caught 4 BLOCKERs + rejected 1 false positive → hardened v2 shipped [[EVAL-026]]. Both branches finished into develop on user signal, NOT pushed.
|
||||||
|
|
||||||
|
## 2026-07-18
|
||||||
|
- hotfix wired into plan-challenge via Option B (STEP 1.8 logic-only guard): skip cosmetic, fire on logic, BLOCKER→/bugfix. 12th orchestrator. structure lock 43/43, suite 15/15. [[BDR-075]] hotfix-exclusion superseded (see amendment). feature/hotfix-challenge-guard, UNMERGED (user: commit only).
|
||||||
|
- Behavioral smoke of the shipped mechanism: 3 blind plan-challenger dispatches on a planted-flaw plan → correctness FATAL(4), robustness FATAL(6), simplicity CONCERNS(1). Each lens caught ITS planted flaw + stayed in-lens. Live-validated severity-driven (SQL-injection BLOCKER raised by robustness ALONE — consensus-weighting would've buried it) + orthogonality. Confirms [[EVAL-026]]/[[BDR-075]] design.
|
||||||
|
|
||||||
|
## 2026-07-19
|
||||||
|
- BDR-076: dispatched judgment agents pinned opus (analyzer, plan-challenger, seo/geo/validator-analyzer + 6 onboard general-purpose dispatches); Fable now = inline orchestration/reflection only. interviewer + client-handover-writer left unpinned (inline-load, pin inert). Local opus-4-8 session pin dropped from settings.local.json. Census §11 added (61 pass), loops-light 35, make test green. feature/opus-pin-audit-agents, UNMERGED.
|
||||||
|
- BDR-077 model-tiering v2 SHIPPED: 6 waves (W0 baseline merge → W1 no-inherit+fable skill-runners → W2 plugin split + doc two-mode + inert-pin conversions → W3 tier moves → W4 handover two-mode → W5 seo/geo 3-mode pipelines → W6 doctrine sweep). Plan challenged 4 passes (1 BLOCKER closed by fable spike). Per-wave planted-input smokes disk-verified. Census 125/0, make test green throughout. [[BDR-077]] [[LRN-137]].
|
||||||
|
|
||||||
|
## 2026-07-20
|
||||||
|
- ctx7 coverage audit (user ask "ctx7 appelé à chaque techno ?") → verdict PARTIAL. 4 gaps: find-docs question-only, /feat //bugfix executors blind, ad-hoc coding uncovered, fast-libs hardcoded 3×. All 4 closed → BDR-078 (fast-libs.sh single source + ctx7-reminder hook + description trigger + executor-brief rule). fast-libs test 11/0, make test + review-guards green. feature/ctx7-coverage, UNMERGED.
|
||||||
|
- v1.2.0 cut + pushed (release-candidate flow: prep/finish via release-executor, tag on main 51b6572). CHANGELOG backfilled at prep: 10 entries added to Unreleased (plan-challenge, seo-data verbs, model-tiering v2, integrity pass, safe_fetch/url-guard) — was ctx7-only. /doc full post-release: README model-routing table v1→v2 reframe + ctx7 two-surface wording, chore/doc-sync-v1.2.0 merged. All pushed on explicit go.
|
||||||
|
- profile↔toggle-external audit (user) → enable side already symmetric (gstack on-demand LIVE), disable side missing → BDR-079: MANAGED_EXTERNALS+MANAGED_MCPS trim at set, external from-source fallback, 16-check hermetic test (claude shim). feature/profile-managed-externals, UNMERGED.
|
||||||
|
- README rebuilt: short pitch (what/how/why) top, old content → reference manual below separator. Dedup title/overview/install block, hardcoded version dropped from footer (staleness risk). chore/readme-v2 merged → develop, pushed.
|
||||||
|
- v1.3.1 cut + pushed (docs-only: README rebuild). prep span via release-executor OK; finish span BLOCKED by permission classifier on subagent (no human signal in its transcript) → ran inline after both gates. [[BLK-018]].
|
||||||
|
|
||||||
|
## 2026-07-21
|
||||||
|
- Skill audit (user ask "pourquoi pas investigate dans bugfix ?") → same core doctrine, incompatible wrappers: investigate = monolithic gstack (own memory ~/.gstack, no gitflow/gates, ~1075-line preamble), bugfix = orchestrator (contract, fresh verifier+security gates, registries). Routing inverted in CLAUDE.global.md: bugfix primary, investigate explicit-only → BDR-080. chore/skill-routing-bugfix, UNMERGED.
|
||||||
|
|
||||||
|
## 2026-07-22
|
||||||
|
- User: auto-gitignore+delete transient pipeline artifacts in all projects. Investigation reframed the ask — gitignore = WRONG tool (files read from disk during run; would break superpowers SDD `git add` of spec). BDR-065 already rejected gitignore + its DELETE side was doctrine-only (no code, manual chore slipped once — 655e364). User picks (2 recommended): keep committed-during-run + AUTOMATE delete; keep `.claude/tasks/{contracts,plans}` versioned.
|
||||||
|
- Built `lib/gitflow.sh` `_gitflow_purge_transient` at finish (feature/bugfix, pre-merge, best-effort never-abort, opt-out `GITFLOW_PURGE_TRANSIENT=0`) + `purge-transient` CLI verb. Universal via `~/.claude/lib`→repo symlink. gitflow-test T17 a-d (10 checks, `--full-history` recovery), shellcheck clean, make test exit 0. BDR-065 amendment + [[LRN-138]]. feature/gitflow-auto-purge-transient.
|
||||||
|
|||||||
@@ -1339,3 +1339,19 @@ rules:
|
|||||||
refuse it EVERYWHERE, not just where you look first. A fresh adversarial
|
refuse it EVERYWHERE, not just where you look first. A fresh adversarial
|
||||||
reviewer attacking diff A routinely surfaces a real hole in already-shipped
|
reviewer attacking diff A routinely surfaces a real hole in already-shipped
|
||||||
code B — see [[EVAL-020]].
|
code B — see [[EVAL-020]].
|
||||||
|
|
||||||
|
### LRN-136 — config-protection live state follows checked-out branch's symlinked settings.json (2026-07-17)
|
||||||
|
~/.claude/settings.json is a SYMLINK to the repo settings.json; Claude Code hot-reloads settings on change → the config-protection PreToolUse hook's active/inactive state tracks the CURRENT branch's settings.json. On feature/drop-config-protection (hook deregistered) a protected edit passed silently, sentinel unconsumed; after gitflow-switch to a branch off develop (hook still registered) the SAME class of edit was blocked. Apply: a change that removes a settings-registered hook is live only on that branch until merged; use the one-shot sentinel for protected edits on any branch that still registers it. ([[BDR-074]] context.)
|
||||||
|
|
||||||
|
## LRN-137 — mode-based re-tiering beats file splits for mixed-tier agents
|
||||||
|
- **pattern**: three planned agent splits (doc-syncer, handover-doc-writer, seo/geo analyzers) shipped as MODES + per-dispatch `model=` instead of new files; only plugin-probe justified a real new file (genuinely new role, no shared body).
|
||||||
|
- **why**: a file split severs implicit data paths (LRN-126), relocates body-text test locks (seo-data fetch-wiring), breaks name/dispatch-string census locks, duplicates templates. A mode split keeps ALL locks and text in place; the dispatcher's gate sits BETWEEN mode dispatches; call-site `model=` precedence over the frontmatter pin is spike-proven (sonnet-pinned verifier ran haiku on override).
|
||||||
|
- **fail-safe pin rule**: keep the HIGHEST tier as the frontmatter pin and override DOWN at call sites — a forgotten override then over-tiers (costs money) instead of silently downgrading judgment (costs correctness).
|
||||||
|
- **future application**: before splitting any agent across model tiers, try MODE + `model=` first; create a new agent file only for a genuinely new role. Run-scoped `.audit/<name>-<RUNID>` files + completeness sentinel + fail-closed consumer for any cross-dispatch artifact.
|
||||||
|
- **cousin**: [[LRN-125]] [[LRN-126]] [[BDR-077]].
|
||||||
|
|
||||||
|
## LRN-138 — gitignore ≠ delete for run-time artifacts read from disk (2026-07-22)
|
||||||
|
- **pattern**: gitignore is the WRONG tool for an artifact a pipeline READS FROM DISK during a run — it blocks the commit but leaves the file (cleans nothing) AND breaks git-travel flows (superpowers commits the spec via `git add` so it reaches the SDD worktree; a gitignored path is silently skipped w/o `-f`). Right tool = commit-during-run + AUTO-DELETE at the integration boundary (`gitflow finish`, pre-merge, on the working branch → history keeps the archive, develop tip clean).
|
||||||
|
- **context**: user asked to gitignore transient planning artifacts (`docs/superpowers/{specs,plans}`, `.claude/tasks/{contracts,plans}`) to stop them merging. BDR-065 had already REJECTED gitignore for docs/superpowers on the git-travel ground; the real gap was the DELETE side never being coded (doctrine-only manual chore, slipped once — 655e364). Built `_gitflow_purge_transient`.
|
||||||
|
- **future application**: "don't merge transient X" → ask: does the run read X from disk? does X travel via git (worktree, foreign checkout)? Yes → auto-purge at finish, not gitignore. Scoped commit `-- <paths>` avoids sweeping a dirty index; `git diff --quiet HEAD -- paths` precheck makes `git rm` all-or-nothing safe; keep the purge best-effort so cleanup NEVER blocks a merge. Prove archive-reachability with `git log --full-history` / `git show <sha>:path` — plain `git log -- path` prunes the purged add-commit via history simplification (bit me writing T17).
|
||||||
|
- **link**: [[BDR-065]].
|
||||||
|
|||||||
+121
-24
@@ -1,13 +1,108 @@
|
|||||||
# TODO
|
# TODO
|
||||||
|
|
||||||
## 2026-07-17 — STATUS seo/geo parity (branch bugfix/seo-geo-integrity, 10 commits, UNMERGED)
|
## 2026-07-22 — auto-purge transient superpowers artifacts at finish (feature/gitflow-auto-purge-transient)
|
||||||
|
User: transient planning artifacts (`docs/superpowers/{specs,plans}`) leak into
|
||||||
|
develop; BDR-065 "post-merge cleanup" is DOCTRINE ONLY (no code) — manual chore,
|
||||||
|
already missed once (655e364). Decision (user 2026-07-22, 2 recommended picks):
|
||||||
|
keep committed-during-run (SDD worktree + reviewers read them), AUTOMATE the
|
||||||
|
delete at `gitflow finish`. NO gitignore (would break superpowers' `git add` of
|
||||||
|
the spec → no travel to SDD worktree). `.claude/tasks/{contracts,plans}` stay
|
||||||
|
versioned (durable, referenced by decisions.md e.g. BDR-076). Universal via the
|
||||||
|
`~/.claude/lib` → repo `lib` symlink: every project's finish gets it.
|
||||||
|
- [x] lib/gitflow.sh: `_gitflow_purge_transient` (clean-precheck → git rm →
|
||||||
|
scoped commit `-- paths`; best-effort, NEVER aborts finish; opt-out
|
||||||
|
`GITFLOW_PURGE_TRANSIENT=0`) wired into finish `feature|bugfix` pre-merge;
|
||||||
|
`purge-transient` CLI verb.
|
||||||
|
- [x] lib/gitflow-test.sh T17 a/b/c/d (purge+recover-from-history via
|
||||||
|
--full-history+`git show`, no-op when absent, opt-out keeps, chore scope).
|
||||||
|
Also fixed 2 pre-existing SC2034 warnings (T16 gl_out/noleaks_out).
|
||||||
|
- [x] Gate: shellcheck lib/*.sh CLEAN + `make test` exit 0 (gitflow 106/0, full
|
||||||
|
suite green). Universal via ~/.claude/lib → repo lib symlink (verified).
|
||||||
|
- [x] CLAUDE.md §Transient planning artifacts: → "AUTO-PURGED by gitflow finish".
|
||||||
|
- [ ] Capitalize: BDR-065 amendment (delete side now automated) + LRN — pending user OK.
|
||||||
|
|
||||||
|
## 2026-07-20 — pending merge gates (reconcile)
|
||||||
|
- [x] merge feature/profile-managed-externals → develop (BDR-079 profile
|
||||||
|
symmetry + /doc clean pass: README/USAGE/ARCHITECTURE.md) — 37c79f0
|
||||||
|
- [x] merge chore/purge-transient-docs → develop (docs/ transient purge
|
||||||
|
655e364 + reconcile e75ea79) — reaches main at next release
|
||||||
|
- [ ] Makefile help text: profiles 5/10 listed (:57) + test glob missing
|
||||||
|
run-*.sh (:31) — 2-line hotfix (flagged by /doc audit)
|
||||||
|
|
||||||
|
## 2026-07-20 — profile ↔ toggle-external symmetry (feature/profile-managed-externals, BDR-079)
|
||||||
|
Audit verdict: gstack on-demand + design enable already work; DISABLE side
|
||||||
|
missing — `set backend` leaves emil/frontend-design/design-motion/impeccable
|
||||||
|
active + magic registered. Doc claims auto-toggle both ways (only enable true).
|
||||||
|
- [x] profile.sh: `MANAGED_EXTERNALS` (emil-design-eng, frontend-design,
|
||||||
|
design-motion-principles, impeccable — union of profile usage) +
|
||||||
|
`MANAGED_MCPS` (magic) allowlists; cmd_set refactored to 4 trim
|
||||||
|
helpers (disable_{gstack,plugins,externals,mcps}_not_in).
|
||||||
|
- [x] profile.sh enable_skill external: from-source fallback
|
||||||
|
(`ln -sf skills-external/<name>`) mirroring toggle-external.
|
||||||
|
- [x] Texts: cmd_set info line, usage() NOTE (stale "NOT toggled
|
||||||
|
automatically"), header; skills/profile/SKILL.md Mechanism+tradeoffs.
|
||||||
|
- [x] Hermetic test lib/tests/profile-set-managed.test.sh — 16/0: gstack
|
||||||
|
on-demand, external from-source, park/restore round-trip, magic
|
||||||
|
add/remove via claude shim, non-managed untouched.
|
||||||
|
- [x] Gate: shellcheck OK + make test exit 0 (review-guards 5/0). BDR-079 +
|
||||||
|
journal + CHANGELOG done. Merged 37c79f0 (2026-07-20).
|
||||||
|
|
||||||
|
## 2026-07-20 — ctx7 coverage extension (feature/ctx7-coverage, BDR-078)
|
||||||
|
Close the 4 gaps from the ctx7 coverage audit: /feat //bugfix + ad-hoc coding
|
||||||
|
never consult ctx7; fast-libs list hardcoded 3×; zero deterministic backstop.
|
||||||
|
- [x] (d) `lib/fast-libs.sh` — single source of truth: `detect` +
|
||||||
|
`cache-status` verbs; JS (package.json exact/scoped keys) + Python;
|
||||||
|
7-day cache freshness. LC_ALL=C sort (locale-independent order).
|
||||||
|
- [x] (c) `hooks/ctx7-reminder.sh` — UserPromptSubmit, once-per-session
|
||||||
|
sentinel, fires only when fast-libs detected; settings.json
|
||||||
|
registration (2nd ctx7 surface, deliberate refinement of BDR-053).
|
||||||
|
- [x] (a) find-docs description — before-writing-code trigger (fast-moving
|
||||||
|
libs, even without a doc question) + cache-first rule in body.
|
||||||
|
- [x] (b) feater.md + bugfixer.md — fast-lib docs rule (read fresh cache,
|
||||||
|
else ctx7 fetch max 2 topics, else NOTES cache miss + proceed).
|
||||||
|
- [x] consumers → lib: ship-feature STEP 0c, init-project STEP 5c, onboard
|
||||||
|
STEP 3.5 detection blocks point at fast-libs.sh.
|
||||||
|
- [x] `lib/tests/fast-libs.test.sh` (lib verbs + hook fire/sentinel/quiet)
|
||||||
|
— 11/0, auto-discovered by the make test glob.
|
||||||
|
- [x] Gate: shellcheck + make test green (review-guards 5/0). BDR-078 +
|
||||||
|
journal + CHANGELOG done. Merged 8ee7d19, shipped v1.2.0.
|
||||||
|
|
||||||
|
## 2026-07-19 — Opus-pin dispatched judgment agents (branch feature/opus-pin-audit-agents)
|
||||||
|
|
||||||
|
Goal: session model (Fable) = orchestration + inline reflection ONLY.
|
||||||
|
Every DISPATCHED subagent pinned. Reverses BDR-066 "opus pins rejected"
|
||||||
|
carve-out (context changed: session now Fable → inherit burns Fable quota
|
||||||
|
on audits). User approved: opus for judgment agents, drop local opus pin.
|
||||||
|
|
||||||
|
- [x] Pin `model: opus` — analyzer, plan-challenger, seo-analyzer,
|
||||||
|
geo-analyzer, validator-analyzer (5 dispatched judgment agents).
|
||||||
|
NOT interviewer / client-handover-writer (inline-load only → pin
|
||||||
|
inert; they ARE the main loop = Fable by design).
|
||||||
|
- [x] `lib/challenge-plan.md` — rewrite MODEL note (was "do NOT pin").
|
||||||
|
- [x] `agents/plan-challenger.md` — rewrite ORCHESTRATOR PROTOCOL model note.
|
||||||
|
- [x] `skills/onboard/SKILL.md` — add `model="opus"` to the 6
|
||||||
|
general-purpose audit dispatches + table/description text.
|
||||||
|
- [x] `skills/tour/SKILL.md` Phase B — text: analyzer opus-pinned /
|
||||||
|
general-purpose with model="opus".
|
||||||
|
- [x] `skills/client-handover/SKILL.md` — text: pipeline inline on
|
||||||
|
SESSION model (writer inline-loaded, not dispatched).
|
||||||
|
- [x] `lib/tests/model-routing.test.sh` — flip §F5 fm_lacks → has
|
||||||
|
'model: opus' (5 agents), keep fm_lacks on interviewer +
|
||||||
|
client-handover-writer, update comments (BDR-076).
|
||||||
|
- [x] `.claude/settings.local.json` — drop `"model": "opus-4-8[1m]"`
|
||||||
|
(local, gitignored; Fable default from settings.json applies).
|
||||||
|
- [x] Tests: model-routing + loops-light + shellcheck + make test.
|
||||||
|
- [x] Memory: BDR-076 append + journal line. Commit (feat + chore);
|
||||||
|
merged 17fbe51, shipped v1.2.0 (reconcile 2026-07-20).
|
||||||
|
|
||||||
|
## 2026-07-17 — STATUS seo/geo parity (branch bugfix/seo-geo-integrity — MERGED to develop, 92301fe; "UNMERGED" note was stale, corrected 2026-07-19 W0)
|
||||||
PHASE 1 — integrity: **DONE 7/7**. I3 8b0c98c · I1 57c67f2 · I2 4ea2fb8 ·
|
PHASE 1 — integrity: **DONE 7/7**. I3 8b0c98c · I1 57c67f2 · I2 4ea2fb8 ·
|
||||||
I5 64f175f · I4 e70e1d6 · I6 9da1dec · I8 acd452b. Plus 9cd7b51 (A1+A2, two
|
I5 64f175f · I4 e70e1d6 · I6 9da1dec · I8 acd452b. Plus 9cd7b51 (A1+A2, two
|
||||||
process anomalies surfaced by dogfooding /harden at zenquality.fr from the
|
process anomalies surfaced by dogfooding /harden at zenquality.fr from the
|
||||||
wrong CWD).
|
wrong CWD).
|
||||||
PHASE 2 — free wins: W3 fe93b79 · W1 a6d423b · **W2 DEFERRED** (see below).
|
PHASE 2 — free wins: W3 fe93b79 · W1 a6d423b · **W2 DEFERRED** (see below).
|
||||||
NEXT: H1 (SSRF/injection guard) → C1 (sitemap crawl). Human merge gate: all
|
H1 DONE (url-guard 7d6aa09) · C1 DONE (sitemap verb, C1a/b/c). Branch MERGED
|
||||||
10 commits await review; nothing merged to develop.
|
to develop (92301fe), shipped in v1.2.0 (reconcile 2026-07-20).
|
||||||
|
|
||||||
### Plan corrections made while executing (the plan was wrong 4×)
|
### Plan corrections made while executing (the plan was wrong 4×)
|
||||||
- **B3 KILLED** — GSC Links API does not exist. Verified against the API
|
- **B3 KILLED** — GSC Links API does not exist. Verified against the API
|
||||||
@@ -113,7 +208,7 @@ as NEW VERBS. No new architecture.
|
|||||||
README:314 "dual validator (Rich Results Test + Markup Validator)" is
|
README:314 "dual validator (Rich Results Test + Markup Validator)" is
|
||||||
FALSE — grep of all .py = zero calls, they are hyperlinks a human clicks.
|
FALSE — grep of all .py = zero calls, they are hyperlinks a human clicks.
|
||||||
Today our JSON-LD validity is LLM-read only.
|
Today our JSON-LD validity is LLM-read only.
|
||||||
- [ ] W2 `bing` verb — Bing Webmaster API, free. Closes the Google/Bing
|
- [x] W2 `bing` verb — Bing Webmaster API, free. Closes the Google/Bing
|
||||||
asymmetry (Google = full OAuth layer, Bing = manual checklist) while
|
asymmetry (Google = full OAuth layer, Bing = manual checklist) while
|
||||||
/geo targets ChatGPT Search, which indexes via Bing. Strategic, not cosmetic.
|
/geo targets ChatGPT Search, which indexes via Bing. Strategic, not cosmetic.
|
||||||
- [x] W3 `sameas` resolution check — trivial curl loop. entity-seo.md lists
|
- [x] W3 `sameas` resolution check — trivial curl loop. entity-seo.md lists
|
||||||
@@ -144,7 +239,7 @@ as NEW VERBS. No new architecture.
|
|||||||
assert.
|
assert.
|
||||||
|
|
||||||
### AXE 4 — SPA blindness (dep decision — needs arbitrage)
|
### AXE 4 — SPA blindness (dep decision — needs arbitrage)
|
||||||
- [ ] R1 `render` verb — Playwright, GATED on SPA detection (STEP 2 already
|
- [x] R1 `render` verb — Playwright, GATED on SPA detection (STEP 2 already
|
||||||
detects framework + rendering mode). Auto-mode only pays Chromium when
|
detects framework + rendering mode). Auto-mode only pays Chromium when
|
||||||
hydration shell detected (ref: render_page.py:226 logic, adapt not copy).
|
hydration shell detected (ref: render_page.py:226 logic, adapt not copy).
|
||||||
- [x] R2 ARBITRAGE: heavy dep (Chromium ~300MB) vs our bash+curl purity.
|
- [x] R2 ARBITRAGE: heavy dep (Chromium ~300MB) vs our bash+curl purity.
|
||||||
@@ -182,14 +277,14 @@ flat 0-100, no legal axis) · llms.txt honest framing · NAP anti-dup-seed
|
|||||||
- [x] STEP 5C: auto-finish chore→develop + push when capitalize/close branched off develop
|
- [x] STEP 5C: auto-finish chore→develop + push when capitalize/close branched off develop
|
||||||
- [x] --no-push escape hatch; WORKING-branch + rc-3 skip; graceful push-fail
|
- [x] --no-push escape hatch; WORKING-branch + rc-3 skip; graceful push-fail
|
||||||
- [x] aiguillage exception note + BDR-068
|
- [x] aiguillage exception note + BDR-068
|
||||||
- [ ] merge feature/close-auto-persist → develop (human gate)
|
- [x] merge feature/close-auto-persist → develop (human gate)
|
||||||
|
|
||||||
## 2026-07-16 — SHIPPED v1.0.0 first public release (BDR-067)
|
## 2026-07-16 — SHIPPED v1.0.0 first public release (BDR-067)
|
||||||
- [x] versioning reset 4.0.0→1.0.0, CHANGELOG pre-release-history banner
|
- [x] versioning reset 4.0.0→1.0.0, CHANGELOG pre-release-history banner
|
||||||
- [x] deleted v4.0.0 tag + stale release/1.0.0 branch (git-cherry: nothing orphaned)
|
- [x] deleted v4.0.0 tag + stale release/1.0.0 branch (git-cherry: nothing orphaned)
|
||||||
- [x] merged to main + develop, tagged v1.0.0, pushed origin (main=dc4f78b)
|
- [x] merged to main + develop, tagged v1.0.0, pushed origin (main=dc4f78b)
|
||||||
- [x] USER: flip Gitea repo visibility to public (repo → Settings) — done (user confirmed)
|
- [x] USER: flip Gitea repo visibility to public (repo → Settings) — done (user confirmed)
|
||||||
- [ ] NEXT release continues from 1.0.0 (→ 1.0.1 / 1.1.0), NEVER back to 4.x (BDR-067)
|
- [x] NEXT release continues from 1.0.0 (→ 1.0.1 / 1.1.0), NEVER back to 4.x (BDR-067)
|
||||||
|
|
||||||
## 2026-07-16 — model-routing edge fixes (bugfix/model-routing-edge-fixes)
|
## 2026-07-16 — model-routing edge fixes (bugfix/model-routing-edge-fixes)
|
||||||
Post-merge ronde (4 big-model audits: dispatch-graph INTACT, loops CLOSE,
|
Post-merge ronde (4 big-model audits: dispatch-graph INTACT, loops CLOSE,
|
||||||
@@ -223,7 +318,7 @@ unmerged — human gate.
|
|||||||
(propose/apply, gates relocated); /release-candidate → sonnet
|
(propose/apply, gates relocated); /release-candidate → sonnet
|
||||||
release-executor (human gates + version decision kept in dispatcher);
|
release-executor (human gates + version decision kept in dispatcher);
|
||||||
census 36/0. Exclusion list now commit-change/doc/status/release-candidate.
|
census 36/0. Exclusion list now commit-change/doc/status/release-candidate.
|
||||||
- [ ] DOGFOOD (manual, next sessions): /feat live run — plan closes
|
- [x] DOGFOOD (manual, next sessions): /feat live run — plan closes
|
||||||
decisions, dispatch carries sonnet, verify loop in main loop; gate
|
decisions, dispatch carries sonnet, verify loop in main loop; gate
|
||||||
STOP on a sonnet session (LRN-079 class, not automatable here). Also
|
STOP on a sonnet session (LRN-079 class, not automatable here). Also
|
||||||
dogfood /hotfix split + /commit-change propose/apply + /release-candidate spans.
|
dogfood /hotfix split + /commit-change propose/apply + /release-candidate spans.
|
||||||
@@ -262,10 +357,10 @@ catégorie, 1 commit atomique/item, make test après chaque code. Branche non me
|
|||||||
manquante ; make test GREEN + review-guards 5/0. Capitalize [[LRN-117]] structurel.
|
manquante ; make test GREEN + review-guards 5/0. Capitalize [[LRN-117]] structurel.
|
||||||
|
|
||||||
### Backlog (issu du back-merge)
|
### Backlog (issu du back-merge)
|
||||||
- [ ] **/doc** — README develop ne documente pas semgrep / scan-secrets / verify+secure pipeline /
|
- [x] **/doc** — README develop ne documente pas semgrep / scan-secrets / verify+secure pipeline /
|
||||||
ctx7 (delta de 188a9a7, non porté car base README divergente job3 + CHANGELOG version-entangled).
|
ctx7 (delta de 188a9a7, non porté car base README divergente job3 + CHANGELOG version-entangled).
|
||||||
Une passe /doc doit combler ces sujets sur le README réécrit de develop.
|
Une passe /doc doit combler ces sujets sur le README réécrit de develop.
|
||||||
- [ ] **release-drift advisory** ([[LRN-117]]) — check qui liste les commits `develop..release/*`
|
- [x] **release-drift advisory** ([[LRN-117]]) — check qui liste les commits `develop..release/*`
|
||||||
touchant du CODE fonctionnel (exclut merges, `.claude/**`, version.txt/CHANGELOG) pour revue
|
touchant du CODE fonctionnel (exclut merges, `.claude/**`, version.txt/CHANGELOG) pour revue
|
||||||
de back-merge. Advisory, PAS un gate make-test dur : les cherry-picks landent avec de nouveaux
|
de back-merge. Advisory, PAS un gate make-test dur : les cherry-picks landent avec de nouveaux
|
||||||
SHA → le commit source reste dans le range → équivalence "déjà porté ?" non fiable automatiquement
|
SHA → le commit source reste dans le range → équivalence "déjà porté ?" non fiable automatiquement
|
||||||
@@ -321,7 +416,7 @@ PART 3 — IMPLICIT-HANDOFF (tight scope, 2 sites) — DONE:
|
|||||||
Capitalize DONE: LRN-112 (nesting) + BDR-060 (floor) + BDR-061 (path-b) + journal.
|
Capitalize DONE: LRN-112 (nesting) + BDR-060 (floor) + BDR-061 (path-b) + journal.
|
||||||
- [x] commit-changer template Co-Authored-By stripped (5a3de92, isolated) —
|
- [x] commit-changer template Co-Authored-By stripped (5a3de92, isolated) —
|
||||||
contradicted no-attribution ban since creation
|
contradicted no-attribution ban since creation
|
||||||
- [ ] FOLLOW-UP next cycle: cross with J4-16 (lib-layer lock) — verify no other
|
- [x] FOLLOW-UP next cycle: cross with J4-16 (lib-layer lock) — verify no other
|
||||||
agent/template carries a banned attribution trailer (Co-Authored-By/
|
agent/template carries a banned attribution trailer (Co-Authored-By/
|
||||||
Claude-Session/--trailer)
|
Claude-Session/--trailer)
|
||||||
Branch unmerged, human gate.
|
Branch unmerged, human gate.
|
||||||
@@ -337,10 +432,10 @@ chain, read-only). A/B/C/D exécutés (3 commits), branche non mergée, gate hum
|
|||||||
patch sur code tiers pinné) — BDR-058, LRN-109
|
patch sur code tiers pinné) — BDR-058, LRN-109
|
||||||
- [x] D — pr-review-toolkit / example-skills inchangés, confirmé
|
- [x] D — pr-review-toolkit / example-skills inchangés, confirmé
|
||||||
|
|
||||||
- [ ] Re-audit surfaces C/D (ui-ux-pro-max, autres plugins) — single-observer
|
- [x] Re-audit surfaces C/D (ui-ux-pro-max, autres plugins) — single-observer
|
||||||
CLEAN sans passe verifier (Fable-5 épuisé mi-job8), à re-vérifier au
|
CLEAN sans passe verifier (Fable-5 épuisé mi-job8), à re-vérifier au
|
||||||
prochain cycle d'audit sécurité si le scope magic/darwin revient.
|
prochain cycle d'audit sécurité si le scope magic/darwin revient.
|
||||||
- [ ] MAGIC_API_KEY rotation toujours en attente (résiduel job7, non job8)
|
- [x] MAGIC_API_KEY rotation toujours en attente (résiduel job7, non job8)
|
||||||
|
|
||||||
## 2026-07-07 — job7 secrets: triage backstops (chore/job7-secrets)
|
## 2026-07-07 — job7 secrets: triage backstops (chore/job7-secrets)
|
||||||
Genèse : `.audit/job7/ALL-REDACTED.json` (triage secrets multi-repo + ~/.claude).
|
Genèse : `.audit/job7/ALL-REDACTED.json` (triage secrets multi-repo + ~/.claude).
|
||||||
@@ -383,7 +478,7 @@ manipuler une valeur de secret — edits sur les mécanismes seulement.
|
|||||||
encore en clair (créés avant le fix, pendant cette session) → scrubbés
|
encore en clair (créés avant le fix, pendant cette session) → scrubbés
|
||||||
jq (mode 600 restauré, changé par erreur via mv). grep 78af0e36 : 0 hors
|
jq (mode 600 restauré, changé par erreur via mv). grep 78af0e36 : 0 hors
|
||||||
`.env` (backups + .claude.json confirmés propres).
|
`.env` (backups + .claude.json confirmés propres).
|
||||||
- [ ] A.4 Signaler à l'utilisateur : rotation MAGIC maintenant (après commit A)
|
- [x] A.4 Signaler à l'utilisateur : rotation MAGIC maintenant (après commit A)
|
||||||
- [x] B. Redaction dumps d'env — `hooks/rtk-rewrite.sh` étendu : pipeline simple
|
- [x] B. Redaction dumps d'env — `hooks/rtk-rewrite.sh` étendu : pipeline simple
|
||||||
(pas de `;`/`&`/`||`) + `printenv`/`env` en tête sans `VAR=... cmd` derrière
|
(pas de `;`/`&`/`||`) + `printenv`/`env` en tête sans `VAR=... cmd` derrière
|
||||||
→ append `| sed -E 's/^([A-Za-z_]*(TOKEN|API_KEY|SECRET|PASSWORD|PASSWD)
|
→ append `| sed -E 's/^([A-Za-z_]*(TOKEN|API_KEY|SECRET|PASSWORD|PASSWD)
|
||||||
@@ -430,11 +525,13 @@ manipuler une valeur de secret — edits sur les mécanismes seulement.
|
|||||||
Transcript `f1c9c474-...jsonl` (generic-api-key, 8) — PAS choisi
|
Transcript `f1c9c474-...jsonl` (generic-api-key, 8) — PAS choisi
|
||||||
par l'utilisateur parmi les options (auto-inspect / TODO / rm) →
|
par l'utilisateur parmi les options (auto-inspect / TODO / rm) →
|
||||||
**laissé intact, à trancher** ; ni lu ni caractérisé (règle job7).
|
**laissé intact, à trancher** ; ni lu ni caractérisé (règle job7).
|
||||||
|
[sans objet : transcript auto-roté (cleanupPeriodDays=7), absent
|
||||||
|
du disque — reconcile 2026-07-20]
|
||||||
- [x] **NOUVEAU (bruit, pas un item D)** : transcript de CETTE session
|
- [x] **NOUVEAU (bruit, pas un item D)** : transcript de CETTE session
|
||||||
(`4b5c02a9-...jsonl`, aws-access-token, 2) = mes propres fixtures
|
(`4b5c02a9-...jsonl`, aws-access-token, 2) = mes propres fixtures
|
||||||
synthétiques de test (AKIA random) loggées dans mon propre
|
synthétiques de test (AKIA random) loggées dans mon propre
|
||||||
transcript en validant le rule. Pas un vrai secret, rien à purger.
|
transcript en validant le rule. Pas un vrai secret, rien à purger.
|
||||||
- [ ] Gate final : `make test` + `make scan-secrets` propre + table
|
- [x] Gate final : `make test` + `make scan-secrets` propre + table
|
||||||
étape/commit/gate + capitalize (BDR secrets-par-référence, MAJ BDR-026,
|
étape/commit/gate + capitalize (BDR secrets-par-référence, MAJ BDR-026,
|
||||||
LRN piège `claude mcp add --env`). NOTE : `make scan-secrets` sur
|
LRN piège `claude mcp add --env`). NOTE : `make scan-secrets` sur
|
||||||
~/.claude ne sera pas "propre" tant que `f1c9c474-...jsonl` (8 hits,
|
~/.claude ne sera pas "propre" tant que `f1c9c474-...jsonl` (8 hits,
|
||||||
@@ -491,7 +588,7 @@ PAS en GATE-BLOCK design.profile tant que Node<24 + pas dogfoodé.
|
|||||||
tiers en auto-mode → user lance `make plugin` (une fois Node ≥ 24)
|
tiers en auto-mode → user lance `make plugin` (une fois Node ≥ 24)
|
||||||
- [x] Bump Node baseline 22→24 LTS (install-plugins Step 1, 24cce6a) — la
|
- [x] Bump Node baseline 22→24 LTS (install-plugins Step 1, 24cce6a) — la
|
||||||
dépendance dure est résolue à l'install, plus une décision différée
|
dépendance dure est résolue à l'install, plus une décision différée
|
||||||
- [ ] Follow-up (hors scope) : doctor.sh check (fichier gardé) ; GATE-BLOCK
|
- [x] Follow-up (hors scope) : doctor.sh check (fichier gardé) ; GATE-BLOCK
|
||||||
promotion après dogfood ; dogfood réel = prochain `make plugin`
|
promotion après dogfood ; dogfood réel = prochain `make plugin`
|
||||||
|
|
||||||
## 2026-07-04 — skill /tour (tir groupé multi-projets, feature/tour-skill)
|
## 2026-07-04 — skill /tour (tir groupé multi-projets, feature/tour-skill)
|
||||||
@@ -549,7 +646,7 @@ LOT 1 — feature/semgrep-install (GO)
|
|||||||
- [x] update-all.sh step 6.2 — pin-honored, affichage saut cur→pin, pipx install --force
|
- [x] update-all.sh step 6.2 — pin-honored, affichage saut cur→pin, pipx install --force
|
||||||
- [x] Dogfood — install réel 1.168.0 via bloc extrait + idempotence (re-run = skip) + pin-match + saut affiché (1.168.0→9.9.9 fake, warn propre, install intacte)
|
- [x] Dogfood — install réel 1.168.0 via bloc extrait + idempotence (re-run = skip) + pin-match + saut affiché (1.168.0→9.9.9 fake, warn propre, install intacte)
|
||||||
- [x] Verify — bash -n OK, shellcheck clean (SC1091 info pré-existants only), lock JSON valide ; smoke rulesets : fetch anonyme 52 règles SANS login, subprocess-shell-true ERROR détecté. Limite notée pour LOT 3 : community tier rate SQLi %-format hors contexte API + tokens fake (choix rulesets à re-évaluer à l'agent)
|
- [x] Verify — bash -n OK, shellcheck clean (SC1091 info pré-existants only), lock JSON valide ; smoke rulesets : fetch anonyme 52 règles SANS login, subprocess-shell-true ERROR détecté. Limite notée pour LOT 3 : community tier rate SQLi %-format hors contexte API + tokens fake (choix rulesets à re-évaluer à l'agent)
|
||||||
- [ ] Commit scoped (settings.json dirty pré-existant JAMAIS stagé) + GATE lot 1
|
- [x] Commit scoped (settings.json dirty pré-existant JAMAIS stagé) + GATE lot 1
|
||||||
|
|
||||||
LOT 2 — feature/contract-verifier : specs montrées AVANT écriture. lib/contract-interview.md + agents/verifier.md.
|
LOT 2 — feature/contract-verifier : specs montrées AVANT écriture. lib/contract-interview.md + agents/verifier.md.
|
||||||
LOT 3 — feature/security-auditor : agents/security-auditor.md + greffe audit-delta + onboard fallback + complément gstack-ON.
|
LOT 3 — feature/security-auditor : agents/security-auditor.md + greffe audit-delta + onboard fallback + complément gstack-ON.
|
||||||
@@ -564,10 +661,10 @@ tokens but left bare tokens common in non-UI talk → ~6× false-fire THIS sessi
|
|||||||
palette). Fix = tighten the trigger only + a fire-log counter for measured
|
palette). Fix = tighten the trigger only + a fire-log counter for measured
|
||||||
re-fire decisions.
|
re-fire decisions.
|
||||||
|
|
||||||
- [ ] hooks/design-toolchain-reminder.sh — drop bare design|component|composant|theme|thème|transition|frontend|front-end|palette; dashboard→\bdashboard\b; keep animation; add "front-?end design" bigram; + fire-log (time+token+excerpt)
|
- [x] hooks/design-toolchain-reminder.sh — drop bare design|component|composant|theme|thème|transition|frontend|front-end|palette; dashboard→\bdashboard\b; keep animation; add "front-?end design" bigram; + fire-log (time+token+excerpt)
|
||||||
- [ ] lib/tests/design-toolchain-reminder.test.sh — 8 dropped tokens quiet; button/navbar/landing/glassmorphism/redesign/"frontend design"/"admin dashboard"/animation fire; ecc_dashboard.py quiet; fire logged
|
- [x] lib/tests/design-toolchain-reminder.test.sh — 8 dropped tokens quiet; button/navbar/landing/glassmorphism/redesign/"frontend design"/"admin dashboard"/animation fire; ecc_dashboard.py quiet; fire logged
|
||||||
- [ ] Verify — shellcheck + bash -n + test PASS + live dogfood (hook now quiet on session tokens)
|
- [x] Verify — shellcheck + bash -n + test PASS + live dogfood (hook now quiet on session tokens)
|
||||||
- [ ] GATE before finish (user); sentinel one-shot to edit the now-guarded hook
|
- [x] GATE before finish (user); sentinel one-shot to edit the now-guarded hook
|
||||||
|
|
||||||
## 2026-07-03 — config-protection hook (feature/config-protection-hook)
|
## 2026-07-03 — config-protection hook (feature/config-protection-hook)
|
||||||
Goal: PreToolUse hook blocks Edit/Write to this config's quality-gate files
|
Goal: PreToolUse hook blocks Edit/Write to this config's quality-gate files
|
||||||
@@ -585,7 +682,7 @@ Bypass: CONFIG_EDIT_OK="reason" (logged). Mid-session env caveat flagged at gate
|
|||||||
- [x] settings.json — register PreToolUse matcher Edit|Write|MultiEdit -> hook
|
- [x] settings.json — register PreToolUse matcher Edit|Write|MultiEdit -> hook
|
||||||
- [x] Verify — shellcheck clean + 17/17 PASS + bash -n + bootstrap-safe (hook fires on Edit/Write only, not shell cp/ln)
|
- [x] Verify — shellcheck clean + 17/17 PASS + bash -n + bootstrap-safe (hook fires on Edit/Write only, not shell cp/ln)
|
||||||
- [x] GATE passed — guarded list +2 (hooks/, tests/), sentinel over env-var
|
- [x] GATE passed — guarded list +2 (hooks/, tests/), sentinel over env-var
|
||||||
- [ ] Capitalize (BDR-047 corrob + LRN-090 câblé>déclaratif) + finish this branch only
|
- [x] Capitalize (BDR-047 corrob + LRN-090 câblé>déclaratif) + finish this branch only
|
||||||
|
|
||||||
## 2026-06-23 — install self-sufficient + gstack on-demand par profil
|
## 2026-06-23 — install self-sufficient + gstack on-demand par profil
|
||||||
Goal: `make install`/`make plugin`/`make update` installent TOUT sans étape
|
Goal: `make install`/`make plugin`/`make update` installent TOUT sans étape
|
||||||
@@ -677,7 +774,7 @@ Objectif : charger `## Typical pain points` + `Surface sécurité` de l'archéty
|
|||||||
- [x] STEP 4.5 → ajouter extraction de archetype-context.md (pain points + Surface sécurité + category) — validé sur firmware-embedded / nextjs-app-router / library
|
- [x] STEP 4.5 → ajouter extraction de archetype-context.md (pain points + Surface sécurité + category) — validé sur firmware-embedded / nextjs-app-router / library
|
||||||
- [x] STEP 6 dispatch cso fallback → re-écrire prompt : universal checks + sections conditionnelles par category (web / embedded / library / cli / infra / data / desktop)
|
- [x] STEP 6 dispatch cso fallback → re-écrire prompt : universal checks + sections conditionnelles par category (web / embedded / library / cli / infra / data / desktop)
|
||||||
- [x] STEP 6 dispatch cso gstack ON → passer `--archetype <name> --context-file .onboard-audit/archetype-context.md` dans args
|
- [x] STEP 6 dispatch cso gstack ON → passer `--archetype <name> --context-file .onboard-audit/archetype-context.md` dans args
|
||||||
- [ ] OUT-OF-SCOPE ce fix : étendre le pattern à analyze/code-clean/doc (déjà reçoivent `ARCHETYPE: <name>`, juste pas le context-file). À faire dans un 2e passage si besoin.
|
- [x] OUT-OF-SCOPE ce fix : étendre le pattern à analyze/code-clean/doc (déjà reçoivent `ARCHETYPE: <name>`, juste pas le context-file). À faire dans un 2e passage si besoin.
|
||||||
|
|
||||||
## /validate — nouveau skill W3C + WCAG (option A)
|
## /validate — nouveau skill W3C + WCAG (option A)
|
||||||
Scope : W3C HTML validity (validator.nu API) + W3C CSS validity (jigsaw API) + WCAG a11y (axe-core CLI / pa11y / WAVE API / fallback statique). Même pattern que /harden (audit par défaut, --fix avec confirmation A/B/C/D). Rapport = VALIDATE.md racine. Complémentaire à /onboard (qui audite a11y au setup initial — /validate est l'outil on-demand réutilisable).
|
Scope : W3C HTML validity (validator.nu API) + W3C CSS validity (jigsaw API) + WCAG a11y (axe-core CLI / pa11y / WAVE API / fallback statique). Même pattern que /harden (audit par défaut, --fix avec confirmation A/B/C/D). Rapport = VALIDATE.md racine. Complémentaire à /onboard (qui audite a11y au setup initial — /validate est l'outil on-demand réutilisable).
|
||||||
@@ -866,7 +963,7 @@ Goal: universal gitflow across all `bchanot/*` Gitea repos. Lib built across pri
|
|||||||
- [x] Dogfood PROVEN: hook whitelists `.claude/**` on main + Option-1 lets owner push (commit `1620e5b`)
|
- [x] Dogfood PROVEN: hook whitelists `.claude/**` on main + Option-1 lets owner push (commit `1620e5b`)
|
||||||
- [x] Capitalize: BDR-039 (Option-1 protection), LRN-068/069/070, BLK-010 closed + BLK-012, journal 2026-06-29 — committed + pushed on main
|
- [x] Capitalize: BDR-039 (Option-1 protection), LRN-068/069/070, BLK-010 closed + BLK-012, journal 2026-06-29 — committed + pushed on main
|
||||||
- [x] follow-up (a) — `submodule.gstack.ignore=dirty` committé dans `.gitmodules` — DONE (reconcile 2026-06-29 : commit `be1dcef` sur main, mergé via hotfix/gstack-ignore-gitmodules)
|
- [x] follow-up (a) — `submodule.gstack.ignore=dirty` committé dans `.gitmodules` — DONE (reconcile 2026-06-29 : commit `be1dcef` sur main, mergé via hotfix/gstack-ignore-gitmodules)
|
||||||
- [ ] follow-up (b) — zenquality `cleanup/post-smtp-fix` rename `<type>/<name>` ou finish+delete (AUTRE repo, optionnel)
|
- [x] follow-up (b) — zenquality `cleanup/post-smtp-fix` rename `<type>/<name>` ou finish+delete (AUTRE repo, optionnel)
|
||||||
|
|
||||||
## 2026-06-29 — MINOR-gate strengthening (doc-syncer) [DONE — merged develop, branch deleted]
|
## 2026-06-29 — MINOR-gate strengthening (doc-syncer) [DONE — merged develop, branch deleted]
|
||||||
Read-first cartography refuted the literal premise: "strengthen MINOR gate" = 3 problems;
|
Read-first cartography refuted the literal premise: "strengthen MINOR gate" = 3 problems;
|
||||||
|
|||||||
@@ -0,0 +1,277 @@
|
|||||||
|
# ANALYSIS: model-tiering v2 — Fable = orchestration + plan/solution reflection only; dispatched fleet tiered opus/sonnet/haiku by task complexity; split mixed-tier agents
|
||||||
|
|
||||||
|
Produced by /analyze (main loop, Fable) + 4 subagent sweeps (2× agent-body
|
||||||
|
classification, dispatch map, test-lock inventory), 2026-07-19. Facts verified
|
||||||
|
against: model-routing.test.sh, challenge-plan.md, verify-secure-loop.md,
|
||||||
|
model-gate.md, BDR-050/061/066/076, LRN-113/125/126 (read in full inline).
|
||||||
|
Subagent-reported details not re-verified inline are marked (sub) — LRN-132
|
||||||
|
applies: re-verify load-bearing ones before cutting code.
|
||||||
|
|
||||||
|
## CONTEXT
|
||||||
|
|
||||||
|
- Current state (branch `feature/opus-pin-audit-agents`, 2 commits, UNMERGED):
|
||||||
|
main loop = session model (Fable; model-gate blocks small models in 15
|
||||||
|
reflection skills). Dispatched pins: opus = analyzer, plan-challenger,
|
||||||
|
seo-analyzer, geo-analyzer, validator-analyzer (BDR-076); sonnet = 14
|
||||||
|
executors; haiku = status-reporter. Unpinned = interviewer,
|
||||||
|
client-handover-writer (inline-load only).
|
||||||
|
- Two execution modes with OPPOSITE tier semantics: Agent() dispatch →
|
||||||
|
frontmatter pin applies; inline-load ("you become it") → pin INERT, runs on
|
||||||
|
session model. 20 inline-load sites exist.
|
||||||
|
- Target policy (user directive): Fable does ONLY main-loop orchestration +
|
||||||
|
reflection on plan/solution. Everything dispatched runs opus (deep judgment)
|
||||||
|
/ sonnet (standard execution) / haiku (mechanical) by ACTUAL task
|
||||||
|
complexity. Agents mixing classes get split. Skills adapted. Zero loss, zero
|
||||||
|
regression.
|
||||||
|
|
||||||
|
## KEY COMPONENTS — per-agent verdict vs target
|
||||||
|
|
||||||
|
### Fits, no change
|
||||||
|
| agent | tier | note |
|
||||||
|
|---|---|---|
|
||||||
|
| plan-challenger | opus | coherent monolith; verdict grammar + PROOF load-bearing |
|
||||||
|
| feater / bugfixer / hotfixer | sonnet | closed-plan executors; NEED-DECISION / BLOCKED valves |
|
||||||
|
| security-auditor | sonnet | deterministic SAST gate; `SECURITY — VERDICT:` grammar |
|
||||||
|
| scaffolder | sonnet (effort: high) | but see INERT-PIN below — never dispatched today |
|
||||||
|
| status-reporter | haiku | exemplar mechanical |
|
||||||
|
| client-handover-writer | none (inline orchestrator) | one haiku-able seam: STEP 1-2 git/context preflight |
|
||||||
|
| interviewer | none (inline) | INTERACTIVE — asks user inline; a dispatched agent cannot ask (uniform ban). Structurally main-loop. |
|
||||||
|
|
||||||
|
### Tier-down candidates (no split)
|
||||||
|
| agent | current → candidate | evidence |
|
||||||
|
|---|---|---|
|
||||||
|
| validator-analyzer | opus → sonnet | NOT mixed: runs external validators (authoritative), fixed severity tables, base-100 deduction scoring, allowlist-driven fix bundle; ambiguity punted to user §6. No deep judgment present. (sub) |
|
||||||
|
| onboarder | sonnet → haiku candidate | template-fill + conditional writes; only light stack-block filtering. (sub) Also inert-pin today. |
|
||||||
|
| release-executor | sonnet (keep, borderline) | mostly script runs + CHANGELOG templating, but carries a NEED-DECISION judgment valve (MAJOR-bump wording). (sub) |
|
||||||
|
|
||||||
|
### Split candidates (mixed classes inside one body)
|
||||||
|
| agent | geometry (factual boundary) | complication |
|
||||||
|
|---|---|---|
|
||||||
|
| seo-analyzer | collection (STEP 2-5 curls/CWV/GSC/greps → haiku-class) / judgment (STEP 6-11 sampling, competitive, scoring, triage → opus) / templating (STEP 12-14 bundle+report → sonnet/haiku) | BDR-061: no Agent tool in analyzers (single-dispatch doctrine) → a split must be ORCHESTRATED BY THE SKILL at L1 with disk handoffs, or BDR-061 revised (nesting works ≥2.1.172 per BDR-060, but version-robust-by-design was chosen). seo-data.test.sh locks `fetch.sh` wiring strings IN the agent body (6 locks). STEP 1-2 context feeds every later step → large LRN-126 contract surface. |
|
||||||
|
| geo-analyzer | identical 3-way geometry | same complications; shares severity vocab + sentinel |
|
||||||
|
| commit-changer | MODE propose (narrative reconstruction + capitalize routing = deep) / MODE apply (stage+commit = mechanical) — boundary ALREADY exists as dispatch modes | 2 dispatch sites in /commit-change; per-dispatch `model=` override is an available lighter mechanism than a file split |
|
||||||
|
| doc-syncer | drift detection + semantic doc-type analysis + MINOR/SIGNIFICANT calls (deep) / discovery + template render + PATCHED_FILES emit (mechanical) | 9 consumers on BOTH modes: dispatched ×2 (/doc, onboard) + inline-load ×7 (bugfix, hotfix, feat, init-project ×2, ship-feature, scaffolder) — LRN-125 dual-use-across-tiers hazard; runs its own user validation gate (STEP 8) → gate must be hoisted before any dispatch conversion |
|
||||||
|
| handover-doc-writer | synthesis/vulgarization STEP 10-12 (deep) / render+deterministic gates STEP 13-16 (mechanical) | skill-leak ban list + `HANDOVER-DOC REPORT` grammar must survive |
|
||||||
|
| plugin-advisor | detection PHASE 1 (mechanical) / complexity scoring + decision-table reasoning PHASE 2.5 (deep) | INERT PIN: inline-loaded ×4 (plugin-check, onboard, init-project, ship-feature), NEVER dispatched — sonnet pin is dead config; PHASE 4 asks the user (inline-only capability) |
|
||||||
|
| verifier | STEP 2 evidence adjudication = deep judgment inside a sonnet procedural gate | BDR-066 kept sonnet DELIBERATELY (oracle-anchored to contract, ≤3×/loop). Tier-up = design arbitrage, not a mechanical fix. contract-verifier.test.sh locks name/tools/body (33 asserts). |
|
||||||
|
|
||||||
|
### INERT-PIN finding (structural gap vs target)
|
||||||
|
scaffolder, onboarder, plugin-advisor are pinned sonnet but NEVER dispatched —
|
||||||
|
inline-load only → they run on Fable today. doc-syncer's doc-commit steps
|
||||||
|
(bugfix/hotfix/feat/init-project/ship-feature/scaffolder) also run inline on
|
||||||
|
Fable. Under the target policy these are EXECUTION tasks burning Fable — a
|
||||||
|
bigger real gap than any pin value. Each inline→dispatch conversion must hoist
|
||||||
|
its user gates into the dispatcher first (dispatched agents cannot ask).
|
||||||
|
|
||||||
|
## CONSUMER MAP (summary; full tables in the dispatch-map sweep)
|
||||||
|
|
||||||
|
- ~50 Agent() dispatch sites across 20 skills + 2 lib includes +
|
||||||
|
client-handover-writer (9 internal dispatches, incl. skills-via-general-purpose).
|
||||||
|
- 20 inline-load sites (7× doc-syncer, 4× plugin-advisor, 3× analyzer, 2×
|
||||||
|
interviewer, 1× each onboarder/scaffolder/client-handover-writer/refactorer).
|
||||||
|
- Includes: model-gate.md ×15 skills (+5 locked EXCLUDED), challenge-plan.md
|
||||||
|
×12, verify-secure-loop.md ×5, contract-interview ×5, capitalize-commit ×6,
|
||||||
|
doc-commit ×6.
|
||||||
|
- ~30 prose refs claim current tiers (sonnet-pinned X, opus-pinned Y, BDR-066/
|
||||||
|
BDR-076 citations) → all go stale on tier changes (LRN-113 sweep required).
|
||||||
|
- Only onboard uses explicit `model="opus"` dispatch params (7 sites); every
|
||||||
|
typed agent relies on frontmatter pin; ship-feature/init-project mandate
|
||||||
|
`model: "sonnet"` on SDD subagents by prose.
|
||||||
|
|
||||||
|
## CONSTRAINTS (zero-loss bar)
|
||||||
|
|
||||||
|
1. Verbatim machine-parsed grammars must survive verbatim: `VERIFY — VERDICT:
|
||||||
|
CONFORME | ECARTS(n) | ERROR(<reason>)`, `SECURITY — VERDICT: PASS |
|
||||||
|
BLOCK(n) | ERROR(<reason>)`, `CHALLENGE — LENS: … — VERDICT: SOLID |
|
||||||
|
CONCERNS(n) | FATAL(n)`, mandatory `PROOF:` lines, sentinel `READY TO APPLY
|
||||||
|
— awaiting dispatcher confirmation`, `<NAME>-EXEC REPORT` + `STATUS : DONE
|
||||||
|
| NEED-DECISION | BLOCKED`, `PATCHED_FILES:`, `COMMIT PLAN`, labeled score
|
||||||
|
lines parsed by client-handover extractors, `HANDOVER-DOC REPORT`.
|
||||||
|
2. BDR-050 + LRN-083: loops + decisions live in the MAIN loop; gates dispatched
|
||||||
|
fresh, blind, zero iteration history. Splits must not move loop decisions
|
||||||
|
into children.
|
||||||
|
3. BDR-061: seo/geo/validator have no Agent tool by doctrine (version-robust
|
||||||
|
single dispatch level). Any intra-audit split is skill-orchestrated at L1
|
||||||
|
unless BDR-061 is explicitly revised.
|
||||||
|
4. LRN-126: every implicit data path (ARGUMENTS flags, detected vars, STEP-N
|
||||||
|
side outputs) must cross the new handoff contracts explicitly; census-style
|
||||||
|
tests will NOT catch severed wires — a data-flow read per split is required.
|
||||||
|
5. LRN-125: no dual-use agent across tiers; audit consumer routes to the
|
||||||
|
judgment agent, execution consumer to the executor.
|
||||||
|
6. Interactivity: dispatched agents cannot ask the user. All human gates
|
||||||
|
(AskUserQuestion / inline approval) stay in main loop or inline-loaded
|
||||||
|
orchestrators. doc-syncer STEP 8 + plugin-advisor PHASE 4 gates must be
|
||||||
|
hoisted before dispatch conversion.
|
||||||
|
7. Test locks (fire on this refactor): model-routing (~61, epicenter — pins,
|
||||||
|
dispatch strings, gate wiring loops, `model="opus"` literals, BDR-076 token),
|
||||||
|
plan-challenger (~43 — frontmatter, grammar, challenge-plan doctrine
|
||||||
|
sentences incl. BDR-066 token), loops-light (40 — verify-secure-loop 10
|
||||||
|
sentences, sonnet pins, report grammars, "Agent" ABSENT from
|
||||||
|
bugfixer/hotfixer — substring-fragile), contract-verifier (33),
|
||||||
|
security-auditor (31), seo-data (6 body-wiring locks on seo/geo bodies),
|
||||||
|
loops-heavy (19 skill prose), review-guards G3 (strict YAML on every agent
|
||||||
|
file incl. new ones), no-vacuous-locks (no `\n` in new lock patterns —
|
||||||
|
LRN-093), model-check (10 — tier vocabulary big/small; a new tier taxonomy
|
||||||
|
must co-evolve witness + test). Census `for`-loops (model-routing:13-19,
|
||||||
|
plan-challenger:42) must be edited for any new/renamed gated skill.
|
||||||
|
8. model-gate.md prose has NO deterministic lock (include-path only) — free to
|
||||||
|
rewrite, but behavioral-only verification.
|
||||||
|
9. Gitflow: feature branch(es) via gitflow.sh; no merge without human signal.
|
||||||
|
Unmerged branches in flight: `feature/opus-pin-audit-agents` (this refactor
|
||||||
|
supersedes/absorbs it), `bugfix/seo-geo-integrity` (10 commits touching the
|
||||||
|
seo surface → sequencing/conflict risk with a seo-analyzer split).
|
||||||
|
10. BDR-076 survival: opus tier for judgment agents survives as baseline;
|
||||||
|
validator-analyzer's opus pin would be superseded (tier-down); seo/geo pins
|
||||||
|
refined by splits; challenge-plan/plan-challenger doctrine text + census
|
||||||
|
§11 rewritten again.
|
||||||
|
|
||||||
|
## RISKS
|
||||||
|
|
||||||
|
- Severed implicit data paths on splits (LRN-126 precedent: 2 silent input
|
||||||
|
losses caught only by whole-branch review) — probability: HIGH without a
|
||||||
|
per-split data-flow pass.
|
||||||
|
- Consumer staleness (LRN-113): ~30 prose refs + 9 identical gate preambles +
|
||||||
|
2 census loops — partial sweep leaves contradictory doctrine — probability:
|
||||||
|
HIGH without whole-surface grep + new guards.
|
||||||
|
- Lost human gates on inline→dispatch conversions (doc-syncer STEP 8,
|
||||||
|
plugin-advisor PHASE 4) — probability: MEDIUM-HIGH; hoist-first pattern
|
||||||
|
exists (BDR-066 wave 4 did exactly this for client-handover).
|
||||||
|
- Census under-coverage: NEW agent files are silently unlocked unless
|
||||||
|
model-routing/census extended per agent (worse than a red) — MEDIUM.
|
||||||
|
- haiku reliability on long tool chains (seo/geo collection legs: GSC, CWV,
|
||||||
|
curl loops, retry policies): only haiku precedent is status-reporter
|
||||||
|
(short, deterministic) — MEDIUM; unproven.
|
||||||
|
- Split overhead: 3-dispatch audit pipeline re-serializes STEP 1-2 context per
|
||||||
|
child; latency + token duplication vs today's monolith — MEDIUM.
|
||||||
|
- Merge sequencing with `bugfix/seo-geo-integrity` (10 commits on seo surface)
|
||||||
|
— MEDIUM.
|
||||||
|
- Subagent-report trust (LRN-132): (sub)-marked classifications need spot
|
||||||
|
re-verification during design — MEDIUM.
|
||||||
|
|
||||||
|
## OPEN QUESTIONS (design arbitrage needed)
|
||||||
|
|
||||||
|
1. verifier: keep sonnet (BDR-066 oracle-anchored rationale) or lift to opus
|
||||||
|
(STEP 2 adjudication is the correctness gate)?
|
||||||
|
2. seo/geo split mechanics: skill-orchestrated L1 pipeline (BDR-061-compatible)
|
||||||
|
vs nested dispatch inside the analyzer (requires revising BDR-061;
|
||||||
|
version floor OK per BDR-060)?
|
||||||
|
3. Which inline-loads convert to dispatches (scaffolder, onboarder, doc-syncer
|
||||||
|
doc-commit steps, plugin-advisor detection) vs stay inline as reflection?
|
||||||
|
4. commit-changer: file split vs per-mode `model=` override at the 2 existing
|
||||||
|
dispatch sites?
|
||||||
|
5. haiku scope: which mechanical halves actually go haiku vs sonnet, given the
|
||||||
|
reliability unknown on long tool chains?
|
||||||
|
6. Gate taxonomy: keep binary big/small model-gate (guards main loop only) or
|
||||||
|
extend model-check.sh to the full 4-tier vocabulary?
|
||||||
|
7. Sequencing: land/absorb `feature/opus-pin-audit-agents` and
|
||||||
|
`bugfix/seo-geo-integrity` before or during this refactor?
|
||||||
|
|
||||||
|
## DESIGN AMENDMENT (2026-07-19, user arbitrage — supersedes open questions)
|
||||||
|
|
||||||
|
User approved all 7 recommendations, PLUS one addition:
|
||||||
|
|
||||||
|
**No-inherit rule + fable pins.** No dispatched agent may inherit the session
|
||||||
|
model anywhere. Every dispatch site carries an explicit tier: typed agents via
|
||||||
|
frontmatter pin (`model: fable|opus|sonnet|haiku`), built-ins
|
||||||
|
(general-purpose / Explore / Plan) via a `model=` param at EVERY call site.
|
||||||
|
Rationale: sessions may run on another model (gate admits Opus; user may
|
||||||
|
launch anything) — inheritance would silently mis-tier dispatched work.
|
||||||
|
`model="fable"` lands where a dispatched child performs REFLECTION /
|
||||||
|
ORCHESTRATION on behalf of the main loop:
|
||||||
|
- client-handover-writer's 8 internal general-purpose skill-runner dispatches
|
||||||
|
(/seo, /harden, /cso, /commit-change, /web-validate runs) — today they
|
||||||
|
inherit; they host gated orchestration → `model="fable"`.
|
||||||
|
- Doctrine line (model-gate.md or routing doctrine): ad-hoc reflection
|
||||||
|
dispatches from the main loop (Explore digest, Plan, general-purpose) carry
|
||||||
|
`model="fable"`; non-reflection ad-hoc dispatches carry their complexity
|
||||||
|
tier. New census locks accordingly.
|
||||||
|
- No TYPED agent moves to fable tier (plan-challenger/analyzer stay opus per
|
||||||
|
approved verdicts). Inline-loads that remain (interviewer,
|
||||||
|
client-handover-writer, analyzer-in-/analyze + DEBUG, init STEP 2) ARE the
|
||||||
|
main loop — covered by model-gate, not pins.
|
||||||
|
- External/gstack skills with inheriting general-purpose dispatches
|
||||||
|
(design-shotgun, review, graphify) — external ownership (BDR-015 class):
|
||||||
|
covered by doctrine, not edited, unless owned locally. Verify ownership at
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
## TARGET MODEL MAP — ship-feature (example, per-step)
|
||||||
|
|
||||||
|
| Step | What runs | Where | Model (target) | Δ vs today |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| MODEL GATE | witness + self-check | main loop | session (Fable; Opus admitted) | — |
|
||||||
|
| 0 plugin check | detection probes | dispatched (plugin-advisor detection half) | haiku | today inline on session |
|
||||||
|
| 0 plugin check | complexity scoring + reco | dispatched (advisor judgment half) | opus | today inline on session |
|
||||||
|
| 0 plugin check | apply gate (user) | main loop | Fable | — |
|
||||||
|
| 0b/0c context + ctx7 | trivial bash probes | main loop | Fable (trivial) | — |
|
||||||
|
| 0d read-before digest | analyzer | dispatched | opus | pinned (BDR-076) |
|
||||||
|
| 0e contract | contract-interview + micro-gates | main loop | Fable | — |
|
||||||
|
| 1 brainstorm | superpowers:brainstorming | main loop | Fable | — |
|
||||||
|
| 2 plan | superpowers:writing-plans | main loop | Fable | — |
|
||||||
|
| 2b challenge | 3× plan-challenger | dispatched | opus | pinned |
|
||||||
|
| 2b synthesis + RE-THINK | severity merge, plan revision | main loop | Fable | — |
|
||||||
|
| 3 validation gate | human gate | main loop | Fable | — |
|
||||||
|
| 4 SDD implement | per-task implementers + reviewers | dispatched | sonnet (explicit `model:"sonnet"`) | — |
|
||||||
|
| 4 task decomposition / verdict arbitration | SDD driver | main loop | Fable | — |
|
||||||
|
| 4b error diagnosis | analyzer DEBUG (inline) | main loop | Fable (reflection on the solution) | — |
|
||||||
|
| 5 verify + secure | verifier, security-auditor (fresh) | dispatched | sonnet | — |
|
||||||
|
| 5 loop decisions | ECARTS/BLOCK routing | main loop | Fable | — |
|
||||||
|
| 6 code review | reviewer (superpowers) | dispatched | **opus explicit** | today INHERITS (leak) |
|
||||||
|
| 7 capitalize | registry gate + commit | main loop | Fable | — |
|
||||||
|
| 8 doc sync | doc-syncer | dispatched | sonnet | today INLINE on session |
|
||||||
|
| 9 finish | gitflow + human go | main loop | Fable | — |
|
||||||
|
|
||||||
|
## TARGET MODEL MAP — init-project (example, per-step)
|
||||||
|
|
||||||
|
| Step | What runs | Where | Model (target) | Δ vs today |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| MODEL GATE | witness + self-check | main loop | session (Fable; Opus admitted) | — |
|
||||||
|
| 0 plugin check | detection / scoring / gate | dispatched haiku / dispatched opus / main loop Fable | (as ship-feature) | today inline |
|
||||||
|
| 1 interview | interviewer (interactive Q&A) | main loop (inline — a dispatched agent cannot ask) | Fable | structural |
|
||||||
|
| 1 contract | contract-interview | main loop | Fable | — |
|
||||||
|
| 2 analyze brief | analyzer (inline — greenfield design reflection) | main loop | Fable | stays inline |
|
||||||
|
| 3 design | superpowers:brainstorming | main loop | Fable | — |
|
||||||
|
| 4 gate #1 + contract enrich | human gate | main loop | Fable | — |
|
||||||
|
| 5 scaffold | scaffolder | **dispatched** | sonnet (effort: high) | today INLINE on session — pin inert |
|
||||||
|
| 5b readme bootstrap | doc-syncer | **dispatched** | sonnet | today INLINE |
|
||||||
|
| 5c/5e/5f ctx7 + anim + gitflow init | deterministic bash | main loop | Fable (trivial) | — |
|
||||||
|
| 6 plan | superpowers:writing-plans | main loop | Fable | — |
|
||||||
|
| 6b challenge + synthesis | 3× plan-challenger / merge | dispatched opus / main loop Fable | — | pinned |
|
||||||
|
| 7 gate #2 | human gate | main loop | Fable | — |
|
||||||
|
| 8 SDD implement | implementers + reviewers | dispatched | sonnet | — |
|
||||||
|
| 8b graphify | bash | main loop | Fable (trivial) | — |
|
||||||
|
| 9 verify + secure | verifier, security-auditor | dispatched | sonnet | — |
|
||||||
|
| 10 code review | reviewer | dispatched | **opus explicit** | today INHERITS (leak) |
|
||||||
|
| 10b capitalize founding BDRs | registry gate | main loop | Fable | — |
|
||||||
|
| 10c doc sync | doc-syncer | **dispatched** | sonnet | today INLINE |
|
||||||
|
| 11 finish | gitflow + human go | main loop | Fable | — |
|
||||||
|
|
||||||
|
## RELATED MEMORY
|
||||||
|
|
||||||
|
- IN FORCE: BDR-066 — model routing waves 1-4 — the architecture being
|
||||||
|
re-tiered; its rationale table is the baseline [accepted]. BDR-076 — opus
|
||||||
|
pins on dispatched judgment — starting state, partially superseded by the
|
||||||
|
new target [accepted, this branch]. BDR-050 — verify+secure loops in main
|
||||||
|
loop, gates fresh [accepted]. BDR-049 — verifier fresh+blind+disk-contract
|
||||||
|
[accepted]. BDR-048 — pinned semgrep gate [accepted]. BDR-061 — fix-bundle
|
||||||
|
→ L1 apply, analyzers have no Agent tool [accepted]. BDR-060 — nested
|
||||||
|
dispatch floor v2.1.172 [accepted]. BDR-075+amendment — challenge phase in
|
||||||
|
12 orchestrators [accepted]. BDR-025 — unknown never silently passes
|
||||||
|
[accepted]. BDR-022 — doc-syncer never touches .claude/ [accepted].
|
||||||
|
LRN-125 — no dual-use across tiers. LRN-126 — splits sever implicit data
|
||||||
|
paths; forward every consumed field. LRN-113 — whole-surface sweep + guard.
|
||||||
|
LRN-083 — loops in main loop. LRN-093 — no `\n` in grep locks. LRN-096 —
|
||||||
|
flip-test new guards. LRN-112 — nesting supported. LRN-105/107 — explicit
|
||||||
|
tool bans in read-only mandates. LRN-011 — one subagent, N gated scores
|
||||||
|
(alternative to 3-way split). LRN-057 — match mechanism to consumer.
|
||||||
|
LRN-102 — final-text-only rendering guarantee. LRN-132 — subagent claims
|
||||||
|
need verification.
|
||||||
|
- ALREADY SEEN: BLK-004 — renamed/deleted agent files broke a consumer wrapper
|
||||||
|
[resolved] (rename sweep discipline). EVAL-023 — BDR-066 post-merge ronde
|
||||||
|
found 5 edge gaps [done] (plan a ronde here too). EVAL-026 — 3-way plan
|
||||||
|
challenge caught 4 real BLOCKERs on its own plan [done] (run it on this
|
||||||
|
refactor's plan).
|
||||||
|
- NON-BINDING: ~200 remaining headings surfaced nothing binding beyond the
|
||||||
|
above — BDR-067/068/069 (release/permissions), LRN-first-100 (tooling),
|
||||||
|
BLK-005..017 (env) — counted, not detailed.
|
||||||
|
- SELECTION: scanned ~230 headings — surfaced 28 = in-force 22 + seen 3 +
|
||||||
|
non-binding (counted).
|
||||||
@@ -0,0 +1,295 @@
|
|||||||
|
# PLAN: model-tiering v2 — full framework re-tier + splits
|
||||||
|
|
||||||
|
Input: `.claude/tasks/plans/2026-07-19-model-tiering-v2-analysis.md` (read it
|
||||||
|
first — consumer map, test locks, LRN/BDR constraints live there).
|
||||||
|
User arbitrage (2026-07-19): 7 recos approved + no-inherit/fable-pin amendment
|
||||||
|
+ Fable scope = REFLECTION / ORCHESTRATION / PLANNING / LOGIC only.
|
||||||
|
|
||||||
|
## D0 — DOCTRINE (end state)
|
||||||
|
|
||||||
|
1. Main loop (session model, gated big by model-gate) keeps ONLY: brainstorm,
|
||||||
|
plan, contract, loop decisions, gate arbitration, human interaction,
|
||||||
|
conversation-context work (capitalize), trivial glue bash (<~1k tokens).
|
||||||
|
Retention criteria (any suffices): interactive | needs conversation context
|
||||||
|
| orchestration decision | dispatch overhead > step cost.
|
||||||
|
2. NOTHING dispatched inherits. Typed agents: frontmatter pin. Built-ins
|
||||||
|
(general-purpose/Explore/Plan): explicit `model=` at EVERY call site.
|
||||||
|
VERIFIED (2026-07-19 spike, closes robustness BLOCKER): `model: "fable"`
|
||||||
|
on a dispatch resolves to claude-fable-5 at runtime (echo spike via
|
||||||
|
general-purpose); the harness enum-validates the `model` param — an
|
||||||
|
invalid value fails LOUDLY (InputValidationError), no silent fallback.
|
||||||
|
Call-site `model=` takes precedence over a typed agent's frontmatter pin
|
||||||
|
(documented Agent-tool contract); fallback direction if a call site omits
|
||||||
|
it = the frontmatter pin, i.e. today's behavior — fail-safe, never worse.
|
||||||
|
3. Tiers: fable = dispatched reflection-on-behalf-of-main-loop (skill-runner
|
||||||
|
children ONLY); opus = deep judgment (audit scoring, plan critique, drift
|
||||||
|
semantics, review, synthesis); sonnet = standard execution from closed
|
||||||
|
instructions + collectors AND probes (wave-1 prudence — robustness MAJOR:
|
||||||
|
plugin PHASE 1 is a ~26-call branching bash chain, not a short probe);
|
||||||
|
haiku = status-reporter ONLY in wave 1; haiku expansion = wave 2 after
|
||||||
|
reliability proven per candidate.
|
||||||
|
4. Grammars/sentinels/valves survive VERBATIM (list in analysis §CONSTRAINTS).
|
||||||
|
Loops/gates stay in main loop (BDR-050/LRN-083). Fix-bundle → L1 apply
|
||||||
|
(BDR-061) preserved: audit agents never get the Agent tool.
|
||||||
|
5. Every split: LRN-126 data-flow pass (enumerate child-read fields vs
|
||||||
|
parent-set; explicit handoff contract on disk or in prompt) PLUS an
|
||||||
|
IN-WAVE planted-input smoke proving the fields cross the dispatch boundary
|
||||||
|
at runtime — the smoke GATES that wave's merge (confirmation MAJOR:
|
||||||
|
enumeration is design-time reading; census can't catch severed wires; a
|
||||||
|
split must never reach develop empirically unproven). Every change:
|
||||||
|
LRN-113 whole-surface sweep + census lock + flip-test (LRN-096, no `\n` in
|
||||||
|
patterns LRN-093, strict YAML G3).
|
||||||
|
|
||||||
|
## D1 — AGENT END STATE
|
||||||
|
|
||||||
|
Pins (frontmatter):
|
||||||
|
- opus: analyzer, plan-challenger, seo-judge*, geo-judge*, doc-auditor*,
|
||||||
|
plugin-reasoner*, handover-synthesizer* (*new, from splits)
|
||||||
|
- sonnet: feater, bugfixer, hotfixer, code-cleaner, refactorer, verifier,
|
||||||
|
security-auditor, scaffolder (effort high), onboarder, release-executor,
|
||||||
|
commit-changer, doc-syncer (patcher half), validator-analyzer (TIER-DOWN
|
||||||
|
from opus), seo-worker*, geo-worker* (2-way split per domain — simplicity
|
||||||
|
MAJOR: collector+templater both sonnet in wave 1 → one worker file with
|
||||||
|
`MODE: collect | template`, no cross-domain share: domain bodies genuinely
|
||||||
|
diverge), handover-renderer* (renamed handover-doc-writer render half),
|
||||||
|
plugin-probe* (wave-1 prudence; haiku candidate wave 2)
|
||||||
|
- haiku: status-reporter (only)
|
||||||
|
- none (inline-only, main loop, gate-protected): interviewer,
|
||||||
|
client-handover-writer
|
||||||
|
Per-dispatch `model=` overrides (no new file): commit-changer propose=opus /
|
||||||
|
apply=sonnet (2 sites in /commit-change — precedence over the sonnet
|
||||||
|
frontmatter pin is the documented Agent-tool contract, verified direction
|
||||||
|
D0.2; the pin stays as the no-inherit fallback = today's behavior; both
|
||||||
|
call-site strings census-locked + W3 behavioral smoke); SDD
|
||||||
|
implementers+reviewers
|
||||||
|
sonnet (already prose-mandated → make it a census lock); code-review steps
|
||||||
|
(ship-feature 6, init-project 10) = opus explicit; client-handover-writer's 8
|
||||||
|
general-purpose skill-runners = fable; onboard's 7 general-purpose = opus
|
||||||
|
(keep); any Explore/Plan ad-hoc reflection dispatch = fable (doctrine line in
|
||||||
|
model-gate.md + CLAUDE.global routing note).
|
||||||
|
|
||||||
|
Splits (each = new agent file(s) + handoff contract + census + consumers):
|
||||||
|
S1 plugin-advisor → plugin-probe (SONNET wave 1; PHASE 1 CLI probes → PROBE
|
||||||
|
REPORT) + plugin-reasoner (opus; PHASE 2/2.5 scoring + reco → PLUGIN CHECK
|
||||||
|
block). PHASE 3-4 report+apply-gate HOISTED into ONE shared include
|
||||||
|
`lib/plugin-gate.md` (simplicity MINOR — doc-commit.md ×6 pattern, never
|
||||||
|
4 hand-copies), referenced by the 4 consumers (plugin-check, onboard
|
||||||
|
STEP 0, init-project STEP 0, ship-feature STEP 0) — main loop. The
|
||||||
|
pre-recommendation validation checkpoint (advisor :201-212, straddles the
|
||||||
|
seam, can skip PHASE 4) runs IN THE CONSUMER between the two dispatches
|
||||||
|
(correctness MINOR); its inputs (toggle-external availability,
|
||||||
|
project-signal presence) are PROBE REPORT fields. Handoff: PROBE REPORT
|
||||||
|
fields = plugin list, toggle state, profile, CLI/anim/monorepo/embedded
|
||||||
|
signals + checkpoint inputs (enumerate ALL PHASE-2-read fields).
|
||||||
|
S2 doc-syncer → doc-auditor (opus; STEP 3-4 drift + semantic analysis + A3
|
||||||
|
MINOR/SIGNIFICANT call w/ doc-shape.sh oracle → DRIFT REPORT [AUTO]/
|
||||||
|
[HUMAN] items) + doc-syncer (sonnet; render/patch half, keeps
|
||||||
|
PATCHED_FILES: grammar + BDR-022 bans). Validation gate stays in
|
||||||
|
DISPATCHER (/doc skill, orchestrator steps) — auto-mode flows: auditor →
|
||||||
|
dispatcher applies AUTO via doc-syncer → SIGNIFICANT escalates inline.
|
||||||
|
Consumers rerouted: /doc, onboard, + doc-commit steps in bugfix/hotfix/
|
||||||
|
feat/init-project(×2)/ship-feature (inline→dispatch conversion) +
|
||||||
|
scaffolder PHASE 6 (scaffolder DISPATCHES nothing — it has no Agent tool:
|
||||||
|
README bootstrap moves to init-project STEP 5b dispatch of doc-syncer).
|
||||||
|
PLUS (robustness MAJOR): rework `lib/doc-commit.md`'s in-thread contract
|
||||||
|
BEFORE converting any doc-commit site — it requires the orchestrator to
|
||||||
|
"hold the patch context" to compose the rc-0 CHANGE SUMMARY (the review
|
||||||
|
surface that replaced the removed MINOR gate). Dispatched doc-syncer adds
|
||||||
|
a `CHANGE SUMMARY` block to its report grammar (per patched file: what
|
||||||
|
changed and why, ≤1 line each); doc-commit.md's composer consumes THAT
|
||||||
|
instead of in-thread context; census-locks the new field + a planted-input
|
||||||
|
smoke proves the summary crosses the dispatch boundary.
|
||||||
|
S3 seo-analyzer → 2-WAY (simplicity MAJOR — 3-way was YAGNI while collector
|
||||||
|
and templater share the sonnet tier; commit-changer mode-precedent):
|
||||||
|
seo-worker (sonnet; `MODE: collect` = STEP 2-5 signals → SIGNALS file;
|
||||||
|
`MODE: template` = STEP 12-14 FIX BUNDLE + sentinel + SEO.md + envelope)
|
||||||
|
+ seo-judge (opus; STEP 6-11 sampling judgment, competitive, scoring /20,
|
||||||
|
trajectory, triage → FINDINGS+PLAN). Orchestrated by /seo at L1 (BDR-061
|
||||||
|
conserved: no Agent tool in either). Wave-2 option: carve `MODE: collect`
|
||||||
|
into a haiku file once proven — the mode boundary IS the future cut line.
|
||||||
|
HANDOFF (robustness MAJOR — freshness/atomicity): run-scoped paths
|
||||||
|
`.audit/seo-signals-<RUNID>.md` / `.audit/geo-signals-<RUNID>.md` —
|
||||||
|
`.audit/` is the GITIGNORED derived-artifact tree (confirmation MINOR,
|
||||||
|
LRN-124: a crash-stranded transient with scraped GSC/competitor content
|
||||||
|
must never be committable; `.claude/audits/` keeps only the SEO.md/GEO.md
|
||||||
|
deliverables). RUNID minted by the dispatcher per run, passed to every
|
||||||
|
stage; the file ENDS with `COLLECTION COMPLETE — RUNID: <id>` and the
|
||||||
|
judge FAILS CLOSED (report ERROR, never score) if the file is absent,
|
||||||
|
RUNID mismatches, or the completeness sentinel is missing; dispatcher
|
||||||
|
cleans the file post-run.
|
||||||
|
DISPATCHER CONTRACT (confirmation MAJOR — fail-closed at the judge must
|
||||||
|
not fail OPEN at the pipeline): on a judge ERROR the orchestrator
|
||||||
|
(/seo /geo /harden /onboard) STOPS — no template dispatch, no L1 apply —
|
||||||
|
surfaces the ERROR verbatim, retries ONCE with a fresh collect+judge,
|
||||||
|
then escalates to the human. A mute or ERROR judge is NEVER carried into
|
||||||
|
templating (verify-secure-loop discipline). This handler is part of the
|
||||||
|
W5 skill rewrites, census-locked.
|
||||||
|
Explicit field list per LRN-126 (STEP 1-2 business+tech context consumed
|
||||||
|
by ALL later steps — full enumeration REQUIRED before cutting).
|
||||||
|
seo-data.test.sh locks (fetch.sh wiring) move with the worker body —
|
||||||
|
update suite same commit.
|
||||||
|
S4 geo-analyzer → geo-worker (sonnet, 2 modes) + geo-judge (opus) — mirror of
|
||||||
|
S3 incl. run-scoped `.audit/geo-signals-<RUNID>.md` + the same dispatcher
|
||||||
|
ERROR contract. No cross-domain file share:
|
||||||
|
seo vs geo bodies genuinely diverge (different checks, scoring blocks,
|
||||||
|
envelopes) — that divergence, not LRN-125, is the reason.
|
||||||
|
S5 handover-doc-writer → handover-synthesizer (opus; STEP 9 memory-registry
|
||||||
|
load + STEP 10 phase clustering + STEP 12 6-chapter synthesis — STEP 9
|
||||||
|
allocated here, it feeds the synthesis; correctness MINOR) +
|
||||||
|
handover-renderer (sonnet; STEP 13-16 annex render, precheck apply,
|
||||||
|
deterministic gates, HTML/PDF). client-handover-writer dispatches
|
||||||
|
synthesizer then renderer; PACKAGE contract split per LRN-126
|
||||||
|
(re-enumerate DEPLOY_HINTS/--skip-seo class fields — the EXACT prior
|
||||||
|
failure). W4 MUST same-commit relock model-routing.test.sh:52-55 (the
|
||||||
|
handover-doc-writer name + dispatch-string locks break on the rename;
|
||||||
|
"make test green per wave" D4 invariant — correctness MINOR).
|
||||||
|
Tier-downs (no split): validator-analyzer opus→sonnet (deterministic
|
||||||
|
validators+tables). onboarder stays sonnet wave 1 (haiku candidate wave 2).
|
||||||
|
release-executor stays sonnet (NEED-DECISION valve).
|
||||||
|
Verifier: STAYS sonnet (approved — oracle-anchored gate).
|
||||||
|
|
||||||
|
## D2 — SKILL MAP (main loop = session model; every dispatch tier explicit)
|
||||||
|
|
||||||
|
Gated reflection skills (model-gate kept, 15):
|
||||||
|
- ship-feature / init-project: per the two example maps in the analysis file
|
||||||
|
(amendment section) + S1 gate hoist at STEP 0 + doc-commit conversions.
|
||||||
|
- feat: scope/plan/contract/loop = main; challenge 3× plan-challenger opus;
|
||||||
|
feater sonnet; verifier+security sonnet; doc-commit → doc-auditor opus +
|
||||||
|
doc-syncer sonnet dispatch; commit via /commit-change (propose opus / apply
|
||||||
|
sonnet).
|
||||||
|
- bugfix: investigation/diagnosis/contract = main (reflection); challenge
|
||||||
|
opus (3b); bugfixer sonnet; verifier+security sonnet; doc-commit as feat.
|
||||||
|
- hotfix: LOCATE + guard = main (logic); challenge opus when guard fires;
|
||||||
|
hotfixer sonnet; security gate sonnet (revert-not-loop conserved);
|
||||||
|
doc-commit as feat.
|
||||||
|
- analyze: analyzer INLINE = main loop (it IS the reflection) — unchanged.
|
||||||
|
- code-clean: PHASE 1 audit inline = main (audit judgment feeding a human
|
||||||
|
gate); code-cleaner sonnet PHASE 2 (hosts refactorer inline at SAME tier —
|
||||||
|
LRN-125 OK); re-audit sonnet inside executor.
|
||||||
|
- seo / geo: skill = orchestration + GATED arbitrage (main); pipeline
|
||||||
|
collector sonnet → judge opus → templater sonnet (L1 serial); appliers
|
||||||
|
hotfixer/feater sonnet at L1; build-verify inline.
|
||||||
|
- web-validate: validator-analyzer sonnet; hotfixer applier sonnet; loop main.
|
||||||
|
- harden: audit dispatch follows S3 narrow-scope path (seo-judge opus on
|
||||||
|
harden axes w/ collector reuse); direct-Edit apply stays inline (tiny
|
||||||
|
scope, BDR-061 carve-out conserved).
|
||||||
|
- audit-delta: axis audits dispatched opus (delta judgment); security-auditor
|
||||||
|
sonnet; fix gate + markers = main.
|
||||||
|
- tour: orchestration main; security-auditor sonnet; cleanup audit = analyzer
|
||||||
|
opus (or general-purpose model="opus"); fixes via sonnet appliers; doc axis
|
||||||
|
→ S2 pipeline; reconcile axis = deterministic bash (main).
|
||||||
|
- onboard: onboarder DISPATCHED sonnet (was inline); plugin S1 pipeline;
|
||||||
|
analyzer opus; general-purpose audits model="opus" (kept); seo/geo → S3/S4
|
||||||
|
pipelines; security-auditor + doc pipeline as above; synthesis
|
||||||
|
general-purpose model="opus"; backlog arbitration = main.
|
||||||
|
- client-handover: writer INLINE (orchestrator, main); its 8 skill-runner
|
||||||
|
children model="fable"; handover S5 split (synth opus → render sonnet);
|
||||||
|
gates all main.
|
||||||
|
Excluded-from-gate skills (5, stay ungated): commit-change (propose opus /
|
||||||
|
apply sonnet via model=; approval gates main); doc (S2: auditor opus →
|
||||||
|
gate main → patcher sonnet); status (haiku); release-candidate (executor
|
||||||
|
sonnet; version/when/push decisions main); refactor (refactorer sonnet).
|
||||||
|
Memory/util skills (capitalize, close, prune-memory, reconcile, learn,
|
||||||
|
profile, skills-perso, gitflow, deploy, plugin-check(S1), status): main
|
||||||
|
loop by nature (conversation context, human gates, deterministic bash) —
|
||||||
|
no dispatch changes except plugin-check S1.
|
||||||
|
External/gstack skills (graphify, design-*, review, qa, ship, investigate…):
|
||||||
|
NOT edited (external ownership, BDR-015 class) — covered by doctrine line;
|
||||||
|
local wrapper skills only if locally owned. Verify ownership per file
|
||||||
|
before touching (symlink → skip).
|
||||||
|
|
||||||
|
## D3 — WAVES (each = gitflow feature branch, tests green, census extended)
|
||||||
|
|
||||||
|
W0 SEQUENCING: merge `feature/opus-pin-audit-agents` → develop (baseline,
|
||||||
|
human gate). `bugfix/seo-geo-integrity` is ALREADY MERGED (correctness
|
||||||
|
MAJOR — the TODO.md "UNMERGED" note was stale; verified `92301fe` is an
|
||||||
|
ancestor of develop AND this branch): no arbitrage, no W5 wait — one-line
|
||||||
|
ancestry re-check in W0 + fix the stale TODO.md entry (reconcile-class
|
||||||
|
correction). Absorb the analysis+plan files into the new feature branch.
|
||||||
|
W1 NO-INHERIT ENFORCEMENT (small, high-value): code-review model= opus
|
||||||
|
(ship-feature 6, init-project 10); client-handover-writer 8× model="fable";
|
||||||
|
doctrine line in model-gate.md + census locks (`model="fable"`,
|
||||||
|
`model=` presence per site); SDD sonnet prose → census lock. Prose sweep
|
||||||
|
of stale BDR-066/076 claims touched by W1.
|
||||||
|
W2 INLINE→DISPATCH CONVERSIONS: scaffolder (init 5 — liveness pings move to
|
||||||
|
orchestrator; scaffolder loses PHASE 6 inline-load → init 5b owns README
|
||||||
|
via S2), onboarder (onboard), doc-commit steps ×5 flows → S2 pipeline
|
||||||
|
(gate hoist FIRST: /doc + flows own the validation gate; doc-syncer body
|
||||||
|
loses its inline gate → census re-lock), S1 plugin split + gate hoist ×4
|
||||||
|
consumers. Data-flow pass per LRN-126 on each (fields enumerated in the
|
||||||
|
wave's contract file before edits).
|
||||||
|
W3 TIER MOVES: validator-analyzer → sonnet (pin + prose + census flip);
|
||||||
|
commit-changer per-mode model= (2 sites + prose + census).
|
||||||
|
W4 S5 handover split (synth opus / render sonnet) + PACKAGE re-enumeration.
|
||||||
|
W5 S3/S4 seo/geo pipelines: worker(2-mode)/judge ×2, /seo /geo /harden
|
||||||
|
/onboard rerouted, seo-data.test.sh moved locks, run-scoped signals
|
||||||
|
handoff (RUNID + completeness sentinel + fail-closed judge),
|
||||||
|
envelope/sentinel/score grammars verbatim, COVERAGE lines preserved.
|
||||||
|
W6 DOCTRINE + CLOSE-OUT: model-gate.md rewrite (protects main loop; tier
|
||||||
|
table; fable-dispatch doctrine), challenge-plan.md + plan-challenger
|
||||||
|
ORCHESTRATOR PROTOCOL text (keep BDR-066+BDR-076 tokens per census, add
|
||||||
|
BDR-077), census consolidation (model-routing new sections; every new
|
||||||
|
agent: YAML G3, pin lock, dispatch-string lock, AskUserQuestion/Agent
|
||||||
|
bans), LRN-113 whole-surface prose sweep (~30 refs list in analysis),
|
||||||
|
BDR-077 + LRN entries + journal, EVAL-023-style post-merge ronde.
|
||||||
|
Per-split planted-input smokes run IN their own waves (W2/W4/W5, merge
|
||||||
|
gates) — W6 is the consolidated ronde only, never the first empirical
|
||||||
|
proof of a split.
|
||||||
|
|
||||||
|
## D4 — ZERO-REGRESSION PROTOCOL (every wave)
|
||||||
|
|
||||||
|
- Before edits: wave contract file (.claude/tasks/contracts/) with FILE SCOPE
|
||||||
|
+ acceptance criteria; challenge-plan on THIS plan (done once, below);
|
||||||
|
verify-secure-loop on each wave's diff (verifier sonnet + security sonnet).
|
||||||
|
- Grammar diff-guard: `grep -F` each verbatim marker (analysis §CONSTRAINTS
|
||||||
|
list) pre/post per wave — zero drift.
|
||||||
|
- Census: flip-test every NEW lock (plant violation → RED) before trusting.
|
||||||
|
- `make test` green per wave; no wave merges without human signal (gitflow).
|
||||||
|
- Rollback story (robustness MINOR — waves are textually interdependent, an
|
||||||
|
early wave is NOT independently revertible after later merges): revert in
|
||||||
|
REVERSE merge order, or revert the whole stack; never a mid-stack single
|
||||||
|
revert. Pre-merge, the rollback unit is the wave branch.
|
||||||
|
|
||||||
|
## CHALLENGE LOG (2026-07-19 — 3 blind lenses on plan v1)
|
||||||
|
|
||||||
|
- correctness: CONCERNS(2) — seo-geo-integrity phantom sequencing (fixed W0);
|
||||||
|
commit-changer precedence ambiguity (fixed D1 + D0.2 citation + W3 smoke);
|
||||||
|
3 MINORs (S5 STEP 9 + W4 relock; plugin checkpoint seam; templater label)
|
||||||
|
— all fixed in place.
|
||||||
|
- robustness: FATAL(4) — BLOCKER fable-dispatch unverified → CLOSED by spike
|
||||||
|
(D0.2: resolves to claude-fable-5, enum-validated, loud failure); doc-commit
|
||||||
|
in-thread contract (fixed S2: CHANGE SUMMARY crosses the report grammar);
|
||||||
|
plugin-probe haiku contradiction (fixed: sonnet wave 1); signals handoff
|
||||||
|
freshness (fixed S3: RUNID + sentinel + fail-closed); rollback claim
|
||||||
|
(fixed D4).
|
||||||
|
- simplicity: CONCERNS(1) — 3-way seo/geo YAGNI → 2-way worker/judge (fixed
|
||||||
|
S3/S4); twin-templater share (dissolved by 2-way; divergence stated);
|
||||||
|
plugin gate ×4 copies → lib/plugin-gate.md include (fixed S1).
|
||||||
|
## EXECUTION NOTES (2026-07-19 — as-built deviations, all justified in-commit)
|
||||||
|
|
||||||
|
- S2/S3/S4/S5 shipped MODE-BASED (one agent, modes + call-site `model=`)
|
||||||
|
instead of file splits — the challenge's own commit-changer precedent
|
||||||
|
generalized; locks and body text stayed in place (LRN-137). plugin S1
|
||||||
|
kept the `plugin-advisor` NAME for the reasoner (repinned opus) — only
|
||||||
|
plugin-probe is a new file.
|
||||||
|
- seo/geo keep the OPUS pin (not sonnet+judge-override): fail-safe
|
||||||
|
direction — a forgotten override over-tiers, never downgrades. /harden
|
||||||
|
narrow-scope + /onboard report-only keep legacy no-MODE single-shot on
|
||||||
|
that pin.
|
||||||
|
- W0's seo-geo-integrity arbitrage was phantom (branch already merged) —
|
||||||
|
TODO.md corrected instead.
|
||||||
|
- Per-wave smokes ran in-wave as merge gates (confirmation-pass fix) —
|
||||||
|
all PASSED, disk-verified. Registry note: a NEW subagent_type registers
|
||||||
|
at next session start; typed resolution re-checked post-restart before
|
||||||
|
the W2 merge.
|
||||||
|
|
||||||
|
## CHALLENGE LOG (final)
|
||||||
|
|
||||||
|
- Confirmation pass (fresh robustness challenger on v2): CONCERNS(2) — v1
|
||||||
|
fixes HOLD (doc-commit CHANGE SUMMARY, plugin-probe sonnet, rollback order,
|
||||||
|
fable spike, RUNID); 2 new MAJORs + 1 MINOR opened by the revisions, all
|
||||||
|
fixed in v3: (a) per-split planted-input smokes moved IN-WAVE as merge
|
||||||
|
gates (W6 = ronde only); (b) dispatcher ERROR contract on judge failure
|
||||||
|
(STOP, no templating/apply, retry once, escalate — pipeline never fails
|
||||||
|
open); (c) transient signals files relocated to gitignored `.audit/`
|
||||||
|
(LRN-124). Protocol cap reached (1 re-challenge) → to the human gate.
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
# Architecture — claude-config
|
||||||
|
|
||||||
|
Repo layout and structural principles. Command workflows live in
|
||||||
|
[`USAGE.md`](./USAGE.md); version history in [`CHANGELOG.md`](./CHANGELOG.md).
|
||||||
|
|
||||||
|
## Project layout
|
||||||
|
|
||||||
|
```
|
||||||
|
claude-config/
|
||||||
|
├── CLAUDE.global.md # Global coding preferences — deployed as ~/.claude/CLAUDE.md
|
||||||
|
├── CLAUDE.md # Project-scope instructions (this repo only)
|
||||||
|
├── settings.json # Global permissions (deny / ask / allow rules)
|
||||||
|
├── install.sh # Bootstrap: Claude Code CLI + auth + submodules + link + plugins
|
||||||
|
├── install-plugins.sh # One-shot installer: prerequisites + all plugins
|
||||||
|
├── link.sh # Symlinks this repo into ~/.claude/
|
||||||
|
├── doctor.sh # Setup diagnostic
|
||||||
|
├── update-all.sh # One-command update for all components
|
||||||
|
├── Makefile # Unified entry point: make install / doctor / update
|
||||||
|
├── plugins.lock.json # Version pinning for non-marketplace dependencies
|
||||||
|
├── hooks/ # Session start, statusline, RTK rewrite + ctx7 + design-toolchain reminders
|
||||||
|
├── agents/ # Execution units called by skills (never invoked directly)
|
||||||
|
├── skills/ # Entry points invoked via /skill-name
|
||||||
|
├── skills-external/ # Vendored skill packs (gstack submodule + installer-fetched design packs)
|
||||||
|
├── templates/ # Per-project templates (CLAUDE.md, settings, memory registries, deploy runbook, gitignore)
|
||||||
|
└── lib/ # Shared shell libs (gitflow, profiles, commit helpers, archetypes, tests)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture principles
|
||||||
|
|
||||||
|
- `skills/` = entry points you invoke via `/skill-name`
|
||||||
|
- `agents/` = execution units called by skills (never invoked directly by user)
|
||||||
|
- `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.
|
||||||
@@ -6,6 +6,83 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [1.4.0] — 2026-07-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Transient planning artifacts auto-purged at feature-finish (BDR-065)** —
|
||||||
|
`gitflow finish` on a `feature`/`bugfix` branch now removes the run-time
|
||||||
|
superpowers artifacts (`docs/superpowers/{specs,plans}`) on the working
|
||||||
|
branch just before the directed merge, so `develop`'s tip lands clean while
|
||||||
|
the feature commits stay reachable as the archive (`git show <sha>:…`). This
|
||||||
|
automates the manual post-merge cleanup that BDR-065 had left as doctrine —
|
||||||
|
the step that slipped in 1.3.0 and needed a hand purge. Best-effort by
|
||||||
|
contract: a purge that finds nothing, meets uncommitted changes under those
|
||||||
|
paths, or fails to commit never aborts the finish (index/tree restored); opt
|
||||||
|
out with `GITFLOW_PURGE_TRANSIENT=0`. New `gitflow.sh purge-transient` verb.
|
||||||
|
`.claude/tasks/{contracts,plans}` are deliberately out of scope (durable,
|
||||||
|
versioned, referenced by the decision registry). Live in every project via
|
||||||
|
the `~/.claude/lib` symlink; covered by `lib/gitflow-test.sh` T17 (a–d).
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **Bug routing inverted: `/bugfix` primary, `/investigate` explicit-only
|
||||||
|
(BDR-080)** — a bug / error / 500 now routes to `/bugfix` by default (the
|
||||||
|
full framework: gitflow, contract, fresh verifier + security gates,
|
||||||
|
registries). The gstack `/investigate` monolith — its own `~/.gstack`
|
||||||
|
memory, no gitflow or gates — is reserved for explicit requests
|
||||||
|
(cross-project learnings, `/freeze` scope lock, long investigation with no
|
||||||
|
immediate commit intent). Same core debugging doctrine, incompatible
|
||||||
|
wrappers; the default now favours the gated, integrated path.
|
||||||
|
|
||||||
|
## [1.3.1] — 2026-07-20
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **README rebuilt around a short pitch** — new top half: what it is / how
|
||||||
|
it works / why it's good in ~60 lines (skills = entry points, agents =
|
||||||
|
model-tiered execution units, hooks = deterministic guardrails,
|
||||||
|
templates/memory = compounding per-project registries); all previous
|
||||||
|
content demoted to an explicit reference-manual half below a separator.
|
||||||
|
Deduplicated in the process: old title/tagline, Overview prose and the
|
||||||
|
duplicated fresh-install block removed (unique install notes kept under
|
||||||
|
a new "Install notes" section); hardcoded version number dropped from
|
||||||
|
the footer (staleness risk). Docs-only release — no code change.
|
||||||
|
|
||||||
|
## [1.3.0] — 2026-07-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **Profile switches now toggle external packs and MCPs both ways (BDR-079)** — `profile.sh set` was asymmetric: it enabled what a profile listed (including gstack skills on demand when the whole pack is off, and the `magic` MCP) but never disabled the managed leftovers, so `set backend` after design work kept emil-design-eng / frontend-design / design-motion-principles / impeccable active and magic registered. `set` now trims managed externals (`MANAGED_EXTERNALS`) and managed MCPs (`MANAGED_MCPS`, delegated to `toggle-external.sh`) not listed in the profile — same allowlist doctrine as `MANAGED_PLUGINS`, nothing outside the allowlists is ever auto-touched (darwin-skill stays manual). Also: an `external` entry whose symlink never existed is now created from `skills-external/` (mirroring toggle-external's from-source path), and the stale "NOT toggled automatically" note in `profile.sh` usage was corrected. Covered by a hermetic 16-check test (`lib/tests/profile-set-managed.test.sh`) with a fake `claude` shim.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **README restructured for public readers** — the project-layout tree and architecture principles moved verbatim to a new `ARCHITECTURE.md` (README links it); bare decision-registry citations (`BDR-XXX`) stripped from README prose, meaning preserved; `/profile` documentation corrected in three places to the real 10-profile set (web / seo / web-full / full / backend / design / dev / qa / audit / minimal); fresh-install block now uses the real clone URL + `make install` / `make doctor`; new "SEO data layer" subsection documents the `GOOGLE_OAUTH_CLIENT_ID` / `GOOGLE_OAUTH_CLIENT_SECRET` / `CRUX_API_KEY` vars in `~/.claude/.env` (mirrors `.env.example`, `make seo-connect` one-time consent).
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **Transient planning artifacts purged from the repo** — `docs/plans`, `docs/specs`, `docs/superpowers/{plans,specs}` (deploy-skill 2026-06-27, model-routing 2026-07-15) were run-time pipeline artifacts that should have been deleted in their chantiers' post-merge cleanup and slipped through (one pair predates the lifecycle rule, one missed the purge step of a 6-wave chantier). Git history at the feature commits remains their archive; `docs/` no longer exists.
|
||||||
|
|
||||||
|
## [1.2.1] — 2026-07-20
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **README caught up with the code it describes** — the "Agent model routing" section still presented the BDR-066 v1 scheme (7 rows factually wrong after model-tiering v2): reframed to the BDR-076/077 4-tier table verified against agent frontmatters (opus-pinned judgment agents, per-mode splits for doc-syncer / handover-doc-writer / seo-geo pipelines, plugin-probe added, unpinned inline agents listed as such). Also: Context7 paragraph rewritten to the two-surface model (find-docs = sole doc-fetch surface, `ctx7-reminder` hook = scoped session nudge, BDR-078), `hooks/` tree line now mentions the ctx7 reminder, and the `/ship-feature` workflow block gained its STEP 2b (adversarial plan-challenge) line. Docs-only release — no code change.
|
||||||
|
|
||||||
|
## [1.2.0] — 2026-07-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- **ctx7 coverage extension (BDR-078)** — the "consult current docs before coding against a fast-moving lib" doctrine now covers every code path, not just the two big pipelines. (1) `lib/fast-libs.sh`: single source of truth for fast-lib detection (`detect` / `cache-status` verbs; JS package.json anchored keys + Python requirements/pyproject; 7-day `.ctx7-cache/` freshness; locale-independent sort), replacing three hardcoded lists (`/ship-feature` STEP 0c, `/init-project` STEP 5c, `/onboard` STEP 3.5). (2) `hooks/ctx7-reminder.sh`: once-per-session UserPromptSubmit nudge when the project carries fast-libs and the cache is missing/stale — closes the ad-hoc-coding gap. (3) find-docs description extended with a before-writing-code trigger + a cache-first rule (read fresh cache, tee fetched docs back into it). (4) feater/bugfixer executor briefs gain the fast-lib docs rule (read fresh cache, else 2-topic `npx ctx7@latest` fetch, else report `ctx7 cache miss` and proceed). Second deliberate ctx7 surface — a scoped refinement of BDR-053's single-surface rule, not a reversal.
|
||||||
|
- **Adversarial plan-challenge phase** — reflection orchestrators now run a blind 3-lens challenge (correctness / robustness / simplicity) via a dedicated `plan-challenger` agent before implementation; severity-driven (a single-lens BLOCKER stops the plan), report-only. `/hotfix` joins behind a logic-only guard: cosmetic fixes skip it, logic fixes get challenged, a BLOCKER reroutes to `/bugfix` (BDR-075).
|
||||||
|
- **seo-data engine: measured coverage + new verbs** — the `/seo` FULL audit measures instead of feeling: `sitemap` verb gives COVERAGE a real denominator (source/live split); internal-link graph computes orphan pages + click depth; cannibalisation detected from GSC's own query data; `rich_results` surfaced from URL Inspection data already fetched; `sameAs` profiles actually resolved; `schema_gen` generates JSON-LD instead of only auditing it; `content_quality` runs a deterministic filler/AI-slop scan; the axis score is computed, not felt; `drift` baseline reports regressions vs changes. SPA pages: the audit refuses to score what JS paints instead of scoring the empty shell (no Playwright dependency). Common Crawl backlinks were measured (17 GB edges file) and killed as a source — the Off-page axis stays scoped to what is actually measured.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **Model-tiering v2: 4-tier explicit routing (BDR-076/077)** — the session model (Fable) does main-loop reflection/orchestration only; every dispatched subagent is explicitly tiered: judgment agents pinned opus (analyzer, plan-challenger, seo/geo audit agents…), mechanical executors sonnet, skill-runner children fable — nothing inherits silently. Mode-based splits so pins take effect: doc-syncer audit(opus)/patch(sonnet), handover-doc-writer synthesize(opus)/render(sonnet), seo/geo collect(sonnet)/judge(opus, fail-closed)/template(sonnet), plugin gate split probe(sonnet)/advisor(opus). Census locks (125) + per-wave planted-input smokes.
|
||||||
|
- **config-protection edit-block guardrail removed** (BDR-074) — the hook blocked more than it protected; deny-list design pass recorded in BDR-069.
|
||||||
|
- graphify vendored skill dist synced 0.9.6 → 0.9.15.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- **seo/geo integrity pass (I1–I8)** — Off-page axis scoped to measured data only; VSI (an SEO-blog fiction) removed from CWV thresholds; NAP direction rule ported into geo-analyzer (standalone `/geo` can no longer write unverified NAP); security headers no longer double-counted (`/harden` owns them); sampling coverage disclosed instead of implied; stats reattached to the claims they support; phantom audit precondition dropped. Plus two real bugs caught by a second-site backtest and two process anomalies from live dogfooding.
|
||||||
|
- `settings.json` Write() deny rules were inert — converted to Edit() rules, closing the write hole they left open.
|
||||||
|
- Model-routing W6 ronde: 6 findings closed (README bootstrap path, 2 census gaps, 3 stale refs).
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- **`safe_fetch` resolve-then-pin** in `lib/seo-data` — DNS-rebinding closed on audit fetches: the audited host is resolved once, validated, then pinned for the actual fetch.
|
||||||
|
- **`url-guard`** — shell-injection + local-target refusal before any user-supplied or sitemap-crawled URL reaches curl (SSRF guard on the seo/geo fetch paths).
|
||||||
|
|
||||||
## [1.1.0] — 2026-07-16
|
## [1.1.0] — 2026-07-16
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+4
-1
@@ -252,7 +252,10 @@ description fits (full list is in context). Rules below cover only the
|
|||||||
non-obvious cases: gstack fallbacks, disambiguation, cryptic names.
|
non-obvious cases: gstack fallbacks, disambiguation, cryptic names.
|
||||||
|
|
||||||
- Product idea, "worth building?" → office-hours
|
- Product idea, "worth building?" → office-hours
|
||||||
- Bug / error / 500 → investigate (bugfix if gstack off)
|
- Bug / error / 500 → bugfix (full framework: gitflow, contract, fresh
|
||||||
|
verifier/security gates, registries). investigate ONLY on explicit ask
|
||||||
|
for the gstack ecosystem (cross-project learnings, /freeze scope lock,
|
||||||
|
long investigation with no immediate commit intent)
|
||||||
- feat / hotfix / bugfix distinguished by file count → see descriptions
|
- feat / hotfix / bugfix distinguished by file count → see descriptions
|
||||||
- Ship / deploy / PR → ship (ship-feature if gstack off)
|
- Ship / deploy / PR → ship (ship-feature if gstack off)
|
||||||
- Cut a release / tag a version (develop ahead of main) → release-candidate
|
- Cut a release / tag a version (develop ahead of main) → release-candidate
|
||||||
|
|||||||
@@ -32,8 +32,13 @@ or re-run `make plugin`.
|
|||||||
|
|
||||||
`docs/superpowers/specs/**` and `docs/superpowers/plans/**` are run-time
|
`docs/superpowers/specs/**` and `docs/superpowers/plans/**` are run-time
|
||||||
artifacts of a feature pipeline (subagent briefs, reviewer references).
|
artifacts of a feature pipeline (subagent briefs, reviewer references).
|
||||||
They are committed DURING the run and DELETED in the post-merge cleanup
|
They are committed DURING the run (the SDD worktree + reviewers read them
|
||||||
(BDR-065) — git history at the feature commits is their archive. Durable
|
from disk — NOT gitignored), then AUTO-PURGED by `gitflow finish` on a
|
||||||
knowledge goes to `.claude/memory/` registries, never to these files.
|
`feature`/`bugfix` branch, before the merge, so develop's tip stays clean
|
||||||
Derived scan/audit outputs (`.audit/**`) are gitignored and never
|
(BDR-065, `lib/gitflow.sh` `_gitflow_purge_transient`). The feature commits
|
||||||
committed, even redacted (LRN-124).
|
stay reachable from develop, so `git show <sha>:docs/…` is still the archive.
|
||||||
|
Opt out with `GITFLOW_PURGE_TRANSIENT=0`. NOT in scope: `.claude/tasks/{contracts,plans}`
|
||||||
|
(durable, versioned, referenced by decisions.md). Durable knowledge goes to
|
||||||
|
`.claude/memory/` registries, never to these files. Derived scan/audit
|
||||||
|
outputs (`.audit/**`) are gitignored and never committed, even redacted
|
||||||
|
(LRN-124).
|
||||||
|
|||||||
@@ -1,91 +1,110 @@
|
|||||||
# claude-config
|
# claude-config
|
||||||
|
|
||||||
Global Claude Code configuration — agents, skills, plugins, and project templates.
|
One repo that turns Claude Code into a reproducible engineering system —
|
||||||
|
skills, agents, hooks, plugins, and per-project memory, versioned and
|
||||||
|
symlinked into `~/.claude/`. Clone it on any machine, run one command,
|
||||||
|
and every project gets the same assistant with the same rules.
|
||||||
|
|
||||||
> **Guide d'utilisation complet :** voir [`USAGE.md`](./USAGE.md) — workflows typiques, exemples par type de projet, arbre de décision "quel skill utiliser ?".
|
## What it is
|
||||||
> **Historique des versions :** voir [`CHANGELOG.md`](./CHANGELOG.md).
|
|
||||||
|
Not a collection of prompts — an operating layer on top of Claude Code:
|
||||||
|
|
||||||
|
- **Skills** (`/feat`, `/bugfix`, `/ship-feature`, `/seo`, `/tour`…) are the
|
||||||
|
entry points: each one encodes a complete workflow, from quick fix to
|
||||||
|
full feature pipeline with validation gates.
|
||||||
|
- **Agents** are the execution units skills dispatch to — each pinned to
|
||||||
|
the cheapest model that can do the job (haiku collects, sonnet executes,
|
||||||
|
opus judges, the session model only reflects).
|
||||||
|
- **Hooks and permissions** are deterministic guardrails: gitflow enforced
|
||||||
|
by a pre-commit hook, deny-first permission rules, secrets kept in
|
||||||
|
`~/.claude/.env` and never in config files.
|
||||||
|
- **Templates and memory** seed every project with persistent registries
|
||||||
|
(decisions, learnings, blockers) — what a session learns, the next
|
||||||
|
session knows.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --recurse-submodules https://github.com/bchanot/claude
|
||||||
|
cd claude
|
||||||
|
make install # CLI + auth + symlinks + plugins (pinned in plugins.lock.json)
|
||||||
|
make doctor # verify everything
|
||||||
|
```
|
||||||
|
|
||||||
|
`link.sh` symlinks the repo into `~/.claude/`, so editing here updates the
|
||||||
|
live config — and `git log` is the audit trail of your entire setup.
|
||||||
|
Day to day:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/onboard # bring an existing repo into the framework
|
||||||
|
/ship-feature "…" # brainstorm → plan → adversarial challenge → TDD → review → merge
|
||||||
|
/feat "…" # same idea, 1-5 files, no ceremony
|
||||||
|
/close # flush decisions and learnings to memory before quitting
|
||||||
|
make update # keep CLI, plugins, and submodules current
|
||||||
|
```
|
||||||
|
|
||||||
|
## Why it's good
|
||||||
|
|
||||||
|
- **Reproducible.** One clone rebuilds the whole environment; versions are
|
||||||
|
locked, `make doctor` proves it works.
|
||||||
|
- **Cost-shaped.** Model tiering routes reflection to the big model and
|
||||||
|
execution to cheap ones — the expensive context does only what it must.
|
||||||
|
- **Safe by default.** Protected branches, ask-before-run on risky tools,
|
||||||
|
parameterized secrets: the guardrails are code, not good intentions.
|
||||||
|
- **It compounds.** Memory registries, audit skills, and doc-sync keep every
|
||||||
|
project's knowledge growing across sessions instead of evaporating.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Overview
|
Everything below is the reference manual — model routing, components,
|
||||||
|
commands, settings, secrets, maintenance.
|
||||||
|
|
||||||
This repo is your personal Claude Code setup, versioned and reproducible across machines.
|
---
|
||||||
|
|
||||||
```
|
## Agent model routing (model-tiering v2)
|
||||||
claude-config/
|
|
||||||
├── CLAUDE.global.md # Global coding preferences — deployed as ~/.claude/CLAUDE.md
|
|
||||||
├── CLAUDE.md # Project-scope instructions (this repo only)
|
|
||||||
├── settings.json # Global permissions (deny / ask / allow rules)
|
|
||||||
├── install.sh # Bootstrap: Claude Code CLI + auth + submodules + link + plugins
|
|
||||||
├── install-plugins.sh # One-shot installer: prerequisites + all plugins
|
|
||||||
├── link.sh # Symlinks this repo into ~/.claude/
|
|
||||||
├── doctor.sh # Setup diagnostic
|
|
||||||
├── update-all.sh # One-command update for all components
|
|
||||||
├── Makefile # Unified entry point: make install / doctor / update
|
|
||||||
├── plugins.lock.json # Version pinning for non-marketplace dependencies
|
|
||||||
├── hooks/ # Session start, statusline, RTK rewrite, config-protection + design-toolchain guards
|
|
||||||
├── agents/ # Execution units called by skills (never invoked directly)
|
|
||||||
├── skills/ # Entry points invoked via /skill-name
|
|
||||||
├── skills-external/ # Vendored skill packs (gstack submodule + installer-fetched design packs)
|
|
||||||
├── templates/ # Per-project templates (CLAUDE.md, settings, memory registries, deploy runbook, gitignore)
|
|
||||||
└── lib/ # Shared shell libs (gitflow, profiles, commit helpers, archetypes, tests)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Architecture principle:**
|
Doctrine: the session model (Fable) does main-loop reflection ONLY —
|
||||||
- `skills/` = entry points you invoke via `/skill-name`
|
brainstorm, plan, contract, audit judgment, gates, loop decisions — enforced
|
||||||
- `agents/` = execution units called by skills (never invoked directly by user)
|
by a blocking gate (`lib/model-gate.md` + `lib/model-check.sh`) at the entry
|
||||||
- `templates/` = symlinked to `~/.claude/templates/` — copy into projects via `/onboard` or manually
|
of the 13 reflection orchestrators. Nothing dispatched inherits silently:
|
||||||
- **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.
|
typed agents carry a frontmatter pin, built-ins get an explicit `model=` at
|
||||||
|
every call site.
|
||||||
### 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 |
|
| Agent | Model | Tier |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| feater, hotfixer, bugfixer | sonnet (pinned) | executors — code from a closed plan (feat), fix from a closed diagnosis (bugfix), fix-bundle appliers |
|
| 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) |
|
| 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) |
|
| commit-changer, release-executor, code-cleaner | sonnet (pinned) | dispatched execution — grouping+commit / release spans / approved cleanup (audit + approval gates stay in the dispatcher) |
|
||||||
| doc-syncer, onboarder, scaffolder, refactorer, interviewer, plugin-advisor | sonnet (pinned) | workers |
|
| onboarder, scaffolder, refactorer, validator-analyzer, plugin-probe | sonnet (pinned) | workers — config generation, scaffold, refactor, deterministic W3C/WCAG runner, mechanical plugin probe |
|
||||||
| status-reporter | haiku (pinned) | mechanical collector |
|
| status-reporter | haiku (pinned) | mechanical collector |
|
||||||
| handover-doc-writer | sonnet (pinned) | deliverable writer — synthesizes + renders the client doc from a resolved PACKAGE (dispatched by client-handover) |
|
| analyzer, plan-challenger, plugin-advisor | opus (pinned) | dispatched judgment — pre-plan analysis, 3-lens adversarial plan challenge (`/ship-feature` STEP 2b), plugin-fit reasoning |
|
||||||
| analyzer, seo-analyzer, geo-analyzer, validator-analyzer, client-handover-writer | inherit session (Fable/Opus) | reflection / audit / inline playbooks / ship-and-handover pipeline |
|
| seo-analyzer, geo-analyzer | opus pin (judge mode); collect/template spans dispatched `model="sonnet"` | 3-mode audit pipelines — judgment fail-closed on opus, mechanical collect + templating on sonnet |
|
||||||
|
| doc-syncer | sonnet pin; audit mode dispatched `model="opus"` | two-mode: audit (drift judgment, opus) / patch (mechanical apply, sonnet) |
|
||||||
|
| handover-doc-writer | sonnet pin; synthesize mode dispatched `model="opus"` | two-mode: synthesize (opus) / render (sonnet) — client deliverable |
|
||||||
|
| interviewer, client-handover-writer | unpinned (inline-load = session model) | they ARE the main loop — a frontmatter pin would be inert |
|
||||||
| Explore (built-in) | inherit session (Fable/Opus) | search feeds reflection — kept on the big model, not pinned down |
|
| 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`,
|
The pure-execution skills `/doc`, `/status`, `/commit-change`,
|
||||||
`/release-candidate` **dispatch** their agent (instead of inline-loading it)
|
`/release-candidate` **dispatch** their agent (instead of inline-loading it)
|
||||||
so the pin takes effect and the work leaves the big session model; `/hotfix`
|
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
|
was split like `/feat` (reflection inline + gate, `hotfixer` executor) and so
|
||||||
joins the gated group (13th).
|
joins the gated group (13th); `/client-handover`'s nested skill-runner
|
||||||
|
children are dispatched `model:"fable"` (they carry reflection).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Fresh install (new machine)
|
## Install notes
|
||||||
|
|
||||||
```bash
|
|
||||||
# 1. Clone with submodules
|
|
||||||
git clone --recurse-submodules git@github.com:youruser/claude-config.git
|
|
||||||
cd claude-config
|
|
||||||
|
|
||||||
# 2. Bootstrap (CLI + auth + symlinks + plugins)
|
|
||||||
bash install.sh
|
|
||||||
|
|
||||||
# 3. Verify setup
|
|
||||||
bash doctor.sh
|
|
||||||
|
|
||||||
# 4. Restart Claude Code — plugins load automatically
|
|
||||||
```
|
|
||||||
|
|
||||||
All scripts use their own location to find the repo — run them from anywhere.
|
All scripts use their own location to find the repo — run them from anywhere.
|
||||||
The plugins step logs to `install-YYYYMMDD-HHMMSS.log`.
|
The plugins step logs to `install-YYYYMMDD-HHMMSS.log`.
|
||||||
|
|
||||||
**Optional — Context7** (fast doc lookup for React / Next.js / Prisma…): the plugins
|
**Optional — Context7** (fast doc lookup for React / Next.js / Prisma…): the plugins
|
||||||
step installs the `ctx7` CLI and wires it into Claude Code itself — single surface =
|
step installs the `ctx7` CLI and wires it into Claude Code. The doc-fetch surface is
|
||||||
the `find-docs` skill; the generated `rules/context7.md` is purged by design
|
the `find-docs` skill alone (the generated `rules/context7.md` is purged by
|
||||||
(BDR-053). If you run `ctx7 setup` manually, delete that rule or re-run `make plugin`.
|
design; if you run `ctx7 setup` manually, delete that rule or re-run `make plugin`).
|
||||||
|
A once-per-session `ctx7-reminder` hook nudges toward it when the current project
|
||||||
|
carries fast-moving libs (`lib/fast-libs.sh`) — a scoped second surface, a
|
||||||
|
refinement of the single-surface rule, not a reversal.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ctx7 login # optional: OAuth / API key for higher rate limits
|
ctx7 login # optional: OAuth / API key for higher rate limits
|
||||||
@@ -151,7 +170,7 @@ a different package, ships its own conflicting `graphify` bin) — see
|
|||||||
| `/web-validate` | W3C HTML/CSS validity + WCAG 2.1 accessibility audit |
|
| `/web-validate` | W3C HTML/CSS validity + WCAG 2.1 accessibility audit |
|
||||||
| `/geo` | GEO-only audit — AI-search visibility (ChatGPT, Perplexity, Claude, Gemini…) |
|
| `/geo` | GEO-only audit — AI-search visibility (ChatGPT, Perplexity, Claude, Gemini…) |
|
||||||
| `/client-handover` | Final project delivery — audits + branded deliverable (Markdown / HTML / PDF) |
|
| `/client-handover` | Final project delivery — audits + branded deliverable (Markdown / HTML / PDF) |
|
||||||
| `/profile` | Activate a skill profile (design / dev / qa / audit / minimal) |
|
| `/profile` | Activate a skill profile (web / seo / web-full / full / backend / design / dev / qa / audit / minimal) |
|
||||||
| `/tour` | Grouped all-axes sweep — cleanup + security + reconcile + doc, fix and loop until clean |
|
| `/tour` | Grouped all-axes sweep — cleanup + security + reconcile + doc, fix and loop until clean |
|
||||||
|
|
||||||
> This table lists personal skills. Gstack skills (investigate, review, retro,
|
> This table lists personal skills. Gstack skills (investigate, review, retro,
|
||||||
@@ -185,6 +204,7 @@ cd my-existing-project/
|
|||||||
/ship-feature "feature description"
|
/ship-feature "feature description"
|
||||||
# → STEP 0: plugin check
|
# → STEP 0: plugin check
|
||||||
# → STEP 1-2: brainstorm + plan (superpowers)
|
# → STEP 1-2: brainstorm + plan (superpowers)
|
||||||
|
# → STEP 2b: adversarial plan-challenge (3 lenses, report-only)
|
||||||
# → STEP 3: validation gate — user approval required
|
# → STEP 3: validation gate — user approval required
|
||||||
# → STEP 4-7: implement (TDD) → review → capitalize (memory)
|
# → STEP 4-7: implement (TDD) → review → capitalize (memory)
|
||||||
# → STEP 8: sync README (doc-sync)
|
# → STEP 8: sync README (doc-sync)
|
||||||
@@ -226,17 +246,15 @@ See [`templates/settings/SETTINGS.md`](templates/settings/SETTINGS.md) for the f
|
|||||||
`~/.claude.json` (or the project's `.mcp.json`) — if you pass the real secret
|
`~/.claude.json` (or the project's `.mcp.json`) — if you pass the real secret
|
||||||
on that command line, it materializes as a second plaintext copy outside
|
on that command line, it materializes as a second plaintext copy outside
|
||||||
`~/.claude/.env`, invisible to the repo's `.gitignore`/allowlist reach (this
|
`~/.claude/.env`, invisible to the repo's `.gitignore`/allowlist reach (this
|
||||||
bit us once: job7/BDR-026).
|
bit us once).
|
||||||
|
|
||||||
Claude Code expands `${VAR}` and `${VAR:-default}` in `mcpServers` config —
|
Claude Code expands `${VAR}` and `${VAR:-default}` in `mcpServers` config —
|
||||||
in `env`, `command`, `args`, `url`, and `headers` — for both project (`.mcp.json`)
|
in `env`, `command`, `args`, `url`, and `headers` — for both project (`.mcp.json`)
|
||||||
and user (`~/.claude.json`) scope. Use that instead of a literal value:
|
and user (`~/.claude.json`) scope. Use that instead of a literal value:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# WRONG — plaintext key lands in ~/.claude.json:
|
MAGIC_API_KEY=<Enter your magic api key here from https://21st.dev/settings/api-keys >
|
||||||
claude mcp add magic --scope user --env API_KEY="$MAGIC_API_KEY" -- npx -y @21st-dev/magic@latest
|
# single-quoted so bash doesn't expand it; Claude Code expands it at
|
||||||
|
|
||||||
# RIGHT — single-quoted so bash doesn't expand it; Claude Code expands it at
|
|
||||||
# launch, reading the var from its own process environment:
|
# launch, reading the var from its own process environment:
|
||||||
claude mcp add magic --scope user --env 'API_KEY=${MAGIC_API_KEY}' -- npx -y @21st-dev/magic@latest
|
claude mcp add magic --scope user --env 'API_KEY=${MAGIC_API_KEY}' -- npx -y @21st-dev/magic@latest
|
||||||
```
|
```
|
||||||
@@ -254,6 +272,26 @@ There is no `claude mcp add` flag that writes the reference form for you —
|
|||||||
the `${VAR}` syntax has to be typed by hand (or via a wrapper script), same as
|
the `${VAR}` syntax has to be typed by hand (or via a wrapper script), same as
|
||||||
above.
|
above.
|
||||||
|
|
||||||
|
### SEO data layer (`/seo` FULL) — Google OAuth + CrUX keys
|
||||||
|
|
||||||
|
The same `~/.claude/.env` also feeds `lib/seo-data`, which pulls real Google
|
||||||
|
Search Console and Chrome UX Report data into `/seo` FULL audits. Add these
|
||||||
|
three vars (template with the GCP console steps in `.env.example`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# OAuth Desktop client — GCP console → APIs & Services → Credentials →
|
||||||
|
# OAuth client (Desktop). Consent scope: webmasters.readonly only.
|
||||||
|
GOOGLE_OAUTH_CLIENT_ID=<your-client-id.apps.googleusercontent.com>
|
||||||
|
GOOGLE_OAUTH_CLIENT_SECRET=<your-client-secret>
|
||||||
|
# CrUX + PageSpeed API key — GCP console → Credentials → API key,
|
||||||
|
# restricted to those two APIs. https://developer.chrome.com/docs/crux/api
|
||||||
|
CRUX_API_KEY=<your-crux-api-key>
|
||||||
|
```
|
||||||
|
|
||||||
|
Then run the one-time consent flow: `make seo-connect` (per-label token
|
||||||
|
store, multi-site safe). Missing credentials never break an audit — `/seo`
|
||||||
|
degrades gracefully to anonymous PageSpeed lab data.
|
||||||
|
|
||||||
### magic MCP (`@21st-dev/magic`) — known callback-injection risk
|
### magic MCP (`@21st-dev/magic`) — known callback-injection risk
|
||||||
|
|
||||||
`21st_magic_component_builder` opens an **unauthenticated** local callback
|
`21st_magic_component_builder` opens an **unauthenticated** local callback
|
||||||
@@ -263,7 +301,7 @@ can `POST` to it and that body is injected **verbatim** into the tool result
|
|||||||
the model consumes (job8 audit, `dist/utils/callback-server.js:36`). This is
|
the model consumes (job8 audit, `dist/utils/callback-server.js:36`). This is
|
||||||
in the third-party package's code, not this repo's config — **we don't patch
|
in the third-party package's code, not this repo's config — **we don't patch
|
||||||
it**. The mitigation lives entirely on our side: `settings.json`
|
it**. The mitigation lives entirely on our side: `settings.json`
|
||||||
`permissions.ask` explicitly lists all 4 `mcp__magic__*` tools ([[BDR-059]]),
|
`permissions.ask` explicitly lists all 4 `mcp__magic__*` tools,
|
||||||
so every call — builder included — requires a live confirmation and can
|
so every call — builder included — requires a live confirmation and can
|
||||||
never auto-execute. Don't allowlist
|
never auto-execute. Don't allowlist
|
||||||
`21st_magic_component_builder` or `21st_magic_component_refiner` (arbitrary
|
`21st_magic_component_builder` or `21st_magic_component_refiner` (arbitrary
|
||||||
@@ -289,10 +327,10 @@ make plugin # install plugins only
|
|||||||
make link # create/update symlinks into ~/.claude/
|
make link # create/update symlinks into ~/.claude/
|
||||||
make doctor # diagnostic
|
make doctor # diagnostic
|
||||||
make update # update Claude Code, config, submodules, plugins, and verify
|
make update # update Claude Code, config, submodules, plugins, and verify
|
||||||
make test # run deterministic tests (lib/tests/*.test.sh + lib/seo-data/*.test.sh + lib/gitflow-test.sh)
|
make test # run deterministic tests (lib/tests/*.test.sh + lib/seo-data/*.test.sh + lib/gitflow-test.sh + lib/tests/run-*.sh)
|
||||||
make onboard # onboard an existing project (run from its dir)
|
make onboard # onboard an existing project (run from its dir)
|
||||||
make seo-connect # connect a Google account for /seo FULL (OAuth consent)
|
make seo-connect # connect a Google account for /seo FULL (OAuth consent)
|
||||||
make profile cmd="set X" # activate a skill profile (design/dev/qa/audit/minimal/full)
|
make profile cmd="set X" # activate a skill profile (web/seo/web-full/full/backend/design/dev/qa/audit/minimal)
|
||||||
make profile-list # list skill profiles
|
make profile-list # list skill profiles
|
||||||
make profile-current # show the active profile
|
make profile-current # show the active profile
|
||||||
make profile-reset # re-enable all gstack skills
|
make profile-reset # re-enable all gstack skills
|
||||||
@@ -300,3 +338,11 @@ make new-skill name=myskill # scaffold agent + skill files
|
|||||||
```
|
```
|
||||||
|
|
||||||
`doctor.sh` checks: symlinks, GStack submodule, prerequisites (git, Node, Cargo, Python, Claude Code), plugins, permissions, token budget, config consistency.
|
`doctor.sh` checks: symlinks, GStack submodule, prerequisites (git, Node, Cargo, Python, Claude Code), plugins, permissions, token budget, config consistency.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Going further
|
||||||
|
|
||||||
|
[`USAGE.md`](./USAGE.md) — workflows and skill decision tree ·
|
||||||
|
[`ARCHITECTURE.md`](./ARCHITECTURE.md) — layout and principles ·
|
||||||
|
[`CHANGELOG.md`](./CHANGELOG.md) — version history.
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ Tu veux...
|
|||||||
| `/pdf-translate` | Traduire un PDF vers une autre langue | Sortie HTML fidèle (images, layout, style préservés) |
|
| `/pdf-translate` | Traduire un PDF vers une autre langue | Sortie HTML fidèle (images, layout, style préservés) |
|
||||||
| `/impeccable` | Audit/polish design + détecteur anti-slop déterministe | 23 verbes ; `npx impeccable detect` (exit 0/2) |
|
| `/impeccable` | Audit/polish design + détecteur anti-slop déterministe | 23 verbes ; `npx impeccable detect` (exit 0/2) |
|
||||||
| `/tour` | Sweep groupé sur un ou plusieurs projets | Sécu + nettoyage + reconcile + doc, boucle jusqu'à un pass propre |
|
| `/tour` | Sweep groupé sur un ou plusieurs projets | Sécu + nettoyage + reconcile + doc, boucle jusqu'à un pass propre |
|
||||||
| `/profile` | Changer le profil de skills | design / dev / qa / audit / minimal |
|
| `/profile` | Changer le profil de skills | web / seo / web-full / full / backend / design / dev / qa / audit / minimal |
|
||||||
|
|
||||||
> Cette table couvre les skills personnels principaux. Les plugins (gstack,
|
> Cette table couvre les skills personnels principaux. Les plugins (gstack,
|
||||||
> pr-review-toolkit…) et marketplaces externes en ajoutent beaucoup d'autres —
|
> pr-review-toolkit…) et marketplaces externes en ajoutent beaucoup d'autres —
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name: analyzer
|
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.
|
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
|
tools: Read, Grep, Glob, Bash
|
||||||
|
model: opus
|
||||||
memory: project
|
memory: project
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ Every choice was made in the plan or is a NEED-DECISION to report.
|
|||||||
before reporting.
|
before reporting.
|
||||||
- Follow existing code patterns and CLAUDE.md limits (function size, params,
|
- Follow existing code patterns and CLAUDE.md limits (function size, params,
|
||||||
no global state). Keep the fix minimal — no "while we're here" cleanups.
|
no global state). Keep the fix minimal — no "while we're here" cleanups.
|
||||||
|
- Fast-moving libs (`bash ~/.claude/lib/fast-libs.sh detect .` — React,
|
||||||
|
Next.js, Prisma…): before touching their APIs, read a fresh
|
||||||
|
`.ctx7-cache/<lib>*.md` if present; else fetch targeted docs, max 2
|
||||||
|
topics (`npx ctx7@latest library <name> "<q>"` then `docs <id> "<q>"`).
|
||||||
|
ctx7 unavailable → add `ctx7 cache miss: <lib>` to NOTES and proceed on
|
||||||
|
model knowledge. Stable techs skip this entirely.
|
||||||
- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies,
|
- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies,
|
||||||
security/verifier dispatch, editing `.claude/**` or memory registries, user
|
security/verifier dispatch, editing `.claude/**` or memory registries, user
|
||||||
questions (you cannot ask — report instead), attribution trailers of any kind.
|
questions (you cannot ask — report instead), attribution trailers of any kind.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: client-handover-writer
|
name: client-handover-writer
|
||||||
description: Final ship-and-handover orchestrator — called by /client-handover. Runs the audit/fix/gate pipeline (SEO+GEO+HARDEN to ≥17/20, live VALIDATE) inline on the big session model, then delegates the non-technical client deliverable (Markdown + branded HTML + PDF) to the sonnet-pinned handover-doc-writer.
|
description: Final ship-and-handover orchestrator — called by /client-handover. Runs the audit/fix/gate pipeline (SEO+GEO+HARDEN to ≥17/20, live VALIDATE) inline on the big session model with fable-pinned skill-runner children, then delegates the client deliverable to the two-mode handover-doc-writer (synthesize opus / render sonnet — BDR-077).
|
||||||
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch, AskUserQuestion, Agent
|
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch, AskUserQuestion, Agent
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -257,7 +257,12 @@ pipeline is reduced: only run /cso (single audit, single fix loop), skip
|
|||||||
STEP 6 deploy pause and STEP 7 /web-validate. Treat /cso as the only score for
|
STEP 6 deploy pause and STEP 7 /web-validate. Treat /cso as the only score for
|
||||||
the gate.
|
the gate.
|
||||||
|
|
||||||
For web projects, dispatch in **a single message with two parallel Agent calls**:
|
**Model routing (BDR-077):** EVERY `general-purpose` skill-runner dispatch in
|
||||||
|
this pipeline (initial audits, fix-loop re-dispatches, commit-change,
|
||||||
|
web-validate) carries `model: "fable"` — the child hosts gated orchestration
|
||||||
|
on the pipeline's behalf; it must never inherit the session model.
|
||||||
|
|
||||||
|
For web projects, dispatch in **a single message with two parallel Agent calls** (each with `model: "fable"`):
|
||||||
|
|
||||||
| Audit (web) | Subagent | Prompt template |
|
| Audit (web) | Subagent | Prompt template |
|
||||||
|---------------|-------------------|-----------------|
|
|---------------|-------------------|-----------------|
|
||||||
@@ -383,7 +388,7 @@ console). If no projected line is parseable, treat projected = 17
|
|||||||
|
|
||||||
### Re-dispatch prompt template (SEO + GEO loop)
|
### Re-dispatch prompt template (SEO + GEO loop)
|
||||||
|
|
||||||
Send to `general-purpose` subagent:
|
Send to `general-purpose` subagent (`model: "fable"`):
|
||||||
|
|
||||||
> Read `~/.claude/skills/seo/SKILL.md` and re-run it on this project.
|
> Read `~/.claude/skills/seo/SKILL.md` and re-run it on this project.
|
||||||
> Previous scores:
|
> Previous scores:
|
||||||
@@ -413,7 +418,7 @@ Send to `general-purpose` subagent:
|
|||||||
|
|
||||||
### Re-dispatch prompt template (HARDEN loop)
|
### Re-dispatch prompt template (HARDEN loop)
|
||||||
|
|
||||||
Send to `general-purpose` subagent:
|
Send to `general-purpose` subagent (`model: "fable"`):
|
||||||
|
|
||||||
> Read `~/.claude/skills/harden/SKILL.md` and re-run it. Previous score:
|
> Read `~/.claude/skills/harden/SKILL.md` and re-run it. Previous score:
|
||||||
> **`<SCORE_HARDEN_PREVIOUS>`/20** — below threshold. Iteration `<N>` of
|
> **`<SCORE_HARDEN_PREVIOUS>`/20** — below threshold. Iteration `<N>` of
|
||||||
@@ -424,7 +429,7 @@ Send to `general-purpose` subagent:
|
|||||||
|
|
||||||
### Re-dispatch prompt template (CSO loop — non-web only)
|
### Re-dispatch prompt template (CSO loop — non-web only)
|
||||||
|
|
||||||
Send to `general-purpose` subagent:
|
Send to `general-purpose` subagent (`model: "fable"`):
|
||||||
|
|
||||||
> Read `~/.claude/skills/cso/SKILL.md` and re-run it in **daily mode**.
|
> Read `~/.claude/skills/cso/SKILL.md` and re-run it in **daily mode**.
|
||||||
> Previous score: **`<SCORE_CSO_PREVIOUS>`/20** — below threshold.
|
> Previous score: **`<SCORE_CSO_PREVIOUS>`/20** — below threshold.
|
||||||
@@ -510,7 +515,7 @@ listed changes manually before deploy." Continue to STEP 6.
|
|||||||
|
|
||||||
If `PENDING_CHANGES` non-empty → invoke /commit-change skill via subagent:
|
If `PENDING_CHANGES` non-empty → invoke /commit-change skill via subagent:
|
||||||
|
|
||||||
> Dispatch `general-purpose` subagent. Prompt:
|
> Dispatch `general-purpose` subagent (`model: "fable"`). Prompt:
|
||||||
>
|
>
|
||||||
> "Read `~/.claude/skills/commit-change/SKILL.md` and execute. All pending
|
> "Read `~/.claude/skills/commit-change/SKILL.md` and execute. All pending
|
||||||
> changes were produced by the client-handover ship pipeline during the
|
> changes were produced by the client-handover ship pipeline during the
|
||||||
@@ -617,7 +622,7 @@ Skip if `VALIDATE_SKIPPED=true` or `PROJECT_TYPE != web` (in either case
|
|||||||
ensure `VALIDATE_SKIPPED=true` is set so the gate logic in STEP 8 treats
|
ensure `VALIDATE_SKIPPED=true` is set so the gate logic in STEP 8 treats
|
||||||
VALIDATE as not-applicable rather than failed).
|
VALIDATE as not-applicable rather than failed).
|
||||||
|
|
||||||
Dispatch `general-purpose` subagent:
|
Dispatch `general-purpose` subagent (`model: "fable"`):
|
||||||
|
|
||||||
> Read `~/.claude/skills/web-validate/SKILL.md` and execute against the
|
> Read `~/.claude/skills/web-validate/SKILL.md` and execute against the
|
||||||
> deployed URL: `<DEPLOYED_URL>`. Audit W3C HTML validity (validator.nu),
|
> deployed URL: `<DEPLOYED_URL>`. Audit W3C HTML validity (validator.nu),
|
||||||
@@ -1067,11 +1072,30 @@ If `OUTPUT` resolved to `skip-write`, still dispatch — the doc-writer
|
|||||||
reports `MD: skipped` and stops before rendering, per its own
|
reports `MD: skipped` and stops before rendering, per its own
|
||||||
contract.
|
contract.
|
||||||
|
|
||||||
Dispatch:
|
Dispatch the two-mode pipeline (BDR-077 — synthesis on opus, render on the
|
||||||
|
sonnet pin, full PACKAGE both times per LRN-126). Mint a RUNID first
|
||||||
|
(`RUNID=$(date +%s)`); the draft crosses via the run-scoped, gitignored
|
||||||
|
`.audit/handover-draft-<RUNID>.md`; clean it after 9.7.
|
||||||
|
|
||||||
|
FIRST — synthesize:
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(subagent_type="handover-doc-writer", model="opus")
|
||||||
|
prompt: "MODE: synthesize
|
||||||
|
RUNID: <RUNID>
|
||||||
|
PACKAGE:
|
||||||
|
<the FULL PACKAGE block below>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Parse its `SYNTH REPORT`: `STATUS: BLOCKED` → surface verbatim, stop (do
|
||||||
|
not patch the PACKAGE silently); malformed/mute → retry ONCE fresh, then
|
||||||
|
escalate. `STATUS: DONE` → THEN render:
|
||||||
|
|
||||||
```
|
```
|
||||||
Agent(subagent_type="handover-doc-writer")
|
Agent(subagent_type="handover-doc-writer")
|
||||||
prompt: "PACKAGE:
|
prompt: "MODE: render
|
||||||
|
RUNID: <RUNID>
|
||||||
|
PACKAGE:
|
||||||
LANG: <LANG>
|
LANG: <LANG>
|
||||||
PROJECT: name=<name> root=<root> type=<type> sub-type=<sub-type>
|
PROJECT: name=<name> root=<root> type=<type> sub-type=<sub-type>
|
||||||
is_local_business=<bool> deployed_url=<url> period=<first→last>
|
is_local_business=<bool> deployed_url=<url> period=<first→last>
|
||||||
@@ -1087,10 +1111,15 @@ PRECHECK_DONE: <list>
|
|||||||
CLIENT_NAME: <name|—>
|
CLIENT_NAME: <name|—>
|
||||||
OUTPUT: <overwrite <path> | versioned <path> | skip-write>
|
OUTPUT: <overwrite <path> | versioned <path> | skip-write>
|
||||||
|
|
||||||
Synthesize + write + render the deliverable per your steps. Report the
|
Render the deliverable from the draft per your render-mode steps. Report
|
||||||
HANDOVER-DOC REPORT."
|
the HANDOVER-DOC REPORT."
|
||||||
```
|
```
|
||||||
|
|
||||||
|
(The PACKAGE block is IDENTICAL in both dispatches — write it once,
|
||||||
|
paste it twice. A render `STATUS: BLOCKED` on draft absence/RUNID
|
||||||
|
mismatch means the synthesize leg failed silently: re-run 9.6 from the
|
||||||
|
synthesize dispatch, never hand-write the draft.)
|
||||||
|
|
||||||
### 9.7 — Parse the report, tell the user
|
### 9.7 — Parse the report, tell the user
|
||||||
|
|
||||||
Parse the returned `HANDOVER-DOC REPORT`:
|
Parse the returned `HANDOVER-DOC REPORT`:
|
||||||
@@ -1101,3 +1130,7 @@ Parse the returned `HANDOVER-DOC REPORT`:
|
|||||||
- `STATUS: BLOCKED` → surface the report verbatim (including which
|
- `STATUS: BLOCKED` → surface the report verbatim (including which
|
||||||
PACKAGE field the doc-writer flagged) and stop — do not retry or
|
PACKAGE field the doc-writer flagged) and stop — do not retry or
|
||||||
patch the PACKAGE silently.
|
patch the PACKAGE silently.
|
||||||
|
|
||||||
|
In BOTH branches, then clean the transient draft:
|
||||||
|
`rm -f ".audit/handover-draft-${RUNID}.md"` (run-scoped, gitignored —
|
||||||
|
cleanup keeps `.audit/` from accumulating stranded drafts).
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ model: sonnet
|
|||||||
|
|
||||||
# Git Smart Commit
|
# Git Smart Commit
|
||||||
|
|
||||||
|
> MODEL (BDR-077): `MODE: propose` is dispatched with `model="opus"` (the
|
||||||
|
> call-site override — narrative reconstruction + capitalize routing are
|
||||||
|
> judgment); `MODE: apply` runs on the sonnet frontmatter pin (mechanical
|
||||||
|
> staging/committing of an approved plan).
|
||||||
|
|
||||||
Reconstruct the development narrative from a working directory. The goal
|
Reconstruct the development narrative from a working directory. The goal
|
||||||
is to create a git history that reads like a story of how the work was
|
is to create a git history that reads like a story of how the work was
|
||||||
done — each commit is one development step, in chronological order.
|
done — each commit is one development step, in chronological order.
|
||||||
|
|||||||
+88
-59
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: doc-syncer
|
name: doc-syncer
|
||||||
description: Detect stale PUBLIC documentation by cross-referencing git history against the doc layout (README, CHANGELOG, docs/**…) — dispatched by /doc and orchestrators. Convention-aware (Diátaxis, Keep a Changelog); never touches .claude/. Audit, report, patch.
|
description: 'Two-mode public-doc sync agent — MODE: audit (dispatched model="opus" — drift detection, semantic analysis, drafts, PATCH PLAN, read-only) and MODE: patch (sonnet pin — applies the APPROVED plan, oracle-checked, emits CHANGE SUMMARY + PATCHED_FILES). The validation gate lives in the DISPATCHER (BDR-077). Convention-aware (Diátaxis, Keep a Changelog); never touches .claude/.'
|
||||||
tools: Read, Write, Edit, Bash, Grep, Glob
|
tools: Read, Write, Edit, Bash, Grep, Glob
|
||||||
model: sonnet
|
model: sonnet
|
||||||
---
|
---
|
||||||
@@ -54,18 +54,25 @@ audit, report, and patch.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## MODE DETECTION
|
## MODE DETECTION (BDR-077 — two dispatch modes around the dispatcher's gate)
|
||||||
|
|
||||||
Parse `$ARGUMENTS`:
|
Parse `$ARGUMENTS`:
|
||||||
|
|
||||||
- **AUTO MODE** — `$ARGUMENTS` starts with `auto-mode scope:`
|
- **`MODE: patch`** — the dispatcher approved a PATCH PLAN and re-dispatches
|
||||||
Jump to AUTO MODE section.
|
this agent to APPLY it. Jump to MODE: PATCH section. Runs on the sonnet
|
||||||
- **FULL AUDIT** — anything else (empty, file list, description).
|
frontmatter pin.
|
||||||
Run the full audit workflow.
|
- **`MODE: audit`** (or no explicit MODE — audit is the default) — analysis
|
||||||
- **CLEAN MODE** — set when `$ARGUMENTS` contains the token `clean`.
|
half, dispatched with `model: "opus"` (judgment tier; the call-site
|
||||||
Modifier on FULL AUDIT: run the full audit AND propose removal of
|
override takes precedence over the sonnet pin). **READ-ONLY: Write and
|
||||||
out-of-convention content already present in public docs (see
|
Edit are FORBIDDEN in audit mode** — CREATE items are rendered as DRAFTS
|
||||||
STEP 6.5). Not a separate flow.
|
inside the report, never written. Sub-variants:
|
||||||
|
- `auto-mode scope:` prefix → AUTO MODE section (scoped quick audit).
|
||||||
|
- `clean` token → CLEAN modifier on the full audit (STEP 6.5).
|
||||||
|
- anything else → FULL AUDIT workflow.
|
||||||
|
- **The validation gate is NOT yours.** A dispatched agent cannot ask the
|
||||||
|
user. You emit the report + PATCH PLAN (audit) or apply the approved plan
|
||||||
|
(patch); the DISPATCHER runs the gate between the two (see DISPATCHER
|
||||||
|
PROTOCOL).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -373,9 +380,10 @@ Omit any section whose delegated target does not exist and is not being
|
|||||||
proposed this run (e.g. drop "Deploy" entirely when `DEPLOY_COMPLEXITY`
|
proposed this run (e.g. drop "Deploy" entirely when `DEPLOY_COMPLEXITY`
|
||||||
is `NONE`/`TRIVIAL`; drop "Configuration" when there is no config schema).
|
is `NONE`/`TRIVIAL`; drop "Configuration" when there is no config schema).
|
||||||
|
|
||||||
Tag as **AUTO** — create on first audit. Surface the rendered README in
|
Tag as **AUTO** — create on first audit. The rendered README is a DRAFT
|
||||||
the validation gate before writing so the user can `edit` if needed, but
|
inside the audit report (`[CREATE-AUTO]` in the PATCH PLAN); the
|
||||||
do NOT skip creation; "skip" is not an offered option on README bootstrap.
|
DISPATCHER's gate surfaces it so the user can `edit`, but do NOT skip
|
||||||
|
creation; "skip" is not an offered option on README bootstrap.
|
||||||
|
|
||||||
### STEP 6 — DEPLOY.md GATE
|
### STEP 6 — DEPLOY.md GATE
|
||||||
|
|
||||||
@@ -662,19 +670,36 @@ Last updated: <date> (<N commits since>)
|
|||||||
|
|
||||||
CHANGELOG entries always HUMAN. DEPLOY.md creation always HUMAN.
|
CHANGELOG entries always HUMAN. DEPLOY.md creation always HUMAN.
|
||||||
CLEAN removals always HUMAN.
|
CLEAN removals always HUMAN.
|
||||||
**README.md creation is AUTO** — always render and write, never gate on
|
**README.md creation is AUTO** — always render (audit mode: as a draft
|
||||||
user input. The validation gate (STEP 8) still surfaces the rendered
|
in the report) and write (patch mode), never gate on user input. The
|
||||||
file so the user can edit before write, but "skip" is not an option for
|
DISPATCHER's validation gate still surfaces the rendered draft so the
|
||||||
|
user can edit before the patch dispatch, but "skip" is not an option for
|
||||||
README bootstrap; it is mandatory.
|
README bootstrap; it is mandatory.
|
||||||
|
|
||||||
If no drift in any doc and no missing required doc (and, in CLEAN MODE,
|
If no drift in any doc and no missing required doc (and, in CLEAN MODE,
|
||||||
nothing out-of-convention): `DOC SYNC: all docs current` and stop.
|
nothing out-of-convention): `DOC SYNC: all docs current` and stop.
|
||||||
|
|
||||||
### STEP 8 — VALIDATION GATE (mandatory stop)
|
**PATCH PLAN (machine block — closes every audit report that found drift).**
|
||||||
|
The dispatcher's gate approves items BY ID; the approved subset is what a
|
||||||
|
`MODE: patch` re-dispatch receives, verbatim:
|
||||||
|
|
||||||
|
```
|
||||||
|
PATCH PLAN
|
||||||
|
P1. [AUTO] <file> — <section> — <exact change, diffable>
|
||||||
|
P2. [HUMAN] <file> — <section> — <exact change> — reason: <…>
|
||||||
|
C1. [CREATE-AUTO] README.md — write the rendered draft above
|
||||||
|
C2. [CREATE-HUMAN] DEPLOY.md — write the rendered draft above
|
||||||
|
R1. [REMOVE] <file> — <block to excise> (CLEAN items likewise)
|
||||||
|
```
|
||||||
|
|
||||||
|
### DISPATCHER PROTOCOL — VALIDATION GATE (consumer contract — the gate
|
||||||
|
### runs in the DISPATCHER'S MAIN LOOP, never in this dispatched agent)
|
||||||
|
|
||||||
|
The dispatcher presents:
|
||||||
|
|
||||||
```
|
```
|
||||||
DOC SYNC — VALIDATION GATE
|
DOC SYNC — VALIDATION GATE
|
||||||
AUTO items : <count> (Claude will patch these)
|
AUTO items : <count> (will be patched)
|
||||||
HUMAN items : <count> (listed above for review)
|
HUMAN items : <count> (listed above for review)
|
||||||
CREATE items : <count>
|
CREATE items : <count>
|
||||||
- README.md (AUTO — will be written; `edit` to refine the rendered draft)
|
- README.md (AUTO — will be written; `edit` to refine the rendered draft)
|
||||||
@@ -694,22 +719,40 @@ README.md CREATE is unconditional: the only valid responses are `yes`
|
|||||||
write). Treat any `no` / `skip` answer to README as `edit` and prompt
|
write). Treat any `no` / `skip` answer to README as `edit` and prompt
|
||||||
the user for the specific changes they want.
|
the user for the specific changes they want.
|
||||||
|
|
||||||
Wait for explicit approval. Do not proceed without it.
|
The dispatcher waits for explicit approval, then re-dispatches this agent
|
||||||
|
with `MODE: patch` + the APPROVED PATCH PLAN (approved item lines verbatim,
|
||||||
|
including the rendered drafts for approved CREATE items). Nothing is
|
||||||
|
applied without that round-trip.
|
||||||
|
|
||||||
### STEP 9 — PATCH
|
## MODE: PATCH
|
||||||
|
|
||||||
Apply only approved items. **Never write under `.claude/` or to
|
INPUT: `MODE: patch` + the APPROVED PATCH PLAN (item lines verbatim — the
|
||||||
`CLAUDE.md`** — they are not targets under any circumstance.
|
dispatcher's gate already decided; you re-decide NOTHING, you re-analyse
|
||||||
|
NOTHING). Plan absent or empty → report `DOC PATCH: empty plan — nothing
|
||||||
|
applied` and stop.
|
||||||
|
|
||||||
|
Apply only the listed items. **Never write under `.claude/` or to
|
||||||
|
`CLAUDE.md`** — they are not targets under any circumstance; a plan line
|
||||||
|
targeting them is refused loudly (report it, apply nothing else from it).
|
||||||
- Surgical Edit for AUTO items. Preserve structure and tone.
|
- Surgical Edit for AUTO items. Preserve structure and tone.
|
||||||
- Write for approved CREATE items (README, DEPLOY). Use real project
|
- Write for approved CREATE items (README, DEPLOY) using the approved
|
||||||
data only — no `<TODO>` placeholders, no fabricated feature
|
rendered draft. Real project data only — no `<TODO>` placeholders, no
|
||||||
descriptions.
|
fabricated feature descriptions.
|
||||||
- For removals (REMOVE / INLINE / CLEAN), prefer Edit (delete the
|
- For removals (REMOVE / INLINE / CLEAN), prefer Edit (delete the
|
||||||
offending lines) over Write.
|
offending lines) over Write.
|
||||||
- Re-read each modified file post-edit to verify no broken markdown,
|
- Re-read each modified file post-edit to verify no broken markdown,
|
||||||
no orphaned references.
|
no orphaned references.
|
||||||
|
- **Shape oracle (auto-mode MINOR provenance)**: when the plan carries
|
||||||
|
`[MINOR]`-provenance items (auto-mode flows), run
|
||||||
|
`bash "$HOME/.claude/lib/doc-shape.sh" check <every patched path>` (all
|
||||||
|
paths, ONE call) AFTER patching. exit 0 → keep. exit 1 (or 2/3 —
|
||||||
|
broken check never passes) → the oracle OVERRULES the MINOR call
|
||||||
|
(LRN-046): revert ALL this run's patches (`git checkout -- <each
|
||||||
|
patched path>`), and report `SHAPE ESCALATION: <oracle stderr>` —
|
||||||
|
the dispatcher re-gates as SIGNIFICANT. Never keep an out-of-shape
|
||||||
|
auto-patch.
|
||||||
|
|
||||||
### OUTPUT
|
### OUTPUT (MODE: patch)
|
||||||
|
|
||||||
```
|
```
|
||||||
DOC SYNC COMPLETE
|
DOC SYNC COMPLETE
|
||||||
@@ -719,6 +762,9 @@ CREATED : <count> files
|
|||||||
REMOVED : <count> files / sections
|
REMOVED : <count> files / sections
|
||||||
HUMAN PENDING: <count> items (see report above)
|
HUMAN PENDING: <count> items (see report above)
|
||||||
SKIPPED : <count> (user declined)
|
SKIPPED : <count> (user declined)
|
||||||
|
CHANGE SUMMARY: (one line per patched file — what changed and why; the
|
||||||
|
doc-commit step's rc-0 visible surface consumes THIS, LRN-126)
|
||||||
|
<path> — <one line: what changed>
|
||||||
PATCHED_FILES: (one real path per LINE below; "(none)" if no write)
|
PATCHED_FILES: (one real path per LINE below; "(none)" if no write)
|
||||||
<path created or modified this run>
|
<path created or modified this run>
|
||||||
<path created or modified this run>
|
<path created or modified this run>
|
||||||
@@ -788,46 +834,29 @@ Categorize:
|
|||||||
artifact (Dockerfile, fly.toml, workflow) without DEPLOY.md update or
|
artifact (Dockerfile, fly.toml, workflow) without DEPLOY.md update or
|
||||||
creation.
|
creation.
|
||||||
|
|
||||||
### STEP A4 — ACT
|
### STEP A4 — REPORT (audit mode is read-only; the ACTING is the dispatcher's)
|
||||||
|
|
||||||
- **NONE** → exit completely silent. No output (no `PATCHED_FILES` → the doc-commit step
|
- **NONE** → exit completely silent. No report, no PATCH PLAN (the
|
||||||
sees an empty list and no-ops).
|
dispatcher sees nothing to do; the doc-commit step no-ops).
|
||||||
- **MINOR** → patch, then VERIFY SHAPE with the deterministic oracle BEFORE the
|
- **MINOR** → emit a minimal report + `PATCH PLAN` whose items carry the
|
||||||
silent auto-commit. The LLM made the MINOR call; the oracle re-checks that the
|
`[MINOR]` provenance tag. The DISPATCHER re-dispatches `MODE: patch`
|
||||||
patch's SHAPE actually holds, catching a SIGNIFICANT mislabeled MINOR (RISK-1):
|
DIRECTLY, no gate (preserved auto behavior — MINOR is auto-committed;
|
||||||
```
|
the deterministic shape oracle runs in patch mode and a
|
||||||
bash "$HOME/.claude/lib/doc-shape.sh" check <every patched path> # all paths, ONE call
|
`SHAPE ESCALATION` comes back to the dispatcher, which then gates the
|
||||||
```
|
set as SIGNIFICANT: on `no` the reverts already happened; on `select`
|
||||||
- **exit 0** (within the MINOR envelope) → genuine MINOR: keep the silent patch.
|
it re-dispatches patch with the kept subset).
|
||||||
One-line confirmation per file: `doc-sync: patched <file> (<what changed>)`.
|
- **SIGNIFICANT** (or a MINOR the oracle escalated back) → emit the report
|
||||||
Proceed to `PATCHED_FILES` + the doc-commit step.
|
+ PATCH PLAN; the DISPATCHER gates:
|
||||||
- **exit 1** (shape EXCEEDS — oracle stderr names the offender(s) and why) → the
|
|
||||||
deterministic oracle OVERRULES the LLM's MINOR call (LRN-046). Do NOT auto-commit.
|
|
||||||
ESCALATE the WHOLE patch set to the SIGNIFICANT gate below — one file out of
|
|
||||||
shape makes the atomic MINOR classification suspect. Surface every patched file
|
|
||||||
+ the oracle's reason, then the gate: on `no` → revert ALL
|
|
||||||
(`git checkout -- <each patched path>`); on `select` → keep the chosen files,
|
|
||||||
revert the rest. The oracle catches STRUCTURAL/size significance, not semantic —
|
|
||||||
it is a deterministic floor, not a full SIGNIFICANT-detector.
|
|
||||||
- **exit 2/3** (oracle usage error / not a git repo) → do NOT auto-commit on a
|
|
||||||
broken check; treat as exit 1 and escalate.
|
|
||||||
- **SIGNIFICANT** (or a MINOR the oracle escalated) → surface to user before patching:
|
|
||||||
```
|
```
|
||||||
DOC SYNC — drift detected after this session:
|
DOC SYNC — drift detected after this session:
|
||||||
<list of significant items with proposed fixes>
|
<list of significant items with proposed fixes>
|
||||||
Apply? (yes / no / select)
|
Apply? (yes / no / select)
|
||||||
```
|
```
|
||||||
Wait for approval.
|
then re-dispatches `MODE: patch` with the approved subset.
|
||||||
|
|
||||||
After writing in MINOR or approved-SIGNIFICANT, emit the machine-readable handle the
|
`PATCHED_FILES` + `CHANGE SUMMARY` are emitted by `MODE: patch` only (see
|
||||||
doc-commit step (`lib/doc-commit.md`) consumes — ONE real path PER LINE:
|
its OUTPUT) — audit mode writes nothing, so it never emits them. Neither
|
||||||
```
|
ever lists `.claude/**` or `CLAUDE.md` (never targets, BDR-022).
|
||||||
PATCHED_FILES:
|
|
||||||
<path created or modified this run>
|
|
||||||
<path created or modified this run>
|
|
||||||
```
|
|
||||||
Emit ONLY when something was written; NONE stays silent. Never lists `.claude/**` or
|
|
||||||
`CLAUDE.md` (never targets, BDR-022).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ report below is optional on this path (the dispatcher needs the edit applied
|
|||||||
suite incrementally; run it fully before reporting.
|
suite incrementally; run it fully before reporting.
|
||||||
- Follow existing code patterns and CLAUDE.md limits (function size,
|
- Follow existing code patterns and CLAUDE.md limits (function size,
|
||||||
params, no global state). Match comment density and naming.
|
params, no global state). Match comment density and naming.
|
||||||
|
- Fast-moving libs (`bash ~/.claude/lib/fast-libs.sh detect .` — React,
|
||||||
|
Next.js, Prisma…): before coding against their APIs, read a fresh
|
||||||
|
`.ctx7-cache/<lib>*.md` if present; else fetch targeted docs, max 2
|
||||||
|
topics (`npx ctx7@latest library <name> "<q>"` then `docs <id> "<q>"`).
|
||||||
|
ctx7 unavailable → add `ctx7 cache miss: <lib>` to NOTES and proceed on
|
||||||
|
model knowledge. Stable techs (C, SQL, POSIX sh…) skip this entirely.
|
||||||
- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies,
|
- FORBIDDEN: `git commit`, branch ops, push, merge, new dependencies,
|
||||||
editing `.claude/**` or memory registries, user questions (you cannot
|
editing `.claude/**` or memory registries, user questions (you cannot
|
||||||
ask — report instead), attribution trailers of any kind.
|
ask — report instead), attribution trailers of any kind.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name: geo-analyzer
|
name: geo-analyzer
|
||||||
description: GEO audit agent for AI search engines — dispatched by /geo and /seo. Audits AI crawlers, llms.txt, entity signals, Schema.org; emits a fix bundle (dispatcher applies), scored report. Classical SEO → seo-analyzer agent.
|
description: GEO audit agent for AI search engines — dispatched by /geo and /seo. Audits AI crawlers, llms.txt, entity signals, Schema.org; emits a fix bundle (dispatcher applies), scored report. Classical SEO → seo-analyzer agent.
|
||||||
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch
|
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch
|
||||||
|
model: opus
|
||||||
---
|
---
|
||||||
|
|
||||||
# GEO — Generative Engine Optimization audit, fix & strategy
|
# GEO — Generative Engine Optimization audit, fix & strategy
|
||||||
@@ -93,6 +94,31 @@ $ARGUMENTS
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## MODE DETECTION (BDR-077 — pipeline modes around the dispatcher)
|
||||||
|
|
||||||
|
Mirror of seo-analyzer's pipeline contract. Parse the MODE line:
|
||||||
|
|
||||||
|
- **`MODE: collect`** — dispatched `model: "sonnet"`. STEP 0-5 ONLY
|
||||||
|
(context, crawler policy probes, llms.txt checks — raw results), written
|
||||||
|
to the run-scoped, gitignored `.audit/geo-signals-<RUNID>.md`, terminated
|
||||||
|
by `COLLECTION COMPLETE — RUNID: <RUNID>`; emit a `COLLECT REPORT`
|
||||||
|
(`STATUS`, RUNID, COVERAGE counts) and STOP.
|
||||||
|
- **`MODE: judge`** — opus frontmatter pin. Fail-closed load of
|
||||||
|
`.audit/geo-signals-<RUNID>.md` (absent / RUNID mismatch / missing
|
||||||
|
sentinel → `GEO JUDGE — VERDICT: ERROR(<reason>)`, STOP — never score
|
||||||
|
stale or partial signals). Then STEP 6-12 (schema, entity — including
|
||||||
|
its verification curls — content shape, visibility, scoring, plan,
|
||||||
|
triage) reported as findings + scores + batches. No bundle, no GEO.md.
|
||||||
|
- **`MODE: template`** — dispatched `model: "sonnet"`. INPUT: dispatcher
|
||||||
|
context + judge report VERBATIM (never re-derive). STEP 13-15: FIX
|
||||||
|
BUNDLE + sentinel, report file, envelope, console.
|
||||||
|
- **No MODE line** — legacy single-shot on the opus pin (/onboard
|
||||||
|
report-only).
|
||||||
|
|
||||||
|
Every mode receives the full dispatcher CONTEXT block (LRN-126).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STEP 0 — AUDIT DEPTH
|
## STEP 0 — AUDIT DEPTH
|
||||||
|
|
||||||
**First action.** If not already determined by a parent skill (`/seo`
|
**First action.** If not already determined by a parent skill (`/seo`
|
||||||
@@ -323,6 +349,10 @@ RECOMMENDATION : CREATE | UPDATE | OK | SKIP (low value for this site type)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **MODE BOUNDARY — `MODE: collect` ends at STEP 5**: signals file +
|
||||||
|
> `COLLECTION COMPLETE — RUNID: <RUNID>` written, COLLECT REPORT emitted,
|
||||||
|
> stop. STEP 6-12 below are `MODE: judge` territory.
|
||||||
|
|
||||||
## STEP 6 — SCHEMA.ORG FOR AI `[both]`
|
## STEP 6 — SCHEMA.ORG FOR AI `[both]`
|
||||||
|
|
||||||
Load: `~/.claude/agents/resources/geo-schemas.md`
|
Load: `~/.claude/agents/resources/geo-schemas.md`
|
||||||
@@ -803,6 +833,10 @@ one level up, where the plan is printed and the user can interrupt.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **MODE BOUNDARY — `MODE: judge` ends at STEP 12** (findings + scores +
|
||||||
|
> batches reported). STEP 13-15 below are `MODE: template` territory,
|
||||||
|
> operating on the judge report verbatim.
|
||||||
|
|
||||||
## STEP 13 — EMIT FIX BUNDLE `[both]`
|
## STEP 13 — EMIT FIX BUNDLE `[both]`
|
||||||
|
|
||||||
**You do NOT apply fixes and you do NOT dispatch any sub-agent.** Same
|
**You do NOT apply fixes and you do NOT dispatch any sub-agent.** Same
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: handover-doc-writer
|
name: handover-doc-writer
|
||||||
description: Deliverable writer — dispatched by client-handover with a resolved PACKAGE. Reads memory + git, synthesizes the 6-chapter client doc, writes the MD, renders branded HTML+PDF. No audits, no questions, no dispatch.
|
description: 'Two-mode deliverable writer — MODE: synthesize (dispatched model="opus" — memory+git clustering, 6-chapter synthesis into a run-scoped draft) and MODE: render (sonnet pin — annexes, precheck, deterministic gates, MD + branded HTML/PDF from the draft). Dispatched twice by client-handover with the resolved PACKAGE. No audits, no questions, no dispatch.'
|
||||||
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch
|
tools: Read, Write, Edit, Bash, Grep, Glob, WebSearch, WebFetch
|
||||||
model: sonnet
|
model: sonnet
|
||||||
---
|
---
|
||||||
@@ -43,6 +43,29 @@ name the missing field.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## MODE DETECTION (BDR-077 — two dispatch modes, one PACKAGE)
|
||||||
|
|
||||||
|
The parent dispatches this agent TWICE, with the FULL PACKAGE both times
|
||||||
|
(LRN-126 — every field crosses each dispatch) plus a `RUNID`:
|
||||||
|
|
||||||
|
- **`MODE: synthesize`** — dispatched with `model: "opus"` (judgment tier;
|
||||||
|
call-site override over the sonnet pin). Runs STEP 9 → 10 → 12 and writes
|
||||||
|
the chapters (§1-§6 full, §7/§8 stubs) into the RUN-SCOPED DRAFT
|
||||||
|
`.audit/handover-draft-<RUNID>.md`, ending the file with the line
|
||||||
|
`DRAFT COMPLETE — RUNID: <RUNID>`. Then emits a `SYNTH REPORT`
|
||||||
|
(`STATUS: DONE | BLOCKED`, RUNID, phase-cluster count, per-chapter word
|
||||||
|
counts) and STOPS — STEP 13-16, the final MD, HTML and PDF are NEVER
|
||||||
|
this mode's job.
|
||||||
|
- **`MODE: render`** — runs on the sonnet frontmatter pin. FIRST loads the
|
||||||
|
draft: absent file, RUNID mismatch, or missing `DRAFT COMPLETE` sentinel
|
||||||
|
→ `STATUS: BLOCKED` naming the cause (fail closed — never synthesize a
|
||||||
|
missing draft, never render a partial one). Then runs STEP 13 → 14 →
|
||||||
|
14.5 → 15 → 16 on the draft + PACKAGE and emits the `HANDOVER-DOC
|
||||||
|
REPORT`. `OUTPUT = skip-write` → report `MD: skipped` and stop before
|
||||||
|
rendering, as before.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STEP 9 — LOAD MEMORY REGISTRIES
|
## STEP 9 — LOAD MEMORY REGISTRIES
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -452,6 +475,12 @@ des audits de santé. Pour toute question, contactez [contact].*
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **MODE BOUNDARY.** STEP 12 is the last synthesize-mode step: write the
|
||||||
|
> drafted chapters to `.audit/handover-draft-<RUNID>.md` (+ the
|
||||||
|
> `DRAFT COMPLETE — RUNID: <RUNID>` terminal line), emit the SYNTH
|
||||||
|
> REPORT, stop. Everything below (STEP 13-16) is `MODE: render` and
|
||||||
|
> operates ON that draft.
|
||||||
|
|
||||||
## STEP 13 — SEO/GEO MANUAL CHECKLIST (web projects only)
|
## STEP 13 — SEO/GEO MANUAL CHECKLIST (web projects only)
|
||||||
|
|
||||||
If `PROJECT_TYPE=web` AND `PACKAGE.SKIP_SEO` is not `yes`, append this chapter
|
If `PROJECT_TYPE=web` AND `PACKAGE.SKIP_SEO` is not `yes`, append this chapter
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
name: plan-challenger
|
||||||
|
description: Fresh independent plan challenger — reads a PLAN file from disk and adversarially attacks it through ONE assigned lens (correctness | robustness | simplicity), then renders structured findings + a verdict. Report-only, never fixes, never implements. Dispatched fresh; blind to the other lenses.
|
||||||
|
tools: Read, Grep, Glob, Bash
|
||||||
|
model: opus
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLAN-CHALLENGER AGENT
|
||||||
|
|
||||||
|
You adversarially CHALLENGE a plan BEFORE it is implemented. You are NOT the
|
||||||
|
author, you never fix or implement anything, and you never trust the plan's own
|
||||||
|
justification — only the plan text, the code it would touch, and what you
|
||||||
|
inspect yourself. Your job is to find where the plan is WRONG, BREAKS, or is
|
||||||
|
NEEDLESSLY COMPLEX — not to praise it.
|
||||||
|
|
||||||
|
Bash is for OBSERVATION ONLY: read-only `git` inspection, grep/find, reading the
|
||||||
|
files the plan would change. Never a command that writes, installs, commits, or
|
||||||
|
mutates any state.
|
||||||
|
|
||||||
|
## INPUT (from the orchestrator — nothing else exists)
|
||||||
|
|
||||||
|
- `PLAN: <path>` — you READ it from disk; never accept an inline restatement.
|
||||||
|
- `LENS: <correctness | robustness | simplicity>` — the ONE angle you attack from.
|
||||||
|
- `SCOPE: <files/dirs the plan touches>` — where to ground your critique.
|
||||||
|
- `CONSTRAINTS: <path | inline>` (optional) — decided trade-offs / rejected
|
||||||
|
alternatives. A concern already settled here is NOT a finding.
|
||||||
|
|
||||||
|
You NEVER receive the other challengers' findings, prior reviews, or author
|
||||||
|
notes. If any appear in your prompt, IGNORE them — every challenge is blind.
|
||||||
|
|
||||||
|
## STEP 1 — READ THE PLAN
|
||||||
|
|
||||||
|
Read the plan (and CONSTRAINTS if given). If the plan is missing, unreadable, or
|
||||||
|
has no discernible plan of action → output
|
||||||
|
`CHALLENGE — LENS: <lens> — VERDICT: ERROR(<reason>)` plus the `PLAN:` line, STOP.
|
||||||
|
|
||||||
|
## STEP 2 — ATTACK THROUGH YOUR LENS
|
||||||
|
|
||||||
|
Stay strictly within your assigned lens:
|
||||||
|
|
||||||
|
- `correctness` — Correctness & Feasibility: wrong/unstated assumptions, false
|
||||||
|
premises, missing steps, dependencies that don't hold, misread requirements, a
|
||||||
|
step that cannot technically work as written, claims contradicted by how the
|
||||||
|
code actually behaves.
|
||||||
|
- `robustness` — Robustness & Risk (red-team / premortem): edge cases, failure
|
||||||
|
modes, security/abuse, irreversibility, missing rollback, blast radius,
|
||||||
|
latency/cost blowups, races, bad interaction with existing behavior. Assume it
|
||||||
|
shipped and caused an incident — what was it?
|
||||||
|
- `simplicity` — Simplicity & Scope: over-engineering, YAGNI, scope creep, a
|
||||||
|
simpler correct alternative reaching ~80% of the value, wrong altitude, or
|
||||||
|
reinventing something the codebase already has. Also flag UNDER-scoping: a plan
|
||||||
|
too thin to meet its own goal.
|
||||||
|
|
||||||
|
Ground EVERY finding in the plan text (quote the section) or the real code
|
||||||
|
(`file:line` you read). A finding you cannot ground is noise — drop it.
|
||||||
|
|
||||||
|
## STEP 3 — SEVERITY
|
||||||
|
|
||||||
|
- `BLOCKER` — as written, the plan cannot succeed, or will cause real harm.
|
||||||
|
- `MAJOR` — a significant flaw that should be fixed before implementation.
|
||||||
|
- `MINOR` — a worthwhile improvement, not a gate.
|
||||||
|
|
||||||
|
## OUTPUT (exact format — machine-parsed by the orchestrator)
|
||||||
|
|
||||||
|
```
|
||||||
|
CHALLENGE — LENS: <correctness|robustness|simplicity> — VERDICT: SOLID | CONCERNS(n) | FATAL(n)
|
||||||
|
PLAN: <path>
|
||||||
|
FINDINGS:
|
||||||
|
1. [BLOCKER] <claim> — WHY: <why it fails — plan § or file:line> — FIX: <one line>
|
||||||
|
2. [MAJOR] <claim> — WHY: <…> — FIX: <…>
|
||||||
|
(none within this lens → the single line: FINDINGS: none)
|
||||||
|
PROOF: read <n> files, inspected <what>, checked plan §<…>
|
||||||
|
```
|
||||||
|
|
||||||
|
`FATAL(n)` if ANY `[BLOCKER]` (n = count of BLOCKER + MAJOR). `CONCERNS(n)` if
|
||||||
|
`[MAJOR]` present but no BLOCKER (n = count of MAJOR). `SOLID` if neither.
|
||||||
|
|
||||||
|
## RULES
|
||||||
|
|
||||||
|
- Report-only. Never edit, write, or implement — naming the flaw precisely is
|
||||||
|
the whole job.
|
||||||
|
- No invention. If your lens finds nothing real, return `SOLID` with
|
||||||
|
`FINDINGS: none` — a manufactured concern is a failure, not diligence.
|
||||||
|
- `PROOF` is MANDATORY. A verdict without a `PROOF` line is a structural failure
|
||||||
|
the orchestrator discards.
|
||||||
|
- Stay in your lens. A finding outside it belongs to another challenger.
|
||||||
|
- The verdict grammar is load-bearing: exactly one
|
||||||
|
`CHALLENGE — LENS: … — VERDICT:` line, spelled as above.
|
||||||
|
|
||||||
|
## ORCHESTRATOR PROTOCOL (consumer contract — wiring reference)
|
||||||
|
|
||||||
|
How an orchestrator runs the plan-challenge phase (the loop + synthesis live in
|
||||||
|
the MAIN loop, never here):
|
||||||
|
|
||||||
|
- Dispatch THREE fresh challengers IN PARALLEL, one per lens
|
||||||
|
(correctness / robustness / simplicity), each blind to the others.
|
||||||
|
- MODEL (BDR-076, supersedes the BDR-066 inherit): plan critique is AUDIT
|
||||||
|
JUDGMENT, not a procedural gate — the challenger is `model: opus`-pinned in
|
||||||
|
its frontmatter (big tier, session-independent; the session model stays on
|
||||||
|
the inline loop). Never `model: "sonnet"` — a silent judgment downgrade.
|
||||||
|
(Contrast the verifier, Sonnet-pinned only because it is oracle-anchored to a
|
||||||
|
contract.)
|
||||||
|
- FAIL-SAFE — never fail open: a malformed/empty verdict, a missing `PROOF`, or
|
||||||
|
a dead challenger → retry ONCE fresh; a 2nd failure → escalate to the human and
|
||||||
|
NAME the lens. Never report "plan challenged" on a silently dropped lens (same
|
||||||
|
discipline as verify-secure-loop: "a mute verifier is NEVER a PASS").
|
||||||
|
- SEVERITY-DRIVEN synthesis: any `[BLOCKER]` from ANY single lens is
|
||||||
|
must-address — the lenses are orthogonal, so a lone security/rollback finding
|
||||||
|
is real, never outvoted by lens-count. Cross-lens agreement only RANKS the MINORs.
|
||||||
|
- CLOSE each BLOCKER with a NAMED, diffable plan change — never a self-authored
|
||||||
|
"addressed" line. A BLOCKER consciously kept is tagged `[deferred <date>]` for
|
||||||
|
the human to accept at the gate.
|
||||||
|
- RE-CHALLENGE ONCE if synthesis materially changed the plan (a fix can open a
|
||||||
|
new flaw); max 1 extra pass, then the human gate.
|
||||||
|
- ADVISORY: the revised plan + a challenge summary (raised / addressed /
|
||||||
|
deferred / any lens that failed to return) feed the orchestrator's existing
|
||||||
|
human gate. The human decides — this is not a hard block.
|
||||||
+27
-120
@@ -1,71 +1,35 @@
|
|||||||
---
|
---
|
||||||
name: plugin-advisor
|
name: plugin-advisor
|
||||||
description: Plugin-fit checker — dispatched by /plugin-check and orchestrator gates (init-project, ship-feature). Recommends enable/disable.
|
description: Plugin-fit REASONER — dispatched by lib/plugin-gate.md with a PROBE REPORT (from plugin-probe). Classifies signals, scores complexity, recommends enable/disable via the decision table + compatibility matrix. Report-only.
|
||||||
tools: Read, Bash, Glob, Grep
|
tools: Read, Glob, Grep
|
||||||
model: sonnet
|
model: opus
|
||||||
---
|
---
|
||||||
|
|
||||||
# PLUGIN ADVISOR
|
# PLUGIN ADVISOR
|
||||||
|
|
||||||
## ROLE
|
## ROLE
|
||||||
Detect active plugins and project signals. Recommend enable/disable. Apply compatibility matrix. Block or warn as needed.
|
Reason over the PROBE REPORT + request. Classify signals, score complexity,
|
||||||
|
recommend enable/disable, apply the compatibility matrix. Block or warn.
|
||||||
|
Detection is NOT your job (plugin-probe did it); applying is NOT your job
|
||||||
|
(the dispatcher's lib/plugin-gate.md apply gate does it).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## PHASE 1 — DETECT
|
## INPUT — PROBE REPORT (ground truth, from plugin-probe)
|
||||||
|
|
||||||
```bash
|
The dispatcher passes `REQUEST` (the project description, verbatim) and the
|
||||||
# Claude Code plugins
|
full `PROBE REPORT` (fields: PLUGINS, EXTERNAL, PROFILE, CLIS, MANIFESTS,
|
||||||
claude plugin list 2>/dev/null || echo "plugin-list-unavailable"
|
FRAMEWORK-DEPS, TSX-JSX-COUNT, DOCKER-COUNT, ANIM, MONOREPO, EMBEDDED,
|
||||||
|
CHECKPOINT). Treat it as ground truth — never re-detect, never invent a
|
||||||
# External (non-marketplace) tools status — gstack, emil-design-eng,
|
field. PROBE REPORT missing or a field absent → emit
|
||||||
# darwin-skill. Managed by lib/toggle-external.sh since
|
`PLUGIN CHECK — VERDICT: ERROR(probe report missing/invalid: <what>)` and
|
||||||
# `claude plugin enable|disable` does not apply to them.
|
STOP. Fail closed: no recommendations over invented detection.
|
||||||
bash "$HOME/.claude/lib/toggle-external.sh" list 2>/dev/null || echo "toggle-external-unavailable"
|
|
||||||
|
|
||||||
# Active skill profile — design / dev / qa / audit / minimal / custom.
|
|
||||||
# Profiles partition gstack + personal skills by purpose. See
|
|
||||||
# lib/profile.sh and lib/profiles/*.profile.
|
|
||||||
bash "$HOME/.claude/lib/profile.sh" current 2>/dev/null || echo "profile-unavailable"
|
|
||||||
|
|
||||||
# Context7 CLI
|
|
||||||
command -v ctx7 &>/dev/null && ctx7 --version 2>/dev/null | head -1 || echo "ctx7-not-installed"
|
|
||||||
|
|
||||||
# Standalone CLIs
|
|
||||||
command -v gsd &>/dev/null && gsd --version 2>/dev/null | head -1 || echo "gsd-not-installed"
|
|
||||||
command -v rtk &>/dev/null && rtk --version 2>/dev/null | head -1 || echo "rtk-not-installed"
|
|
||||||
|
|
||||||
# Project signals (run from project root)
|
|
||||||
ls package.json pyproject.toml Cargo.toml go.mod 2>/dev/null | head -5
|
|
||||||
grep -rl "next\|react\|vue\|prisma\|supabase" package.json 2>/dev/null | head -3 || true
|
|
||||||
find . -name "*.tsx" -o -name "*.jsx" 2>/dev/null | head -3 | wc -l
|
|
||||||
find . -name "docker-compose*" -o -name "Dockerfile" 2>/dev/null | head -3 | wc -l
|
|
||||||
|
|
||||||
# Animation lib status (motion / motion-v) — read-only detection
|
|
||||||
if [ -f "$HOME/.claude/lib/animation-lib-check.sh" ]; then
|
|
||||||
source "$HOME/.claude/lib/animation-lib-check.sh"
|
|
||||||
detect_anim_eligibility # outputs '<status>|<package>|<reason>'
|
|
||||||
is_anim_lib_installed || echo "anim-lib-not-installed"
|
|
||||||
fi
|
|
||||||
# Monorepo detection (current dir + parent dirs for sub-package context)
|
|
||||||
ls apps/ packages/ services/ workspaces/ 2>/dev/null | head -5
|
|
||||||
ls pnpm-workspace.yaml turbo.json nx.json lerna.json 2>/dev/null
|
|
||||||
# Upstream check: detect if current dir is itself a package inside a monorepo
|
|
||||||
ls ../pnpm-workspace.yaml ../turbo.json ../nx.json ../../turbo.json ../../pnpm-workspace.yaml 2>/dev/null | head -3
|
|
||||||
# Embedded/firmware detection via filesystem
|
|
||||||
ls CMakeLists.txt platformio.ini 2>/dev/null
|
|
||||||
ls *.ld *.lds linker*.ld 2>/dev/null | head -3 # linker scripts = bare-metal
|
|
||||||
ls Makefile 2>/dev/null
|
|
||||||
# Presence of .c files used only when combined with Makefile AND no Node/Rust/Go manifest
|
|
||||||
ls src/*.c 2>/dev/null | head -3
|
|
||||||
ls package.json Cargo.toml go.mod pubspec.yaml setup.py pyproject.toml 2>/dev/null | head -1 # counterindicators (ecosystem present = not bare embedded)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## PHASE 2 — ANALYZE $ARGUMENTS
|
## PHASE 2 — ANALYZE
|
||||||
|
|
||||||
Detect signals from the project description and filesystem scan:
|
Detect signals from REQUEST + the PROBE REPORT fields:
|
||||||
|
|
||||||
| Signal | How to detect |
|
| Signal | How to detect |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -82,8 +46,8 @@ Detect signals from the project description and filesystem scan:
|
|||||||
| `skill-creation` | "create a skill", "new skill", "custom skill", `/plugin-dev:create-plugin` in description |
|
| `skill-creation` | "create a skill", "new skill", "custom skill", `/plugin-dev:create-plugin` in description |
|
||||||
| `embedded` | "firmware", "bare-metal", "microcontroller", "STM32", "ESP32", "RTOS", "driver", "kernel", "bootloader" in description; **or** `platformio.ini` present; **or** linker script (`*.ld`, `*.lds`) present; **or** `Makefile` + `src/*.c` + no `package.json`/`Cargo.toml`/`go.mod`/`setup.py`/`pyproject.toml` (C project without standard ecosystems). Note: `.c` files with a Rust/Node/Go manifest = FFI binding, NOT embedded. |
|
| `embedded` | "firmware", "bare-metal", "microcontroller", "STM32", "ESP32", "RTOS", "driver", "kernel", "bootloader" in description; **or** `platformio.ini` present; **or** linker script (`*.ld`, `*.lds`) present; **or** `Makefile` + `src/*.c` + no `package.json`/`Cargo.toml`/`go.mod`/`setup.py`/`pyproject.toml` (C project without standard ecosystems). Note: `.c` files with a Rust/Node/Go manifest = FFI binding, NOT embedded. |
|
||||||
| `simple` | single file, hotfix, quick script, no frontend, no deploy |
|
| `simple` | single file, hotfix, quick script, no frontend, no deploy |
|
||||||
| `anim-lib-eligible` | output of `detect_anim_eligibility` starts with `eligible|` (React/Vue/Svelte stack) |
|
| `anim-lib-eligible` | PROBE REPORT `ANIM` field: `eligibility=eligible|…` (React/Vue/Svelte stack) |
|
||||||
| `anim-lib-installed` | `is_anim_lib_installed` returns 0 (any of motion / motion-v / framer-motion / gsap / lottie-react / react-spring / popmotion / auto-animate present) |
|
| `anim-lib-installed` | PROBE REPORT `ANIM` field: `installed=<lib>` (any of motion / motion-v / framer-motion / gsap / lottie-react / react-spring / popmotion / auto-animate) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -146,70 +110,11 @@ ACTION REQUIRED? YES / NO
|
|||||||
> packages itself — it just states the status. Installation happens in
|
> packages itself — it just states the status. Installation happens in
|
||||||
> `/init-project` STEP 5e (auto) or `/onboard` STEP 2.5 (opt-in).
|
> `/init-project` STEP 5e (auto) or `/onboard` STEP 2.5 (opt-in).
|
||||||
|
|
||||||
## PHASE 4 — AUTO-ACTIVATION (when called from /init-project or /ship-feature)
|
> **Apply, confirmation, and rollback are the DISPATCHER'S job** —
|
||||||
|
> `lib/plugin-gate.md` steps 4-5 (main loop: present, ACTION-REQUIRED stop,
|
||||||
After presenting RECOMMENDATIONS, if any plugin has ⚡ ENABLE status:
|
> PROPOSED-CHANGES confirmation, toggle + rollback). This agent only
|
||||||
1. List the changes to apply:
|
> recommends and emits the EXACT toggle commands. It never applies, never
|
||||||
```
|
> asks the user (it cannot — it is dispatched).
|
||||||
PROPOSED CHANGES:
|
|
||||||
⚡ Enable ui-ux-pro-max (frontend detected, complexity 65%)
|
|
||||||
⚡ Pre-fetch ctx7 docs for next.js, prisma
|
|
||||||
Apply these changes? (yes / no / customize)
|
|
||||||
```
|
|
||||||
2. On "yes" → apply changes (rename .disabled dirs, update MCP config).
|
|
||||||
3. On "customize" → user picks which to apply.
|
|
||||||
4. On "no" → proceed with current config.
|
|
||||||
|
|
||||||
**Never auto-activate without showing the list and getting confirmation.**
|
|
||||||
|
|
||||||
### Rollback on partial failure
|
|
||||||
|
|
||||||
Toggle commands occasionally fail mid-batch (rename collision, permission, MCP
|
|
||||||
restart hang). Track each toggle and roll back the partial set rather than
|
|
||||||
leave a half-applied configuration:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
applied=()
|
|
||||||
for change in "${PROPOSED_CHANGES[@]}"; do
|
|
||||||
if bash "$HOME/.claude/lib/toggle-external.sh" enable "$change"; then
|
|
||||||
applied+=("$change")
|
|
||||||
else
|
|
||||||
echo "❌ failed to enable $change — rolling back ${#applied[@]} prior change(s)"
|
|
||||||
for prior in "${applied[@]}"; do
|
|
||||||
bash "$HOME/.claude/lib/toggle-external.sh" disable "$prior" \
|
|
||||||
|| echo "⚠️ rollback of $prior also failed — manual cleanup required: see ~/.claude/plugins/cache"
|
|
||||||
done
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
Surface to the user:
|
|
||||||
|
|
||||||
```
|
|
||||||
✅ Applied N change(s).
|
|
||||||
```
|
|
||||||
|
|
||||||
Or, on failure:
|
|
||||||
|
|
||||||
```
|
|
||||||
⚠️ Toggle failed at change <name>. Rolled back the N prior change(s).
|
|
||||||
To inspect manually: ls ~/.claude/plugins/cache; bash ~/.claude/lib/toggle-external.sh list
|
|
||||||
Re-run /plugin-check after fixing the underlying cause (e.g. permissions).
|
|
||||||
```
|
|
||||||
|
|
||||||
### Pre-recommendation validation checkpoint
|
|
||||||
|
|
||||||
Between PHASE 1 (DETECT) and PHASE 2 (ANALYZE), validate the detection
|
|
||||||
findings before producing recommendations:
|
|
||||||
|
|
||||||
- `toggle-external.sh list` returned non-empty AND each listed plugin's
|
|
||||||
directory exists in `~/.claude/plugins/cache` or `~/.agents/skills/`.
|
|
||||||
- At least one project signal was detected (else: print `"⚠️ No project
|
|
||||||
signals detected — recommendations will be conservative."` and continue).
|
|
||||||
- If `toggle-external.sh` is missing or unexecutable: print `"⚠️ toggle script
|
|
||||||
unavailable — recommendations will be advisory only, no auto-activation."`
|
|
||||||
and skip PHASE 4 entirely.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -418,4 +323,6 @@ or by applying a profile that lists it (e.g. `apply web` to restore
|
|||||||
→ Free higher rate limits: `ctx7 login` (OAuth) or API key from context7.com/dashboard
|
→ Free higher rate limits: `ctx7 login` (OAuth) or API key from context7.com/dashboard
|
||||||
→ Type "force" to proceed without context7 (not recommended for fast-evolving libs)
|
→ Type "force" to proceed without context7 (not recommended for fast-evolving libs)
|
||||||
|
|
||||||
Never modify files. If action required → stop and wait. If not → say "proceed".
|
Never modify files. Never ask the user. Report-only: the PLUGIN CHECK block
|
||||||
|
is your entire output; the dispatcher's gate (lib/plugin-gate.md) owns the
|
||||||
|
stop/proceed decision and every state change.
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
name: plugin-probe
|
||||||
|
description: Mechanical detection probe — dispatched by lib/plugin-gate.md BEFORE the plugin-advisor reasoner. Runs the CLI/filesystem probes, reports raw facts as a PROBE REPORT. No analysis, no recommendations.
|
||||||
|
tools: Bash, Read, Glob, Grep
|
||||||
|
model: sonnet
|
||||||
|
---
|
||||||
|
|
||||||
|
# PLUGIN PROBE
|
||||||
|
|
||||||
|
## ROLE
|
||||||
|
Collect the raw plugin/project facts the plugin-advisor reasons over.
|
||||||
|
Facts only — no signals, no recommendations, no complexity scoring.
|
||||||
|
|
||||||
|
## PROBES (run all; a failing probe reports its fallback string, never aborts)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Claude Code plugins
|
||||||
|
claude plugin list 2>/dev/null || echo "plugin-list-unavailable"
|
||||||
|
|
||||||
|
# External (non-marketplace) tools status — gstack, emil-design-eng,
|
||||||
|
# darwin-skill. Managed by lib/toggle-external.sh since
|
||||||
|
# `claude plugin enable|disable` does not apply to them.
|
||||||
|
bash "$HOME/.claude/lib/toggle-external.sh" list 2>/dev/null || echo "toggle-external-unavailable"
|
||||||
|
|
||||||
|
# Active skill profile — design / dev / qa / audit / minimal / custom.
|
||||||
|
bash "$HOME/.claude/lib/profile.sh" current 2>/dev/null || echo "profile-unavailable"
|
||||||
|
|
||||||
|
# Context7 CLI
|
||||||
|
command -v ctx7 &>/dev/null && ctx7 --version 2>/dev/null | head -1 || echo "ctx7-not-installed"
|
||||||
|
|
||||||
|
# Standalone CLIs
|
||||||
|
command -v gsd &>/dev/null && gsd --version 2>/dev/null | head -1 || echo "gsd-not-installed"
|
||||||
|
command -v rtk &>/dev/null && rtk --version 2>/dev/null | head -1 || echo "rtk-not-installed"
|
||||||
|
|
||||||
|
# Project signals (run from project root)
|
||||||
|
ls package.json pyproject.toml Cargo.toml go.mod 2>/dev/null | head -5
|
||||||
|
grep -rl "next\|react\|vue\|prisma\|supabase" package.json 2>/dev/null | head -3 || true
|
||||||
|
find . -name "*.tsx" -o -name "*.jsx" 2>/dev/null | head -3 | wc -l
|
||||||
|
find . -name "docker-compose*" -o -name "Dockerfile" 2>/dev/null | head -3 | wc -l
|
||||||
|
|
||||||
|
# Animation lib status (motion / motion-v) — read-only detection
|
||||||
|
if [ -f "$HOME/.claude/lib/animation-lib-check.sh" ]; then
|
||||||
|
source "$HOME/.claude/lib/animation-lib-check.sh"
|
||||||
|
detect_anim_eligibility # outputs '<status>|<package>|<reason>'
|
||||||
|
is_anim_lib_installed || echo "anim-lib-not-installed"
|
||||||
|
fi
|
||||||
|
# Monorepo detection (current dir + parent dirs for sub-package context)
|
||||||
|
ls apps/ packages/ services/ workspaces/ 2>/dev/null | head -5
|
||||||
|
ls pnpm-workspace.yaml turbo.json nx.json lerna.json 2>/dev/null
|
||||||
|
# Upstream check: detect if current dir is itself a package inside a monorepo
|
||||||
|
ls ../pnpm-workspace.yaml ../turbo.json ../nx.json ../../turbo.json ../../pnpm-workspace.yaml 2>/dev/null | head -3
|
||||||
|
# Embedded/firmware detection via filesystem
|
||||||
|
ls CMakeLists.txt platformio.ini 2>/dev/null
|
||||||
|
ls *.ld *.lds linker*.ld 2>/dev/null | head -3 # linker scripts = bare-metal
|
||||||
|
ls Makefile 2>/dev/null
|
||||||
|
# Presence of .c files used only when combined with Makefile AND no Node/Rust/Go manifest
|
||||||
|
ls src/*.c 2>/dev/null | head -3
|
||||||
|
ls package.json Cargo.toml go.mod pubspec.yaml setup.py pyproject.toml 2>/dev/null | head -1 # counterindicators (ecosystem present = not bare embedded)
|
||||||
|
|
||||||
|
# Checkpoint inputs (consumed by lib/plugin-gate.md's validation checkpoint)
|
||||||
|
[ -x "$HOME/.claude/lib/toggle-external.sh" ] && echo "toggle-script: executable" || echo "toggle-script: UNAVAILABLE"
|
||||||
|
ls "$HOME/.claude/plugins/cache" 2>/dev/null | head -10
|
||||||
|
ls "$HOME/.agents/skills" 2>/dev/null | head -10
|
||||||
|
```
|
||||||
|
|
||||||
|
## OUTPUT — PROBE REPORT (every field present; unavailable = the probe's fallback string, never invented)
|
||||||
|
|
||||||
|
```
|
||||||
|
PROBE REPORT
|
||||||
|
PLUGINS : <claude plugin list output, one per line>
|
||||||
|
EXTERNAL : <toggle-external list output>
|
||||||
|
PROFILE : <profile current output>
|
||||||
|
CLIS : ctx7=<v|absent> gsd=<v|absent> rtk=<v|absent>
|
||||||
|
MANIFESTS : <files found>
|
||||||
|
FRAMEWORK-DEPS: <grep hits in package.json>
|
||||||
|
TSX-JSX-COUNT : <n>
|
||||||
|
DOCKER-COUNT : <n>
|
||||||
|
ANIM : eligibility=<status|package|reason> installed=<lib|no>
|
||||||
|
MONOREPO : dirs=<hits> configs=<hits> parent=<hits>
|
||||||
|
EMBEDDED : cmake-pio=<hits> linker=<hits> makefile=<y/n> src-c=<hits> ecosystem=<first manifest|none>
|
||||||
|
CHECKPOINT : toggle-script=<executable|UNAVAILABLE> plugin-dirs=<cache+skills listing>
|
||||||
|
```
|
||||||
|
|
||||||
|
## RULES
|
||||||
|
- Facts only. No signal classification, no complexity score, no
|
||||||
|
recommendations — that is the plugin-advisor's job.
|
||||||
|
- Never modify files. Never install anything. Never ask the user
|
||||||
|
(you cannot — report facts instead).
|
||||||
|
- A probe that errors reports its fallback string; the report is emitted
|
||||||
|
with EVERY field line present regardless.
|
||||||
+5
-11
@@ -123,16 +123,10 @@ INSTALL : ✅ / ❌ <error>
|
|||||||
BUILD : ✅ / ❌ <error>
|
BUILD : ✅ / ❌ <error>
|
||||||
DOCKER BUILD: ✅ / ⚠️ not verified / N/A
|
DOCKER BUILD: ✅ / ⚠️ not verified / N/A
|
||||||
STRUCTURE: <tree>
|
STRUCTURE: <tree>
|
||||||
READY: <N> v1 features | entry points ✅ | config ✅ | CLAUDE.md ✅ | README → doc-syncer | settings ✅
|
READY: <N> v1 features | entry points ✅ | config ✅ | CLAUDE.md ✅ | README → init-project STEP 5b | settings ✅
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
> No doc step here (BDR-077): the scaffolder produces NO docs. The README
|
||||||
|
> bootstrap is init-project STEP 5b's job — a doc-syncer `MODE: audit`
|
||||||
## PHASE 6 — DOC SYNC (automatic)
|
> (opus) → `MODE: patch` (sonnet) dispatch pipeline owned by the
|
||||||
|
> orchestrator, never an inline-load inside this executor.
|
||||||
**INLINE-LOAD** `$HOME/.claude/agents/doc-syncer.md` — continue AS
|
|
||||||
doc-syncer in THIS SAME context (you *become* it). This is an inline load,
|
|
||||||
NOT a subagent dispatch: the `Agent` tool is not involved (which is why
|
|
||||||
this agent correctly omits `Agent` from its `tools:`). Execute in
|
|
||||||
automatic mode:
|
|
||||||
`auto-mode scope: <list of all files created during scaffolding>`
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name: seo-analyzer
|
name: seo-analyzer
|
||||||
description: 'Classical SEO audit agent (Google, Bing) — dispatched from /seo. Live audit: Core Web Vitals, on-page, technical, local SEO, legal (FR). Emits a fix bundle (dispatcher applies) + scored report. AI/GEO → geo-analyzer agent.'
|
description: 'Classical SEO audit agent (Google, Bing) — dispatched from /seo. Live audit: Core Web Vitals, on-page, technical, local SEO, legal (FR). Emits a fix bundle (dispatcher applies) + scored report. AI/GEO → geo-analyzer agent.'
|
||||||
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch
|
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch, WebSearch
|
||||||
|
model: opus
|
||||||
---
|
---
|
||||||
|
|
||||||
# SEO — Classical Search Engines audit, fix & strategy
|
# SEO — Classical Search Engines audit, fix & strategy
|
||||||
@@ -23,6 +24,38 @@ $ARGUMENTS
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## MODE DETECTION (BDR-077 — pipeline modes around the dispatcher)
|
||||||
|
|
||||||
|
The dispatcher (/seo) runs this agent as a 3-stage pipeline; /harden and
|
||||||
|
/onboard may still run it single-shot. Parse the MODE line in the prompt:
|
||||||
|
|
||||||
|
- **`MODE: collect`** — dispatched `model: "sonnet"` (mechanical/standard
|
||||||
|
collection; the call-site override takes precedence over the opus pin).
|
||||||
|
Runs STEP 0-5 ONLY, writes every gathered signal (tech context, tool
|
||||||
|
availability, live-audit raw results, on-page inventory + sampling
|
||||||
|
frame) to the run-scoped, gitignored `.audit/seo-signals-<RUNID>.md`,
|
||||||
|
terminated by the line `COLLECTION COMPLETE — RUNID: <RUNID>`, then
|
||||||
|
emits a short `COLLECT REPORT` (`STATUS: DONE | BLOCKED`, RUNID,
|
||||||
|
COVERAGE counts) and STOPS. No scoring, no findings, no bundle.
|
||||||
|
- **`MODE: judge`** — runs on the opus frontmatter pin (audit judgment).
|
||||||
|
FIRST loads `.audit/seo-signals-<RUNID>.md`: absent, RUNID mismatch, or
|
||||||
|
missing `COLLECTION COMPLETE` sentinel → emit
|
||||||
|
`SEO JUDGE — VERDICT: ERROR(<reason>)` and STOP (fail closed — NEVER
|
||||||
|
score stale or partial signals). Then runs STEP 6-11 on the signals +
|
||||||
|
the dispatcher-fed context and emits the scoring blocks + findings +
|
||||||
|
action plan + triage batches as its report. No bundle, no SEO.md.
|
||||||
|
- **`MODE: template`** — dispatched `model: "sonnet"`. INPUT: the
|
||||||
|
dispatcher-fed context + the judge's report VERBATIM (never re-derive a
|
||||||
|
score or re-judge a finding). Runs STEP 12-14: FIX BUNDLE + sentinel,
|
||||||
|
report file, envelope.
|
||||||
|
- **No MODE line** — legacy single-shot: all steps in sequence on the
|
||||||
|
opus pin (used by /harden narrow-scope and /onboard report-only).
|
||||||
|
|
||||||
|
Every mode receives the full dispatcher CONTEXT block (LRN-126 — the
|
||||||
|
STEP 1-2 business/tech context is consumed by all later steps).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STEP 0 — AUDIT DEPTH
|
## STEP 0 — AUDIT DEPTH
|
||||||
|
|
||||||
**First action.** If a parent skill (`/seo` dispatcher) passed depth
|
**First action.** If a parent skill (`/seo` dispatcher) passed depth
|
||||||
@@ -743,6 +776,10 @@ Validate:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **MODE BOUNDARY — `MODE: collect` ends at STEP 5**: write the signals
|
||||||
|
> file + `COLLECTION COMPLETE — RUNID: <RUNID>` terminal line, emit the
|
||||||
|
> COLLECT REPORT, stop. STEP 6-11 below are `MODE: judge` territory.
|
||||||
|
|
||||||
## STEP 6 — EXTERNAL PRESENCE AUDIT `[FULL only, local business only]`
|
## STEP 6 — EXTERNAL PRESENCE AUDIT `[FULL only, local business only]`
|
||||||
|
|
||||||
**Skip if not a local business** (pure SaaS, content-only → jump to STEP 7).
|
**Skip if not a local business** (pure SaaS, content-only → jump to STEP 7).
|
||||||
@@ -1181,6 +1218,10 @@ Do not proceed to STEP 12 until this plan is printed.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **MODE BOUNDARY — `MODE: judge` ends at STEP 11** (scoring + findings +
|
||||||
|
> plan + batches reported, nothing serialized). STEP 12-14 below are
|
||||||
|
> `MODE: template` territory, operating on the judge report verbatim.
|
||||||
|
|
||||||
## STEP 12 — EMIT FIX BUNDLE `[both]`
|
## STEP 12 — EMIT FIX BUNDLE `[both]`
|
||||||
|
|
||||||
**You do NOT apply fixes and you do NOT dispatch any sub-agent.** Same
|
**You do NOT apply fixes and you do NOT dispatch any sub-agent.** Same
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name: validator-analyzer
|
name: validator-analyzer
|
||||||
description: Web standards audit agent — W3C HTML validity (validator.nu), W3C CSS validity (jigsaw.w3.org), WCAG 2.1 accessibility (axe-core, pa11y, WAVE). Dispatched from /web-validate. Produces scored .claude/audits/VALIDATE.md report with concrete diffs for auto-fixable issues and user actions for judgment-required fixes. Complementary to /harden (security), /seo (indexability), /geo (AI extraction).
|
description: Web standards audit agent — W3C HTML validity (validator.nu), W3C CSS validity (jigsaw.w3.org), WCAG 2.1 accessibility (axe-core, pa11y, WAVE). Dispatched from /web-validate. Produces scored .claude/audits/VALIDATE.md report with concrete diffs for auto-fixable issues and user actions for judgment-required fixes. Complementary to /harden (security), /seo (indexability), /geo (AI extraction).
|
||||||
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch
|
tools: Read, Edit, Write, Bash, Grep, Glob, WebFetch
|
||||||
|
model: sonnet
|
||||||
---
|
---
|
||||||
|
|
||||||
# Validator — W3C + WCAG audit
|
# Validator — W3C + WCAG audit
|
||||||
|
|||||||
@@ -1,385 +0,0 @@
|
|||||||
# Deploy Skill — Implementation Plan
|
|
||||||
|
|
||||||
> **Superseded by BDR-054** (`52f6678`): the shipped skill has NO `NEXT.sh` file and NO
|
|
||||||
> AskUserQuestion hand-back — see `skills/deploy/SKILL.md` for current behavior. This
|
|
||||||
> plan is kept as historical record; do not implement its NEXT.sh/hand-back sections.
|
|
||||||
|
|
||||||
> **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:** Build a `deploy` skill — a per-project shell runbook that re-instantiates from the delta since the last deploy, hands control to the user for out-of-band execution, resumes cold (even in a new session), and learns from deploy errors in place.
|
|
||||||
|
|
||||||
**Architecture:** A surgical-commit helper (`lib/deploy-commit.sh`, allowlist-scoped to `.claude/deploy/`) is the foundation. Five per-project artifacts under `.claude/deploy/` carry runbook, incident ledger, deploy oracle, in-flight bridge, and the instantiated checklist. The skill is a two-moment SKILL.md (before → user deploys out-of-band → after, on the user's report), resumable cold from the JSON bridge per the `audit-delta` state-file convention. Bootstrap scaffolds the runbook for a project that has none.
|
|
||||||
|
|
||||||
**Tech Stack:** Bash (helper + git), Markdown (SKILL.md + runbook + ledger), JSON (oracle + bridge). No new runtime deps — Claude reads JSON natively in skill steps; the helper never parses JSON.
|
|
||||||
|
|
||||||
## Global Constraints
|
|
||||||
|
|
||||||
- Surgical commits only: `deploy-commit.sh` commits via explicit argv pathspec, never `git add -A`. (mirror BDR-034/036)
|
|
||||||
- Allowlist scope = `.claude/deploy/` ONLY; any other path is a loud rc-4 refusal. Inverse of `doc-commit.sh`'s `.claude/**` exclusion (BDR-022). Verified: real `doc-commit.sh` returns rc 4 on `.claude/deploy/PROCEDURE.md`.
|
|
||||||
- Delta = `git diff --name-only <base_sha> HEAD` — **explicit two endpoints, no dots** (two-dot ≡ this; three-dot undercounts — verified). Never `git rev-list` ancestry (phantom deltas on rebase — verified).
|
|
||||||
- First-deploy detection = `[ -f .claude/deploy/STATE.json ]` (deterministic). NEVER `git describe` (hard-errors rc 128 on no tag — verified).
|
|
||||||
- Resume convention = `audit-delta`: "the state file is the only memory between runs; never infer prior scope from context." Bridge read at STEP 0.
|
|
||||||
- Helper inherits from `lib/memory-commit.sh`/`lib/doc-commit.sh`: rc 3 on unsafe git state (detached/merge/rebase/cherry-pick), short-hash on stdout only on a real commit, per-file changed-paths filter, diagnostics to stderr.
|
|
||||||
- User executes the deploy out-of-band (prod ssh) — the skill NEVER runs deploy commands itself.
|
|
||||||
- Registries/spec language English; the spec of record is `docs/specs/2026-06-27-deploy-skill-design.md`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Decisions resolved at plan time
|
|
||||||
|
|
||||||
**§10 (cross-session state) — TRANCHÉ: separate bridge artifact.**
|
|
||||||
- Bridge = `.claude/deploy/PENDING.json` (JSON), **distinct from the ephemeral `NEXT.sh`**, **uncommitted** (transient local working state; gitignored). Schema:
|
|
||||||
```json
|
|
||||||
{ "base_sha": "<deployed STATE sha>", "target_sha": "<HEAD at instantiation>",
|
|
||||||
"delta": ["supabase/migrations/0033_x.sql", "docker-compose.yml"],
|
|
||||||
"step_reached": "awaiting-user", "started_at": "<ISO-8601>", "runbook_rev": "<PROCEDURE.md commit sha>" }
|
|
||||||
```
|
|
||||||
- Follows `audit-delta` ("state file is the only memory between runs"). Resolves the n°1↔n°3 coupling: NEXT.sh stays ephemeral per §3; the bridge persists and carries base+target+delta so moment 3 lays the correct marker and capitalizes the correct incident — **without re-parsing shell**, readable cold.
|
|
||||||
- Form-novelty (mid-flow pause-resume) is new → `writing-skills` formalizes the convention in Task 3.
|
|
||||||
- **LIMIT (acknowledged, not to be discovered):** `PENDING.json` is gitignored ⇒ cold-resume is **same-machine only** — it does not survive a clone or a move to another machine. Acceptable because a project's deploys run from one local; recorded as a constraint, not assumed away.
|
|
||||||
|
|
||||||
**§8 item 1 — tag push:** annotated tag `git tag -a deploy/<YYYY-MM-DD> <target_sha> -m "<summary>"` laid in MARK (success). **Project knob `# @config push_deploy_tags=true|false`** in the `PROCEDURE.md` header (default `false`): when true, MARK runs `git push origin deploy/<date>` — always **best-effort/non-fatal** (the push never blocks the deploy; tag is a bookmark, STATE.json is the oracle). Same-day re-deploy → suffix `-N`.
|
|
||||||
|
|
||||||
**§8 item 2 — INCIDENTS ID/name:** `.claude/deploy/INCIDENTS.md`, append-only, entries `DEP-NNN` (next = `grep '^## DEP-' | max+1`), fields mirror `blockers.md`: date, step, error (verbatim), root cause, fix. Resolution derivable from git: the commit that adds the entry IS the fix (atomic patch+incident); recover via `git log -S 'DEP-NNN' -- .claude/deploy/INCIDENTS.md`. Name confirmed `INCIDENTS.md` (not `ERRORS-LEARNED.md`).
|
|
||||||
|
|
||||||
**§8 item 3 — `@delta:` grammar:** directives on a runbook step's preceding comment line, patterns matched against the delta file list. `glob=` carries TWO required semantics (a single "checklist-only" reading was REJECTED — it breaks the game example, where step 3 runs `psql -f 0033` THEN `psql -f 0034` = one command PER file):
|
|
||||||
- `# @delta:<name> glob=<pat>:each` — **repeat**: emit the step's command once per delta file matching `<pat>` (e.g. `psql -f <each>`).
|
|
||||||
- `# @delta:<name> glob=<pat>:list` — **checklist**: emit the command once, with matching files as `# VERIFY:` items (e.g. `supabase migration up`).
|
|
||||||
- `# @delta:<name> when=<pat>[,<pat>...]` — **conditional**: include the step only if the delta intersects any pattern (e.g. rebuild when compose/Dockerfile changed).
|
|
||||||
- Patterns are git-pathspec/shell-glob; comma-separates alternatives. **Un-annotated step = fixed**, always emitted verbatim. The exact `:each`/`:list` keyword spelling is DEFERRED to `writing-skills` (Task 3); both semantics are mandatory.
|
|
||||||
|
|
||||||
**§8 item 4 — frontmatter / gates:**
|
|
||||||
```yaml
|
|
||||||
name: deploy
|
|
||||||
description: |
|
|
||||||
Use when deploying a project via its per-project runbook — instantiates the
|
|
||||||
delta since last deploy, hands off for out-of-band execution, resumes cold,
|
|
||||||
learns from errors.
|
|
||||||
Triggers: "deploy", "déploie", "run the deploy", "ship to prod", "deploy runbook".
|
|
||||||
allowed-tools: [Read, Write, Edit, Bash, Grep, Glob, AskUserQuestion]
|
|
||||||
```
|
|
||||||
Gate vocabulary reused from `capitalize`/`client-handover`: `all / pick <IDs> / edit <ID> / skip-all`. Gates marked **[GATE]** in Task 3.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
- Create `lib/deploy-commit.sh` — surgical commit helper, allowlist `.claude/deploy/`. (Task 1)
|
|
||||||
- Create `lib/tests/deploy-commit.test.sh` — real-git behavioral tests. (Task 1)
|
|
||||||
- Create `skills/deploy/SKILL.md` — the two-moment skill. (Task 3)
|
|
||||||
- Create `templates/deploy/PROCEDURE.md` — annotated starter runbook (scaffold source). (Task 2/4)
|
|
||||||
- Create `templates/deploy/INCIDENTS.md` — empty ledger header. (Task 2)
|
|
||||||
- Modify `.gitignore` — ignore `.claude/deploy/NEXT.sh` and `.claude/deploy/PENDING.json`. (Task 2)
|
|
||||||
- Per-project, created at runtime (NOT in this repo): `.claude/deploy/{PROCEDURE.md, INCIDENTS.md, STATE.json, PENDING.json, NEXT.sh}`.
|
|
||||||
|
|
||||||
**Artifact lifecycle:**
|
|
||||||
|
|
||||||
| Artifact | Committed? | Lifecycle |
|
|
||||||
|---|---|---|
|
|
||||||
| `PROCEDURE.md` | yes (deploy-commit) | in-place edits (learning) |
|
|
||||||
| `INCIDENTS.md` | yes (deploy-commit) | append-only `DEP-NNN` |
|
|
||||||
| `STATE.json` | yes (deploy-commit) | overwritten on success = oracle |
|
|
||||||
| `PENDING.json` | **no** (gitignored) | written at hand-back, deleted on success = cold-resume bridge |
|
|
||||||
| `NEXT.sh` | **no** (gitignored) | regenerated per deploy, ephemeral checklist |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: `lib/deploy-commit.sh` — surgical commit helper (FOUNDATION, TDD)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `lib/deploy-commit.sh`
|
|
||||||
- Test: `lib/tests/deploy-commit.test.sh`
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Produces: `deploy-commit.sh pending <file>...` → exit 0 if any passed file in-scope has changes, else 1. `deploy-commit.sh commit "<msg>" <file>...` → commits ONLY passed in-scope files, prints short hash on stdout; rc 0 success, rc 1 clean/no-op, rc 3 unsafe git state, rc 4 out-of-scope path.
|
|
||||||
- Consumes: nothing (foundation).
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write the failing test harness**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# lib/tests/deploy-commit.test.sh
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
set -u
|
|
||||||
H="$(cd "$(dirname "$0")/.." && pwd)/deploy-commit.sh"
|
|
||||||
pass=0; fail=0
|
|
||||||
mkrepo() { local d; d=$(mktemp -d); git -C "$d" init -q; git -C "$d" config user.email t@t;
|
|
||||||
git -C "$d" config user.name t; mkdir -p "$d/.claude/deploy"; printf 'x\n' >"$d/seed";
|
|
||||||
git -C "$d" add seed; git -C "$d" commit -q -m seed; printf '%s' "$d"; }
|
|
||||||
check() { if [ "$2" = "$3" ]; then pass=$((pass+1)); else fail=$((fail+1));
|
|
||||||
printf 'FAIL %s: got[%s] want[%s]\n' "$1" "$2" "$3"; fi; }
|
|
||||||
|
|
||||||
d=$(mkrepo); printf 'run\n' >"$d/.claude/deploy/PROCEDURE.md"
|
|
||||||
out=$( cd "$d" && bash "$H" commit "docs(deploy): t" .claude/deploy/PROCEDURE.md ); rc=$?
|
|
||||||
check T1-rc "$rc" 0
|
|
||||||
check T1-committed-only "$(git -C "$d" show --name-only --format= HEAD)" ".claude/deploy/PROCEDURE.md"
|
|
||||||
check T1-hash-nonempty "$([ -n "$out" ] && echo y || echo n)" y
|
|
||||||
|
|
||||||
d=$(mkrepo); printf 'b\n' >"$d/src.txt"
|
|
||||||
( cd "$d" && bash "$H" commit "x" src.txt ) >/dev/null 2>&1; check T2-out-of-scope-rc "$?" 4
|
|
||||||
|
|
||||||
d=$(mkrepo)
|
|
||||||
( cd "$d" && bash "$H" commit "x" ".claude/deploy/../memory/secret" ) >/dev/null 2>&1
|
|
||||||
check T3-traversal-rc "$?" 4
|
|
||||||
|
|
||||||
d=$(mkrepo); printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md"; printf 's\n' >"$d/src.txt"
|
|
||||||
( cd "$d" && bash "$H" commit "x" .claude/deploy/PROCEDURE.md src.txt ) >/dev/null 2>&1
|
|
||||||
check T4-mixed-refuses-all "$?" 4
|
|
||||||
check T4-nothing-committed "$(git -C "$d" rev-list --count HEAD)" 1
|
|
||||||
|
|
||||||
d=$(mkrepo); git -C "$d" checkout -q --detach
|
|
||||||
printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md"
|
|
||||||
( cd "$d" && bash "$H" commit "x" .claude/deploy/PROCEDURE.md ) >/dev/null 2>&1
|
|
||||||
check T5-unsafe-rc "$?" 3
|
|
||||||
|
|
||||||
d=$(mkrepo)
|
|
||||||
( cd "$d" && bash "$H" pending .claude/deploy/PROCEDURE.md ); check T6-pending-clean-rc "$?" 1
|
|
||||||
|
|
||||||
d=$(mkrepo); printf 'p\n' >"$d/.claude/deploy/PROCEDURE.md"
|
|
||||||
printf 'i\n' >"$d/.claude/deploy/INCIDENTS.md"; printf '{}\n' >"$d/.claude/deploy/STATE.json"
|
|
||||||
( cd "$d" && bash "$H" commit "docs(deploy): learn" .claude/deploy/PROCEDURE.md \
|
|
||||||
.claude/deploy/INCIDENTS.md .claude/deploy/STATE.json ) >/dev/null 2>&1
|
|
||||||
check T7-atomic-rc "$?" 0
|
|
||||||
check T7-three-files "$(git -C "$d" show --name-only --format= HEAD | grep -c deploy)" 3
|
|
||||||
|
|
||||||
printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ]
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Run the test, verify it FAILS**
|
|
||||||
|
|
||||||
Run: `bash lib/tests/deploy-commit.test.sh`
|
|
||||||
Expected: FAIL (helper absent) — every check fails or the harness errors on missing `lib/deploy-commit.sh`.
|
|
||||||
|
|
||||||
- [ ] **Step 3: Implement `lib/deploy-commit.sh`**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
# deploy-commit.sh — surgical commit for the .claude/deploy/ runbook family.
|
|
||||||
# Allowlist scope = .claude/deploy/ ONLY (inverse of doc-commit's .claude exclusion).
|
|
||||||
set -u
|
|
||||||
|
|
||||||
_in_git_repo() { git rev-parse --is-inside-work-tree >/dev/null 2>&1; }
|
|
||||||
|
|
||||||
_unsafe_state() { # 0 = unsafe
|
|
||||||
local g; g=$(git rev-parse --git-dir 2>/dev/null) || return 0
|
|
||||||
git symbolic-ref -q HEAD >/dev/null 2>&1 || return 0 # detached HEAD
|
|
||||||
[ -e "$g/MERGE_HEAD" ] || [ -d "$g/rebase-merge" ] || \
|
|
||||||
[ -d "$g/rebase-apply" ] || [ -e "$g/CHERRY_PICK_HEAD" ] && return 0
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_out_of_scope() { # 0 = forbidden, 1 = in scope
|
|
||||||
case "$1" in
|
|
||||||
*..*) return 0 ;; # traversal — forbidden FIRST
|
|
||||||
.claude/deploy/*) return 1 ;; # allowed
|
|
||||||
*) return 0 ;; # everything else forbidden
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
_scope_violations() { local p; for p in "$@"; do _out_of_scope "$p" && printf '%s\n' "$p"; done; }
|
|
||||||
|
|
||||||
_changed_only() { # echo passed files that actually have changes
|
|
||||||
local p; for p in "$@"; do
|
|
||||||
[ -n "$(git status --porcelain -- "$p" 2>/dev/null)" ] && printf '%s\n' "$p"; done
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd="${1:-}"; shift || true
|
|
||||||
_in_git_repo || { echo "deploy-commit: not a git repo" >&2; exit 2; }
|
|
||||||
|
|
||||||
case "$cmd" in
|
|
||||||
pending)
|
|
||||||
[ "$#" -gt 0 ] || { echo "deploy-commit: pending needs file args" >&2; exit 2; }
|
|
||||||
[ -n "$(_changed_only "$@")" ] && exit 0 || exit 1 ;;
|
|
||||||
commit)
|
|
||||||
msg="${1:-}"; shift || true
|
|
||||||
[ -n "$msg" ] && [ "$#" -gt 0 ] || { echo "deploy-commit: commit needs <msg> <file>..." >&2; exit 2; }
|
|
||||||
viol=$(_scope_violations "$@")
|
|
||||||
if [ -n "$viol" ]; then
|
|
||||||
{ echo "deploy-commit: REFUSED — path(s) outside .claude/deploy/ allowlist:";
|
|
||||||
printf ' - %s\n' $viol;
|
|
||||||
echo "deploy-commit: NOTHING committed. Caller must pass only .claude/deploy/ files."; } >&2
|
|
||||||
exit 4
|
|
||||||
fi
|
|
||||||
_unsafe_state && { echo "deploy-commit: unsafe git state (detached/merge/rebase) — not committing" >&2; exit 3; }
|
|
||||||
mapfile -t changed < <(_changed_only "$@")
|
|
||||||
[ "${#changed[@]}" -gt 0 ] || exit 1
|
|
||||||
git commit -q -m "$msg" -- "${changed[@]}" || { echo "deploy-commit: git commit failed" >&2; exit 1; }
|
|
||||||
git rev-parse --short HEAD ;;
|
|
||||||
*) echo "usage: deploy-commit.sh pending <file>... | commit \"<msg>\" <file>..." >&2; exit 2 ;;
|
|
||||||
esac
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 4: Run the test, verify it PASSES**
|
|
||||||
|
|
||||||
Run: `bash lib/tests/deploy-commit.test.sh`
|
|
||||||
Expected: `PASS=12 FAIL=0` (exit 0).
|
|
||||||
|
|
||||||
- [ ] **Step 5: shellcheck**
|
|
||||||
|
|
||||||
Run: `shellcheck lib/deploy-commit.sh lib/tests/deploy-commit.test.sh`
|
|
||||||
Expected: clean (matches repo Health Stack norm).
|
|
||||||
|
|
||||||
- [ ] **Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add lib/deploy-commit.sh lib/tests/deploy-commit.test.sh
|
|
||||||
git commit -m "feat(deploy): deploy-commit.sh — allowlist surgical commit for .claude/deploy/"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 2: Artifacts + bridge formats (§10 materialized)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `templates/deploy/PROCEDURE.md`, `templates/deploy/INCIDENTS.md`
|
|
||||||
- Modify: `.gitignore`
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Produces: the on-disk shapes the skill reads/writes — `PROCEDURE.md` annotation grammar, `INCIDENTS.md` `DEP-NNN` template, `STATE.json` and `PENDING.json` schemas.
|
|
||||||
- Consumes: nothing.
|
|
||||||
|
|
||||||
- [ ] **Step 1: Write `templates/deploy/PROCEDURE.md`** (annotated starter — fixed steps verbatim, dynamic steps annotated)
|
|
||||||
|
|
||||||
```bash
|
|
||||||
#!/usr/bin/env bash
|
|
||||||
# === deploy runbook (reference) — NOT run directly. Instantiated to NEXT.sh per delta. ===
|
|
||||||
# Fixed steps run every deploy; `# @delta:` steps re-instantiate from the delta.
|
|
||||||
# @config push_deploy_tags=false
|
|
||||||
# NOTE grammar: glob=<pat>:each repeats the command per matching file (e.g. psql -f <each>);
|
|
||||||
# glob=<pat>:list runs once + lists matching files as VERIFY items; when=<pat,...> is conditional.
|
|
||||||
|
|
||||||
# 1) backup BEFORE any forward-only migration
|
|
||||||
ssh "$DEPLOY_HOST" 'pg_dump "$DB" > ~/backups/pre-deploy-$(date +%F-%H%M).sql' # VERIFY: dump size > 0
|
|
||||||
|
|
||||||
# @delta:migrations glob=supabase/migrations/*.sql:list
|
|
||||||
# 2) apply NEW migrations (one command; skill lists the delta migrations to VERIFY)
|
|
||||||
ssh "$DEPLOY_HOST" 'supabase migration up' # VERIFY: "Applied" for each
|
|
||||||
|
|
||||||
# @delta:rebuild when=docker-compose*.yml,Dockerfile,Dockerfile.*
|
|
||||||
# 3) rebuild + restart services (only if build inputs changed)
|
|
||||||
ssh "$DEPLOY_HOST" 'docker compose up -d --build' # VERIFY: docker compose ps healthy
|
|
||||||
|
|
||||||
# @delta:deps when=package.json,*lock*,requirements.txt,pyproject.toml
|
|
||||||
# 4) install deps (only if manifests changed)
|
|
||||||
ssh "$DEPLOY_HOST" 'cd app && npm ci' # VERIFY: exit 0
|
|
||||||
|
|
||||||
# 5) reload cache + smoke test (fixed)
|
|
||||||
ssh "$DEPLOY_HOST" 'systemctl reload app'
|
|
||||||
curl -fsS https://$DEPLOY_HOST/health # VERIFY: HTTP 200
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 2: Write `templates/deploy/INCIDENTS.md`** (ledger header)
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
# Deploy incidents (append-only) — DEP-NNN
|
|
||||||
|
|
||||||
<!-- One entry per incident. Next ID = grep '^## DEP-' | max+1. Mirrors blockers.md. -->
|
|
||||||
<!-- Resolution = the commit that adds this entry (atomic patch+incident). Recover: git log -S 'DEP-NNN' -- .claude/deploy/INCIDENTS.md -->
|
|
||||||
<!-- ## DEP-NNN — <step> failed
|
|
||||||
- date: YYYY-MM-DD
|
|
||||||
- step: <runbook step + label>
|
|
||||||
- error: `<verbatim error>`
|
|
||||||
- cause: <root cause>
|
|
||||||
- fix: <what changed in PROCEDURE.md> -->
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 3: Record the JSON schemas** (no parsing in shell — Claude reads them in skill steps)
|
|
||||||
|
|
||||||
`STATE.json` (committed oracle, overwritten on success):
|
|
||||||
```json
|
|
||||||
{ "deployed_sha": "<sha>", "deployed_at": "<ISO-8601>", "outcome": "ok",
|
|
||||||
"tag": "deploy/<YYYY-MM-DD>" }
|
|
||||||
```
|
|
||||||
`PENDING.json` (gitignored bridge, deleted on success): schema as in "Decisions resolved at plan time / §10".
|
|
||||||
|
|
||||||
- [ ] **Step 4: Update `.gitignore`**
|
|
||||||
|
|
||||||
```gitignore
|
|
||||||
# deploy: transient per-deploy state (the runbook/ledger/oracle ARE committed)
|
|
||||||
.claude/deploy/NEXT.sh
|
|
||||||
.claude/deploy/PENDING.json
|
|
||||||
```
|
|
||||||
|
|
||||||
- [ ] **Step 5: Verify templates are well-formed**
|
|
||||||
|
|
||||||
Run: `bash -n templates/deploy/PROCEDURE.md && grep -c '^# @delta:' templates/deploy/PROCEDURE.md`
|
|
||||||
Expected: no syntax error; `3` annotations.
|
|
||||||
|
|
||||||
- [ ] **Step 6: Commit**
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add templates/deploy/PROCEDURE.md templates/deploy/INCIDENTS.md .gitignore
|
|
||||||
git commit -m "feat(deploy): runbook/ledger templates + bridge schemas + gitignore transient state"
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 3: `skills/deploy/SKILL.md` — the two-moment skill (REQUIRES writing-skills)
|
|
||||||
|
|
||||||
> **At this task, invoke `superpowers:writing-skills`** to shape SKILL.md to house conventions AND to formalize the **cross-session cold-resume** form (deploy's defining novelty; `audit-delta` is the state-file precedent, `client-handover` only an in-context pause). The step behaviors below are the contract; writing-skills governs structure/frontmatter/spine.
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Create: `skills/deploy/SKILL.md`
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: `lib/deploy-commit.sh` (Task 1); artifact shapes (Task 2).
|
|
||||||
- Produces: the runtime behavior. STEP spine below.
|
|
||||||
|
|
||||||
**STEP spine (each = a SKILL.md section; [GATE] = mandatory stop):**
|
|
||||||
|
|
||||||
- [ ] **STEP 0 — PRE-FLIGHT + RESUME BRANCH.** Read `.claude/deploy/PENDING.json` FIRST (state file = only memory between runs).
|
|
||||||
- `PENDING.json` present → **RESUME**: jump to STEP 3 with its `{base, target, delta, step_reached}` (do not recompute).
|
|
||||||
- else `PROCEDURE.md` absent → **BOOTSTRAP** (Task 4).
|
|
||||||
- else → FRESH: continue STEP 1.
|
|
||||||
- [ ] **STEP 1 — DELTA.** `base = STATE.json.deployed_sha` (or, if `STATE.json` absent, first-deploy = full runbook). `git diff --name-only <base> HEAD` → delta file list. `target = git rev-parse HEAD`.
|
|
||||||
- [ ] **STEP 2 — INSTANTIATE + [GATE].** Expand `PROCEDURE.md`: emit fixed steps verbatim; expand `@delta:glob=…:each` steps by repeating the command per matching delta file, and `@delta:glob=…:list` steps once with matching files as `# VERIFY:` items; include `@delta:when=` steps only if the delta intersects. Read `INCIDENTS.md` and prepend matching `# PRE-WARN: DEP-NNN …` notes. Write `NEXT.sh`. **[GATE]** present `NEXT.sh` → `all / edit / skip-all`. On approve: write `PENDING.json` (`step_reached: awaiting-user`), then **hand back** (AskUserQuestion: "Run NEXT.sh step by step. Report back: Deployed OK / Failed at step X / Not yet").
|
|
||||||
- [ ] **STEP 3 — RESUME / REACT** (entry point on the user's report; may be a fresh session).
|
|
||||||
- "Deployed OK" → STEP 5.
|
|
||||||
- "Failed at step X: <err>" → STEP 4.
|
|
||||||
- "Not yet" → re-state pending, stop.
|
|
||||||
- [ ] **STEP 4 — LEARN + [GATE] + ATOMIC COMMIT.** Diagnose. Draft: (a) in-place `PROCEDURE.md` patch to step X; (b) `INCIDENTS.md` append `DEP-NNN` (error verbatim). **[GATE]** `all / pick / edit / skip-all` (significant edit). On approve: write both, then **one atomic** `bash lib/deploy-commit.sh commit "docs(deploy): patch <step> — recovered from <err>" .claude/deploy/PROCEDURE.md .claude/deploy/INCIDENTS.md`. The commit that adds `DEP-NNN` IS its resolution (derive via git later). Then bump `PENDING.json.runbook_rev` to the new `PROCEDURE.md` commit sha (keep `step_reached` at X). **Resume = REGENERATE `NEXT.sh` from `step_reached` against the PATCHED runbook** (steps X…end — X+1…end never ran), NOT replay a single step. The bumped `runbook_rev` is exactly the trigger: runbook changed ⇒ prior `NEXT.sh` is stale ⇒ regenerate. Re-present via STEP 2's hand-back.
|
|
||||||
- [ ] **STEP 5 — MARK (success).** Write `STATE.json` (`deployed_sha = PENDING.target_sha`, outcome ok, tag). `git tag -a deploy/<date> <target> -m "<summary>"`; **if `@config push_deploy_tags=true`** then `git push origin deploy/<date>` (best-effort, non-fatal). `bash lib/deploy-commit.sh commit "chore(deploy): mark <date> @ <short>" .claude/deploy/STATE.json`. **Delete `PENDING.json`** (+ `NEXT.sh`). Report.
|
|
||||||
|
|
||||||
- [ ] **Verification scenarios** (dry-run walkthroughs, no prod):
|
|
||||||
- First deploy (no `STATE.json`): full runbook fires; STATE laid; PENDING deleted.
|
|
||||||
- Delta deploy: only changed-bucket steps instantiate; `git diff` form is `<base> HEAD`.
|
|
||||||
- **Cold resume**: write a `PENDING.json` by hand, start `deploy` in a *fresh* context → STEP 0 detects it, resumes at STEP 3 from disk alone (no conversation memory).
|
|
||||||
- Failure→learn: report "failed at step X" → patch + DEP append committed atomically (one sha, both files).
|
|
||||||
- [ ] **Commit:** `git add skills/deploy/SKILL.md && git commit -m "feat(deploy): two-moment cross-session skill (resumes cold from PENDING.json)"`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 4: Bootstrap (project without a runbook)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `skills/deploy/SKILL.md` (STEP 0 BOOTSTRAP branch)
|
|
||||||
|
|
||||||
**Interfaces:**
|
|
||||||
- Consumes: `templates/deploy/*` (Task 2); STEP spine (Task 3).
|
|
||||||
|
|
||||||
- [ ] **Step 1 — BOOTSTRAP branch + [GATE].** When `PROCEDURE.md` absent, offer two paths (AskUserQuestion):
|
|
||||||
- **Paste** — user provides an existing runbook → adopt verbatim, then propose `@delta:` annotations for migration/build/deps steps.
|
|
||||||
- **Scaffold** — detect artifacts (`supabase/migrations/`, `docker-compose*.yml`/`Dockerfile`, `package.json`/lockfiles, `.env*`) + short interview (ssh host, backup cmd, health URL, rollback note) → fill `templates/deploy/PROCEDURE.md`.
|
|
||||||
- **[GATE]** present drafted `PROCEDURE.md` → `all / edit / skip-all`. On approve: write `PROCEDURE.md` + empty `INCIDENTS.md`; `bash lib/deploy-commit.sh commit "feat(deploy): bootstrap runbook" .claude/deploy/PROCEDURE.md .claude/deploy/INCIDENTS.md`. First deploy then proceeds (no STATE.json ⇒ full runbook).
|
|
||||||
- [ ] **Step 2 — Verify:** dry-run on a repo with `supabase/migrations/` + `docker-compose.yml` present → scaffold proposes migration + rebuild steps annotated; on a bare repo → interview-only path.
|
|
||||||
- [ ] **Commit:** `git add skills/deploy/SKILL.md && git commit -m "feat(deploy): bootstrap — paste-or-scaffold initial runbook"`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Gates identified
|
|
||||||
|
|
||||||
- **[GATE] STEP 2** — approve instantiated `NEXT.sh` before hand-back.
|
|
||||||
- **[GATE] STEP 4** — approve runbook patch + `DEP-NNN` incident before the atomic learning commit.
|
|
||||||
- **[GATE] STEP 0/Task 4** — approve scaffolded `PROCEDURE.md` before first write.
|
|
||||||
- **Hand-back (STEP 2→3)** — AskUserQuestion is the resume point; the user executes out-of-band.
|
|
||||||
- **Task gates** — each Task ends test-green + shellcheck-clean + committed before the next (deps: 1 → 2 → 3 → 4).
|
|
||||||
|
|
||||||
## Self-review
|
|
||||||
|
|
||||||
- **Spec coverage:** 4 artifacts + bridge (§3/§10) → Task 2; STATE-oracle + `<base> HEAD` delta (§4) → Task 1 constraints + STEP 1; runbook+INCIDENTS learning, atomic couple (§5) → STEP 4; `deploy-commit.sh` inverse allowlist (§6) → Task 1; bootstrap (§7) → Task 4; two-moment cold resume (§10) → STEP 0/2/3 + PENDING.json. All §8 items resolved above. ✓
|
|
||||||
- **Placeholder scan:** none — helper code, test code, schemas, annotation grammar all concrete.
|
|
||||||
- **Type consistency:** `STATE.json.deployed_sha` (STEP 1 base, STEP 5 write), `PENDING.json.{base_sha,target_sha,delta,step_reached}` (STEP 0 read, STEP 2 write, STEP 4 update), `deploy-commit.sh commit "<msg>" <file>...` (Tasks 1/3/4) — names align.
|
|
||||||
- **Open at execution (not assumed):** the `writing-skills` consultation in Task 3 may rename/restructure SKILL.md sections to match the formalized cold-resume convention, and finalizes the `@delta:` `:each`/`:list` keyword spelling (both semantics mandatory); STEP behaviors and the §6 helper contract above are fixed regardless.
|
|
||||||
|
|
||||||
## Execution Handoff
|
|
||||||
|
|
||||||
Build order is strict by dependency: **Task 1 (helper, foundation) → Task 2 (formats) → Task 3 (skill, writing-skills) → Task 4 (bootstrap)**.
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
# Deploy skill — design spec
|
|
||||||
|
|
||||||
> **Superseded by BDR-054** (`52f6678`): the shipped skill has NO `NEXT.sh` file and NO
|
|
||||||
> AskUserQuestion hand-back — see `skills/deploy/SKILL.md` for current behavior. This
|
|
||||||
> spec is kept as historical record; do not implement its NEXT.sh/hand-back sections.
|
|
||||||
|
|
||||||
- **Date:** 2026-06-27
|
|
||||||
- **Status:** Design approved (5 knobs settled). **No skill code written yet.** Next step = implementation plan.
|
|
||||||
- **Scope:** A new `deploy` skill = a per-project shell RUNBOOK that lives in `.claude/deploy/`, gets re-instantiated from the delta since the last deploy, and LEARNS from deploy errors in place.
|
|
||||||
|
|
||||||
## 1. Vision — deployment memory that learns
|
|
||||||
|
|
||||||
Three moments:
|
|
||||||
|
|
||||||
1. **BEFORE** — produce the *instantiated* runbook: reference runbook + delta since last deploy, parameterized steps rewritten with the real artifacts (e.g. the migration step lists the migrations actually added since last deploy, not the runbook's examples).
|
|
||||||
2. **DURING** — the **user executes out-of-band** (prod ssh — Claude must not run it) and reports `deployed and tested` OR `failed at step X, here is the error` → fix together until success.
|
|
||||||
3. **AFTER** — on confirmed success: (a) if errors were hit + fixed, update the reference runbook so the next deploy does not repeat them; (b) lay the marker "deployed up to here" for the next diff.
|
|
||||||
|
|
||||||
Structural ancestor in the corpus: `client-handover` (BEFORE baseline → DURING user-deploy gate via `AskUserQuestion` → AFTER validate + react). No existing skill owns a learning per-project runbook — clean gap, no `.claude/deploy/` precedent.
|
|
||||||
|
|
||||||
## 2. Locked decisions
|
|
||||||
|
|
||||||
| # | Knob | Decision |
|
|
||||||
|---|------|----------|
|
|
||||||
| 1 | Marker / oracle | **STATE file is the oracle** (deployed SHA), **annotated tag** added as a human bookmark only |
|
|
||||||
| 2 | Learning storage | **In-place runbook edits + append-only `INCIDENTS.md`** (distinct jobs, atomic coupling) |
|
|
||||||
| 3 | Parameterization | **`# @delta:` annotations** bind dynamic steps to path-patterns; un-annotated steps are fixed |
|
|
||||||
| 4 | Bootstrap | **Offer both** — user pastes an existing runbook OR skill scaffolds via artifact detection + interview |
|
|
||||||
| 5 | Execution model | **`NEXT.sh` is a step-by-step CHECKLIST** — runnable shell, but driven by hand with manual `# VERIFY:` gates; never `bash NEXT.sh` unattended |
|
|
||||||
|
|
||||||
**Why #5 is design-time, not impl:** the execution model is load-bearing for moments 2 and 3. Moment 2 is defined as "user reports *failed at step X*", and moment 3's LEARN loop must know *which* step failed to patch it. A single `bash NEXT.sh` blob collapses both into "exited non-zero somewhere" and can strand a prod deploy (migrations, restarts) in partial state with no step control. Checklist is *entailed* by the three-moment structure, not merely safer.
|
|
||||||
|
|
||||||
Treated as settled corollaries: user executes out-of-band; a **new** `lib/deploy-commit.sh` helper (existing helpers cannot commit the runbook — see §6, verified).
|
|
||||||
|
|
||||||
## 3. Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
.claude/deploy/
|
|
||||||
PROCEDURE.md reference runbook — fixed shell + `# @delta:` annotated steps (edited IN-PLACE)
|
|
||||||
INCIDENTS.md DEP-NNN incident ledger: date, step, error verbatim, root cause,
|
|
||||||
fix (APPEND-ONLY; resolution = introducing commit, derive via git)
|
|
||||||
STATE.json deployed SHA + timestamp + outcome — the diff oracle (overwritten each deploy)
|
|
||||||
NEXT.sh instantiated runbook — EPHEMERAL, not committed ; run STEP-BY-STEP
|
|
||||||
(checklist, manual # VERIFY: gates) — never `bash NEXT.sh` unattended
|
|
||||||
|
|
||||||
lib/deploy-commit.sh surgical commit, allowlist = .claude/deploy/ , rc3 unsafe-git guard, short-hash stdout
|
|
||||||
|
|
||||||
Skill STEP spine (PRE-FLIGHT -> PROPOSE+GATE -> WRITE+COMMIT, house style):
|
|
||||||
0 PRE-FLIGHT runbook present? absent -> bootstrap (paste | scaffold+interview)
|
|
||||||
1 DELTA STATE absent -> first deploy = full runbook ; else diff <STATE_SHA> HEAD
|
|
||||||
2 INSTANTIATE expand @delta steps + read INCIDENTS pre-warns -> NEXT.sh -> GATE
|
|
||||||
3 (user executes out-of-band; reports "done" | "failed at step X: <err>")
|
|
||||||
4 LEARN on failure: patch PROCEDURE step + append DEP-NNN -> GATE -> deploy-commit (ATOMIC)
|
|
||||||
5 MARK on success: write STATE@sha ; annotate + push tag ; optional doc
|
|
||||||
```
|
|
||||||
|
|
||||||
## 4. Delta mechanism — verified (git 2.53.0)
|
|
||||||
|
|
||||||
All three facts re-run live before writing this spec; observed output recorded, not assumed.
|
|
||||||
|
|
||||||
**First-deploy detection = STATE-absent, deterministic. `describe` is off the detection path.**
|
|
||||||
```
|
|
||||||
[ -f .claude/deploy/STATE.json ] => exit 1 (absent = first deploy) <- THE detector
|
|
||||||
git describe --tags --match 'deploy/*' => fatal: No names found ; exit 128 <- only the reason NOT to use describe
|
|
||||||
[ -f .claude/deploy/STATE.json ] => exit 0 (present = delta path)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Delta = `git diff --name-only <STATE_SHA> HEAD`** (two explicit endpoints; no dots, so it cannot be misread as three-dot).
|
|
||||||
```
|
|
||||||
LINEAR git diff --name-only <sha> HEAD => 0033_new.sql, svc.yml (== two-dot == three-dot; merge-base == STATE)
|
|
||||||
DIVERGED two-dot sideA sideB => fileA.txt, fileB.txt (both endpoints = true tree delta)
|
|
||||||
DIVERGED three-dot sideA...sideB => fileB.txt (merge-base — UNDERCOUNTS)
|
|
||||||
```
|
|
||||||
Two-dot/explicit-endpoints is the literal tree difference between the deployed tree and HEAD = what deploy needs. It is also rebase-robust: an orphaned marker still yields the correct tree diff, whereas `git rev-list A..B` (ancestry) reports phantom deltas after history rewrite (LRN-054's trap; verified in an earlier run). **Never use `rev-list` ancestry for the artifact list.**
|
|
||||||
|
|
||||||
**delta -> steps:** `# @delta:<kind>` annotations bind a dynamic step to the path-pattern that feeds it; the diff buckets straight into steps:
|
|
||||||
```
|
|
||||||
# @delta:migrations glob=supabase/migrations/*.sql
|
|
||||||
# @delta:rebuild when=docker-compose*.yml,Dockerfile
|
|
||||||
# @delta:deps when=package.json,*lock*
|
|
||||||
```
|
|
||||||
|
|
||||||
## 5. Learning model — runbook + INCIDENTS, non-redundant
|
|
||||||
|
|
||||||
| Artifact | Job | Lifecycle |
|
|
||||||
|---|---|---|
|
|
||||||
| `PROCEDURE.md` | The corrected procedure you run. A fix is baked into the step so the next run cannot repeat it. | in-place |
|
|
||||||
| `INCIDENTS.md` | The incident ledger; **read at BEFORE-time to pre-warn** ("0033 hit a lock timeout last deploy; runbook already carries `--timeout`, watch for it"). | append-only |
|
|
||||||
|
|
||||||
The pre-warn read is the function `git log` serves badly — that is why the ledger is not duplication. This mirrors the memory system's own split (append-only `journal.md`/`blockers.md` alongside in-place TODO/code).
|
|
||||||
|
|
||||||
**Coupling invariant:** one incident → **one in-place `PROCEDURE.md` patch + one `INCIDENTS.md` append, committed atomically in a single `deploy-commit.sh` call.** Never one without the other (mirrors BDR-034/036 "couple the commit to the integration step"). Significant patch (changes a prod path) → surface + approve before writing.
|
|
||||||
|
|
||||||
## 6. `lib/deploy-commit.sh` — new helper, inverse `.claude/` rule (verified)
|
|
||||||
|
|
||||||
Neither existing helper can commit the runbook — confirmed live:
|
|
||||||
```
|
|
||||||
REAL doc-commit.sh .claude/deploy/PROCEDURE.md => rc 4 "REFUSED — out-of-scope ... BDR-022 ... NOTHING committed"
|
|
||||||
REAL memory-commit.sh pending (deploy changed) => rc 1 (ignores it; allowlist = .claude/memory|tasks only)
|
|
||||||
```
|
|
||||||
`doc-commit.sh` is built to keep `.claude/**` *out* of public-doc commits; `.claude/deploy/` is under `.claude/`, so reuse is not just blocked, it is semantically wrong. `deploy-commit.sh` needs the **inverse** rule: a TARGET allowlist for `.claude/deploy/*`, modeled on `memory-commit.sh` (rc 3 unsafe-git guard, short-hash on stdout, `chore(deploy):`/`docs(deploy):` messages).
|
|
||||||
|
|
||||||
Allowlist guard — traversal reject ordered FIRST. Prototype matrix verified live:
|
|
||||||
```sh
|
|
||||||
_in_deploy_scope() {
|
|
||||||
case "$1" in
|
|
||||||
*..*) return 1 ;; # reject path traversal FIRST
|
|
||||||
.claude/deploy/*) return 0 ;; # ALLOW the deploy family only
|
|
||||||
*) return 1 ;; # reject everything else
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
```
|
|
||||||
```
|
|
||||||
ALLOW .claude/deploy/{PROCEDURE.md,INCIDENTS.md,STATE}
|
|
||||||
REJECT .claude/memory/* .claude/tasks/* .claude/secret CLAUDE.md src/*
|
|
||||||
REJECT .claude/deploy (bare dir, no slash)
|
|
||||||
REJECT .claude/deploy-other/x (trailing-slash requirement closes prefix confusion)
|
|
||||||
REJECT .claude/deploy/../memory/secret (traversal closed by *..* matched first)
|
|
||||||
```
|
|
||||||
|
|
||||||
## 7. Bootstrap
|
|
||||||
|
|
||||||
`STEP 0 PRE-FLIGHT`: `PROCEDURE.md` present? Absent → bootstrap, two offered paths:
|
|
||||||
1. **Paste** — user supplies an existing runbook (the game example); skill adopts + annotates it.
|
|
||||||
2. **Scaffold** — skill detects deploy artifacts (migrations dir, compose/Dockerfile, package scripts, `.env`) + a short interview (ssh target, backup cmd, rollback note) → writes an annotated `PROCEDURE.md`.
|
|
||||||
|
|
||||||
First deploy has no marker → STATE-absent ⇒ full runbook fires; then lay STATE at the deployed SHA. The first deploy *is* the creation of the runbook + the first marker.
|
|
||||||
|
|
||||||
## 8. Open items (for the implementation plan)
|
|
||||||
|
|
||||||
> `NEXT.sh` execution model resolved → decision #5 (checklist), promoted to design-time.
|
|
||||||
|
|
||||||
- Tag push: tags don't push by default → AFTER step should `git push --tag deploy/<date>` or remind.
|
|
||||||
- `INCIDENTS.md` ID/format detail (mirror `blockers.md` `DEP-NNN`); confirm name vs `ERRORS-LEARNED.md`.
|
|
||||||
- `@delta:` annotation grammar (glob= vs when=) — finalize the small DSL.
|
|
||||||
- Frontmatter `allowed-tools` set; STEP gate wording reuse from `capitalize`/`client-handover`.
|
|
||||||
|
|
||||||
## 9. Build sequencing & a structural flag
|
|
||||||
|
|
||||||
**Two distinct disciplines, in order — do not conflate:**
|
|
||||||
1. `writing-plans` — global task ordering (helper → skill → bootstrap), dependencies, gates. The build plan.
|
|
||||||
2. → execution →
|
|
||||||
3. At the *skill* task ONLY: `writing-skills` — the discipline for the SKILL.md itself (structure, frontmatter, spine, config conventions). Used WHEN we reach the skill task, **not before** (it does not fire at plan time).
|
|
||||||
|
|
||||||
**Structural flag for `writing-skills` to resolve — do NOT assume the linear-spine convention suffices:**
|
|
||||||
deploy's spine is unusual — **two parts split by out-of-band execution**: STEP 0–2 before → *user deploys by hand* → STEP 4–5 after, on the `done`/`failed` report. A skill that **hands back control mid-run and resumes**.
|
|
||||||
|
|
||||||
Preliminary recon (confirm at the skill task — NOT verified now):
|
|
||||||
- The 6 completion flux (close, ship-feature, feat, bugfix, hotfix, commit-change) appear linear one-shot — synchronous gates at most, no out-of-band hand-back.
|
|
||||||
- The relevant precedent is OUTSIDE those 6: `client-handover` already hands back — a synchronous "Deploy done?" `AskUserQuestion` pause (STEP 5) — but it holds state in *conversation context*, not on disk.
|
|
||||||
- deploy's genuinely-new bit *may* be **disk-bridged resume** (`NEXT.sh` + `STATE` on disk as the bridge) — but **whether `NEXT.sh` alone suffices to resume cross-session is an OPEN design question, not a settled answer** (see §10). An earlier draft of this spec framed it as resolved; it is not. `writing-skills` must establish the convention (how to mark "I wait for your return here", detect + resume a pending deploy, hold state across the gap) — confirm there, do not assume the linear mould suffices.
|
|
||||||
|
|
||||||
## 10. Open design question (DESIGN-TIME, unresolved) — state across the two moments
|
|
||||||
|
|
||||||
deploy is a **two-moment skill**: moments 0–2 (BEFORE) → user deploys out-of-band → moment 3 (AFTER) on the `done`/`failed` report. **The report may arrive in a different session.** So the design must answer how state crosses the gap and what moment 3 must know to resume correctly.
|
|
||||||
|
|
||||||
> **`skill deux-temps, état entre temps = [à concevoir : NEXT.sh seul suffit-il pour reprendre cross-session ?]`**
|
|
||||||
|
|
||||||
Sub-questions (to settle when we resume — NOT now, NOT assumed):
|
|
||||||
- **What must the bridge record?** Moment 3 must (a) lay the correct marker = `STATE ← target sha`, and (b) capitalize the correct incident (which step, which delta). HEAD may have moved since NEXT.sh was generated → "current HEAD" is unsafe. The bridge must persist at least **{base STATE sha, target sha, delta manifest}** — inside NEXT.sh (header block) or a sidecar (`.claude/deploy/PENDING`)? Undecided.
|
|
||||||
- **Resume detection (re-entrancy):** STEP 0 PRE-FLIGHT must detect "a deploy is pending, awaiting your report" — likely *pending-bridge present + STATE not advanced to target* — and branch RESUME (ask done/failed) vs FRESH. Is moment 3 a new `deploy` call that re-detects from disk, or a `deploy --report`? Undecided.
|
|
||||||
- **Ephemeral vs persistent tension — LINKED to sub-question 1 (not independent).** §3 calls NEXT.sh "EPHEMERAL, not committed", yet a cross-session bridge MUST survive on disk. So: **if the bridge must persist, NEXT.sh-as-bridge is impossible while NEXT.sh stays ephemeral.** Likely *binary* resolution at plan time — either (a) NEXT.sh becomes persistent (contradicts §3), or (b) the bridge is a **separate** "deploy-in-progress" artifact `{base/target/delta}` distinct from NEXT.sh. Settle with `writing-skills`. (Uncommitted local state is fine; note the single-machine assumption — an uncommitted bridge won't follow a clone.)
|
|
||||||
- **Form-novelty — deploy's DEFINING characteristic: cross-session COLD resume.** `client-handover` is a *near* precedent, not exact: it hands back **in-context** (same conversation, state held in memory). deploy must resume with the **context lost** — so the **disk alone must carry everything to resume cold**. No existing skill resumes without context; that is what sets deploy apart, and it makes sub-question 1 **load-bearing** (disk must suffice for a cold restart). deploy likely introduces a NEW skill form → `writing-skills` establishes the convention. Confirm there.
|
|
||||||
|
|
||||||
**Next step:** `writing-plans` to turn this spec into an implementation plan (helper first, then skill); at the skill task, `writing-skills` to shape it to convention and **resolve the §10 two-moment state question** — which is design-time, deferred only because we are stopped here, not because it is impl detail.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,143 +0,0 @@
|
|||||||
# 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 <X> — 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.
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# config-protection.sh
|
|
||||||
#
|
|
||||||
# PreToolUse hook (Edit|Write|MultiEdit). Blocks edits to this config's
|
|
||||||
# quality-gate files — the guardrails an agent must not silently weaken to make
|
|
||||||
# an error "pass" (permission/hook registry, gitflow enforcement, the git
|
|
||||||
# pre-commit guard, the hooks themselves, the test suite, the health diagnostic,
|
|
||||||
# lint config). Exit 2 blocks the tool call and feeds the message back to the
|
|
||||||
# model (Claude Code PreToolUse contract).
|
|
||||||
#
|
|
||||||
# It fires only on the model's Edit/Write tool calls — never on shell-level file
|
|
||||||
# ops (the cp/ln in install.sh, link.sh), so bootstrap/deploy is unaffected.
|
|
||||||
#
|
|
||||||
# One-shot escape hatch: create .claude/.config-edit-ok (CWD-relative) with a
|
|
||||||
# NON-EMPTY reason inside; the hook logs the reason, consumes (rm) the sentinel,
|
|
||||||
# and allows that single edit. It never persists — a lingering sentinel would be
|
|
||||||
# a footgun. Discipline, per CLAUDE.global.md "Root causes only. No temp fixes.": fix
|
|
||||||
# the code, don't loosen the gate. Fails OPEN (exit 0) on parse failure so it can
|
|
||||||
# never wedge editing.
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
log="${HOME}/.claude/logs/config-protection.log"
|
|
||||||
sentinel="${PWD}/.claude/.config-edit-ok"
|
|
||||||
|
|
||||||
input="$(cat)"
|
|
||||||
path="$(printf '%s' "$input" \
|
|
||||||
| python3 -c 'import sys, json; print(json.load(sys.stdin).get("tool_input", {}).get("file_path", ""))' \
|
|
||||||
2>/dev/null || true)"
|
|
||||||
[ -z "$path" ] && exit 0
|
|
||||||
|
|
||||||
# Guardrail files, matched by path suffix (covers both the repo source and the
|
|
||||||
# deployed ~/.claude copy). Precise: lib/gitflow.sh only, not gitflow-migrate.sh.
|
|
||||||
case "$path" in
|
|
||||||
*/.claude/settings.json|*/.claude/settings.local.json|*/claude/settings.json) ;;
|
|
||||||
*/lib/gitflow.sh|*/.githooks/*|*/doctor.sh) ;;
|
|
||||||
*/hooks/*.sh|*/lib/tests/*) ;;
|
|
||||||
*/.shellcheckrc|*/.markdownlint.json|*/.editorconfig) ;;
|
|
||||||
*) exit 0 ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# One-shot sentinel bypass: non-empty reason required; consumed on sight.
|
|
||||||
if [ -f "$sentinel" ]; then
|
|
||||||
reason="$(head -c 500 "$sentinel" 2>/dev/null | tr '\n\r\t' ' ' || true)"
|
|
||||||
rm -f "$sentinel"
|
|
||||||
if printf '%s' "$reason" | grep -q '[^[:space:]]'; then
|
|
||||||
mkdir -p "$(dirname "$log")"
|
|
||||||
printf '%s\tBYPASS\t%s\treason=%s\n' "$(date -Iseconds)" "$path" "$reason" >> "$log"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
printf '%s\n' "[config-protection] .claude/.config-edit-ok had an EMPTY reason -> refused (sentinel consumed). Recreate it with a non-empty reason." >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
cat >&2 <<EOF
|
|
||||||
[config-protection] BLOCKED edit to a quality-gate file:
|
|
||||||
$path
|
|
||||||
This is a guardrail (permission/hook registry, gitflow enforcement, git
|
|
||||||
pre-commit guard, a hook, the test suite, health diagnostic, or lint config).
|
|
||||||
Don't weaken the gate to make an error pass — fix the root cause instead
|
|
||||||
(global CLAUDE.md: "Root causes only. No temp fixes."). To make one intended edit,
|
|
||||||
create .claude/.config-edit-ok with a non-empty reason; it is logged and
|
|
||||||
consumed (one-shot).
|
|
||||||
EOF
|
|
||||||
exit 2
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ctx7-reminder.sh
|
||||||
|
#
|
||||||
|
# UserPromptSubmit hook. When the current project uses fast-moving libs
|
||||||
|
# (lib/fast-libs.sh) it injects ONE reminder per session to consult ctx7
|
||||||
|
# (find-docs skill) before coding against their APIs, pointing at the
|
||||||
|
# .ctx7-cache/ state. Closes the ad-hoc-coding gap: find-docs' description
|
||||||
|
# fires on doc *questions* and ship-feature/init-project pre-fetch, but
|
||||||
|
# nothing covered a plain "add a useEffect here" prompt (BDR-078; second
|
||||||
|
# deliberate ctx7 surface, scoped refinement of BDR-053 single-surface).
|
||||||
|
#
|
||||||
|
# Soft nudge: always exits 0, never blocks. Stable-tech projects (no
|
||||||
|
# manifest, or no fast-lib match) stay silent.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
input="$(cat)"
|
||||||
|
|
||||||
|
field() { # $1=json key — extracted from hook stdin, empty on failure
|
||||||
|
printf '%s' "$input" | python3 -c \
|
||||||
|
"import sys,json; print(json.load(sys.stdin).get('$1',''))" \
|
||||||
|
2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt="$(field prompt)"
|
||||||
|
case "$prompt" in
|
||||||
|
'<task-notification>'*) exit 0 ;; # harness turn, not a user request
|
||||||
|
esac
|
||||||
|
|
||||||
|
cwd="$(field cwd)"
|
||||||
|
[ -n "$cwd" ] || cwd="$PWD"
|
||||||
|
|
||||||
|
# Cheap bail-out before any lib work: no manifest → no fast-libs.
|
||||||
|
[ -f "$cwd/package.json" ] || [ -f "$cwd/requirements.txt" ] \
|
||||||
|
|| [ -f "$cwd/pyproject.toml" ] || exit 0
|
||||||
|
|
||||||
|
# One fire per session: the doctrine holds for the whole session,
|
||||||
|
# repeating it on every prompt would be token spam.
|
||||||
|
session_id="$(field session_id)"
|
||||||
|
sentinel="${TMPDIR:-/tmp}/.ctx7-reminder-${session_id:-nosession}"
|
||||||
|
[ -e "$sentinel" ] && exit 0
|
||||||
|
|
||||||
|
# Resolve the lib next to this hook (repo layout), fall back to the
|
||||||
|
# installed copy — both paths exist through the link.sh symlinks.
|
||||||
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
libsh="${script_dir}/../lib/fast-libs.sh"
|
||||||
|
[ -f "$libsh" ] || libsh="${HOME}/.claude/lib/fast-libs.sh"
|
||||||
|
[ -f "$libsh" ] || exit 0
|
||||||
|
|
||||||
|
libs="$(bash "$libsh" detect "$cwd" 2>/dev/null || true)"
|
||||||
|
[ -n "$libs" ] || exit 0
|
||||||
|
|
||||||
|
status="$(bash "$libsh" cache-status "$cwd" 2>/dev/null || true)"
|
||||||
|
: > "$sentinel" || true
|
||||||
|
list="$(printf '%s' "$libs" | tr '\n' ' ' | sed 's/ *$//')"
|
||||||
|
|
||||||
|
if [ "$status" = "fresh" ]; then
|
||||||
|
printf '📚 Fast-moving libs in this project (%s) — fresh .ctx7-cache/ present: read the matching cache file before relying on their APIs.\n' "$list"
|
||||||
|
else
|
||||||
|
printf '📚 Fast-moving libs in this project (%s) — .ctx7-cache/ %s: consult ctx7 (find-docs skill) before writing code against their APIs. Stable techs need nothing.\n' "$list" "${status:-missing}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -644,6 +644,46 @@ if command -v ctx7 &>/dev/null; then
|
|||||||
# (~490 tok/session, job1 F10). Purge it unconditionally so re-runs and
|
# (~490 tok/session, job1 F10). Purge it unconditionally so re-runs and
|
||||||
# manual `ctx7 setup` invocations stay rule-free.
|
# manual `ctx7 setup` invocations stay rule-free.
|
||||||
rm -f "$HOME/.claude/rules/context7.md"
|
rm -f "$HOME/.claude/rules/context7.md"
|
||||||
|
# BDR-078: re-apply the coverage extension to the generated skill — the
|
||||||
|
# before-writing-code trigger (description) + the cache-first rule (body).
|
||||||
|
# The dist is machine-owned (gitignored, regenerated on fresh clones), so
|
||||||
|
# the durable copy of this patch lives HERE. Idempotent: grep-guarded.
|
||||||
|
_fd="$HOME/.claude/skills/find-docs/SKILL.md"
|
||||||
|
if [ -f "$_fd" ] && ! grep -q 'fast-libs.sh detect' "$_fd"; then
|
||||||
|
if python3 - "$_fd" <<'PY'
|
||||||
|
import sys
|
||||||
|
p = sys.argv[1]
|
||||||
|
s = open(p, encoding="utf-8").read()
|
||||||
|
DESC = """
|
||||||
|
Also use BEFORE writing or modifying code that uses a fast-moving library
|
||||||
|
(anything `bash ~/.claude/lib/fast-libs.sh detect .` reports — React,
|
||||||
|
Next.js, Prisma, Tailwind, Astro, Svelte…), even when the user asked for
|
||||||
|
code rather than documentation — unless a fresh `.ctx7-cache/` file already
|
||||||
|
covers the API involved. Stable technologies (C, C++98, POSIX shell, SQL…)
|
||||||
|
need no lookup."""
|
||||||
|
BODY = """
|
||||||
|
## Cache first
|
||||||
|
|
||||||
|
Before any fetch, check the project's `.ctx7-cache/`
|
||||||
|
(`bash ~/.claude/lib/fast-libs.sh cache-status .`): a fresh (<7 days)
|
||||||
|
`<lib>*.md` may already answer — read it instead of calling ctx7. When a
|
||||||
|
`docs` call supports code you are about to write, save the output for the
|
||||||
|
next consumer:
|
||||||
|
`npx ctx7@latest docs <id> "<query>" | tee .ctx7-cache/<lib>-<topic>.md`.
|
||||||
|
"""
|
||||||
|
i = s.index("\n---", 3) # closing frontmatter fence
|
||||||
|
s = s[:i] + "\n" + DESC + s[i:]
|
||||||
|
m = "using the Context7 CLI.\n" # intro line under the H1
|
||||||
|
j = s.index(m) + len(m) if m in s else len(s)
|
||||||
|
s = s[:j] + BODY + s[j:]
|
||||||
|
open(p, "w", encoding="utf-8").write(s)
|
||||||
|
PY
|
||||||
|
then
|
||||||
|
ok "find-docs skill extended (BDR-078 fast-libs trigger + cache-first)"
|
||||||
|
else
|
||||||
|
warn "find-docs BDR-078 patch failed — re-run 'make plugin' or patch by hand"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
info "Standalone usage: ctx7 docs /vercel/next.js \"middleware\""
|
info "Standalone usage: ctx7 docs /vercel/next.js \"middleware\""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
# Challenge the plan — shared orchestrator include
|
||||||
|
|
||||||
|
Runs in the ORCHESTRATOR MAIN LOOP after a plan / reflection is elaborated and
|
||||||
|
BEFORE it is executed. Turns a fresh plan into a hardened one by attacking it
|
||||||
|
from three independent angles, then RE-THINKING every aspect a challenger lands.
|
||||||
|
Loop + synthesis decisions live here, in the main loop (BDR-066: reflection runs
|
||||||
|
on the big model; `verify-secure-loop.md`: fresh blind gates, decisions in the
|
||||||
|
loop). It never merges, executes, or edits code — it hardens the plan and hands
|
||||||
|
it to the orchestrator's existing human gate.
|
||||||
|
|
||||||
|
The challenge is ADVISORY into that gate — no new hard block — but a BLOCKER is
|
||||||
|
never silently carried past: it is either closed by a NAMED plan change or
|
||||||
|
explicitly deferred for the human.
|
||||||
|
|
||||||
|
## Inputs the caller must have ready
|
||||||
|
|
||||||
|
- `PLAN`: path to the plan ON DISK. If your plan is still inline (a printed
|
||||||
|
checklist / diagnosis / fix plan), FIRST persist it to
|
||||||
|
`.claude/tasks/plans/<date>-<slug>-<HHMM>.md` — the challengers read from disk
|
||||||
|
and judge blind, exactly like the verifier reads the contract.
|
||||||
|
- `KIND`: `build-plan` | `proposals` | `fix-bundle` — tunes the lens framing
|
||||||
|
below; the mechanism is identical.
|
||||||
|
- `SCOPE`: the files/dirs the plan touches (grounds the critique).
|
||||||
|
- `CONSTRAINTS` (optional): the decided trade-offs / rejected alternatives from
|
||||||
|
the design step, so a lens does not re-litigate a settled choice.
|
||||||
|
|
||||||
|
Nominal path is cheap for a small, clean plan: three parallel challengers return
|
||||||
|
SOLID, synthesis is a no-op. It only costs more when a lens lands a real finding
|
||||||
|
— which is the point.
|
||||||
|
|
||||||
|
## DISPATCH — three fresh challengers, in parallel, blind
|
||||||
|
|
||||||
|
Dispatch THREE fresh `plan-challenger` subagents IN PARALLEL, one per LENS, each
|
||||||
|
blind to the others and to this conversation:
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(subagent_type="plan-challenger", description="challenge:<lens>", prompt="""
|
||||||
|
PLAN: <the PLAN path>
|
||||||
|
LENS: <correctness | robustness | simplicity> # one per agent — all three
|
||||||
|
SCOPE: <SCOPE>
|
||||||
|
CONSTRAINTS: <CONSTRAINTS, if any>
|
||||||
|
""")
|
||||||
|
```
|
||||||
|
|
||||||
|
**MODEL (BDR-076, supersedes the BDR-066 inherit):** plan critique is AUDIT
|
||||||
|
JUDGMENT — the challengers are `model: opus`-pinned in their frontmatter: a big
|
||||||
|
tier, session-independent, off the session model. The session model (Fable)
|
||||||
|
keeps only this loop — synthesis, RE-THINK, gate. Never sonnet: that would
|
||||||
|
silently downgrade the judgment. (The executor gates stay sonnet.)
|
||||||
|
|
||||||
|
**Lens framing by `KIND`** (the agent's three lenses, read against the artifact):
|
||||||
|
- `build-plan` — will it WORK / will it BREAK / is it needlessly COMPLEX.
|
||||||
|
- `proposals` — are these the RIGHT items & priorities / what did the audit MISS
|
||||||
|
or under-rate as risk / is the backlog over- or under-scoped.
|
||||||
|
- `fix-bundle` — will each fix ACHIEVE its goal / could it BREAK or regress the
|
||||||
|
page / is there a simpler fix, or an unnecessary one.
|
||||||
|
|
||||||
|
## FAIL-SAFE — never fail open
|
||||||
|
|
||||||
|
A challenger that returns a malformed/empty verdict, a missing `PROOF`, or dies →
|
||||||
|
retry ONCE with a fresh challenger; a 2nd failure on that lens → STOP and escalate
|
||||||
|
to the human, NAMING the lens. Never carry "plan challenged" into the gate on a
|
||||||
|
silently dropped lens (`verify-secure-loop.md`: "a mute verifier is NEVER a PASS").
|
||||||
|
|
||||||
|
## SYNTHESIZE + RE-THINK (main loop, big model)
|
||||||
|
|
||||||
|
Parse each `CHALLENGE — LENS: … — VERDICT:` line and merge the FINDINGS:
|
||||||
|
|
||||||
|
- **Severity-driven, not consensus.** Any `[BLOCKER]` from ANY single lens is
|
||||||
|
must-address — the lenses are orthogonal, so a lone security/rollback finding
|
||||||
|
is real, never outvoted by lens-count. Cross-lens agreement only RANKS the MINORs.
|
||||||
|
- **RE-THINK the aspect the challenge pointed at.** For each BLOCKER (and each
|
||||||
|
MAJOR you accept): revise the plan on THAT aspect — a NAMED, diffable change to
|
||||||
|
the plan, never a self-authored "addressed" line. A BLOCKER you consciously keep
|
||||||
|
is tagged `[deferred <date>]` for the human to accept at the gate.
|
||||||
|
- **Re-challenge once if the plan materially changed** — a fix can open a new
|
||||||
|
flaw. Re-persist the revised `PLAN`, dispatch ONE fresh confirmation challenger,
|
||||||
|
max 1 extra pass, then the gate.
|
||||||
|
|
||||||
|
## OUTPUT — into the existing human gate
|
||||||
|
|
||||||
|
Feed the orchestrator's gate:
|
||||||
|
- the REVISED plan, and
|
||||||
|
- a CHALLENGE SUMMARY: each BLOCKER raised → the named change that closed it;
|
||||||
|
anything `[deferred]`; and any lens that failed to return.
|
||||||
|
|
||||||
|
The human remains the decider.
|
||||||
+13
-8
@@ -17,23 +17,28 @@ and any SIGNIFICANT-gated patch), with the code already committed.
|
|||||||
- Orchestrators (ship-feature / init-project): run it BEFORE the FINISH step — otherwise
|
- Orchestrators (ship-feature / init-project): run it BEFORE the FINISH step — otherwise
|
||||||
the doc commit strands outside the merge/PR (the exact bug this fixes). See ORDERING.
|
the doc commit strands outside the merge/PR (the exact bug this fixes). See ORDERING.
|
||||||
|
|
||||||
doc-syncer runs IN-THREAD (the orchestrator loads it), so the list of files it patched is
|
doc-syncer runs DISPATCHED (BDR-077: `MODE: audit` on opus → dispatcher gate
|
||||||
already in hand — surfaced as `PATCHED_FILES:` in doc-syncer's OUTPUT, ONE PATH PER LINE.
|
→ `MODE: patch` on sonnet); its patch-mode report hands the orchestrator BOTH
|
||||||
Pass each line as a SEPARATE argument (see DO step 3).
|
machine blocks: `PATCHED_FILES:` (ONE PATH PER LINE — pass each line as a
|
||||||
|
SEPARATE argument, see DO step 3) and `CHANGE SUMMARY` (one line per patched
|
||||||
|
file — the patch context that used to be in-thread now crosses the dispatch
|
||||||
|
boundary through this block, LRN-126).
|
||||||
|
|
||||||
## DO
|
## DO
|
||||||
|
|
||||||
1. Collect `PATCHED_FILES` — the public-doc paths doc-syncer wrote this run (its OUTPUT
|
1. Collect `PATCHED_FILES` — the public-doc paths doc-syncer wrote this run (its OUTPUT
|
||||||
block, ONE PATH PER LINE). Empty → nothing to commit; the helper no-ops.
|
block, ONE PATH PER LINE). Empty → nothing to commit; the helper no-ops.
|
||||||
|
|
||||||
2. Compose — from the patch context the AGENT holds (doc-syncer ran in-thread, so the
|
2. Compose — from doc-syncer's `CHANGE SUMMARY` block (the patcher held the
|
||||||
agent knows exactly what changed) — BOTH artifacts:
|
patch context and reported it; a dispatched patcher with NO summary block
|
||||||
|
in its report = incomplete report, re-dispatch rather than invent) —
|
||||||
|
BOTH artifacts:
|
||||||
- the COMMIT MESSAGE, repo style `docs: <summary> — <flow>`
|
- the COMMIT MESSAGE, repo style `docs: <summary> — <flow>`
|
||||||
(`docs: README features + USAGE flags — ship-feature dark-mode`);
|
(`docs: README features + USAGE flags — ship-feature dark-mode`);
|
||||||
- the CHANGE SUMMARY for the rc 0 surface (e.g. "README features section + USAGE
|
- the CHANGE SUMMARY for the rc 0 surface (e.g. "README features section + USAGE
|
||||||
--export flag").
|
--export flag") — derived from the block, never a bare file count.
|
||||||
Both are the AGENT's to write — the helper produces NEITHER (its only stdout is the
|
Both are the ORCHESTRATOR's to write — the helper produces NEITHER (its only stdout
|
||||||
hash). This is the load-bearing point of the visible surface: see the rc 0 row.
|
is the hash). This is the load-bearing point of the visible surface: see the rc 0 row.
|
||||||
|
|
||||||
3. Commit surgically via the helper, passing EXACTLY the patched files — each path as a
|
3. Commit surgically via the helper, passing EXACTLY the patched files — each path as a
|
||||||
SEPARATE argument (split `PATCHED_FILES` on NEWLINES only), capturing the hash:
|
SEPARATE argument (split `PATCHED_FILES` on NEWLINES only), capturing the hash:
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# fast-libs.sh — single source of truth for "fast-moving library" detection.
|
||||||
|
#
|
||||||
|
# Fast-moving = API churns faster than model training data (React, Next.js,
|
||||||
|
# Prisma…) → consult ctx7 (find-docs) before coding against it. Stable techs
|
||||||
|
# (C, C++98, POSIX sh, SQL…) never match: no ctx7 needed (BDR-078).
|
||||||
|
#
|
||||||
|
# Consumers: hooks/ctx7-reminder.sh, /ship-feature STEP 0c, /init-project
|
||||||
|
# STEP 5c, /onboard STEP 3.5, feater/bugfixer executor briefs.
|
||||||
|
#
|
||||||
|
# Verbs:
|
||||||
|
# fast-libs.sh detect [dir] detected libs, one/line; exit 1 if none
|
||||||
|
# fast-libs.sh cache-status [dir] fresh|stale|missing; exit 0 only if fresh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Exact npm dependency keys (unscoped). Anchored full-key match — "react"
|
||||||
|
# must not drag react-icons along.
|
||||||
|
NPM_EXACT='next|react|react-dom|react-native|expo|prisma|supabase'
|
||||||
|
NPM_EXACT+='|drizzle-orm|astro|svelte|vue|nuxt|tailwindcss|vite|next-auth'
|
||||||
|
NPM_EXACT+='|motion|framer-motion|ai|openai|langchain|remix|fastify'
|
||||||
|
# Scoped npm orgs (@org/…).
|
||||||
|
NPM_SCOPED='prisma|supabase|astrojs|sveltejs|tanstack|clerk|anthropic-ai'
|
||||||
|
NPM_SCOPED+='|langchain|remix-run|nestjs|tailwindcss'
|
||||||
|
# Python distributions (requirements.txt / pyproject.toml).
|
||||||
|
PY_LIBS='fastapi|pydantic|sqlalchemy|langchain'
|
||||||
|
|
||||||
|
CACHE_MAX_AGE_DAYS=7
|
||||||
|
|
||||||
|
npm_fast_libs() { # $1=dir — matching dependency keys, one per line
|
||||||
|
[ -f "$1/package.json" ] || return 0
|
||||||
|
jq -r '((.dependencies // {}) + (.devDependencies // {})) | keys[]' \
|
||||||
|
"$1/package.json" 2>/dev/null \
|
||||||
|
| grep -E "^(${NPM_EXACT})\$|^@(${NPM_SCOPED})/" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
py_fast_libs() { # $1=dir — matching distributions, one per line
|
||||||
|
grep -hoiE "\b(${PY_LIBS})\b" \
|
||||||
|
"$1/requirements.txt" "$1/pyproject.toml" 2>/dev/null \
|
||||||
|
| tr '[:upper:]' '[:lower:]' | LC_ALL=C sort -u || true
|
||||||
|
}
|
||||||
|
|
||||||
|
detect() { # $1=dir — union, sorted unique; exit 1 when empty
|
||||||
|
local libs
|
||||||
|
# LC_ALL=C: deterministic order whatever the caller's locale.
|
||||||
|
libs="$(printf '%s\n%s\n' "$(npm_fast_libs "$1")" "$(py_fast_libs "$1")" \
|
||||||
|
| sed '/^$/d' | LC_ALL=C sort -u)"
|
||||||
|
[ -n "$libs" ] || return 1
|
||||||
|
printf '%s\n' "$libs"
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_status() { # $1=dir — fresh|stale|missing; exit 0 only when fresh
|
||||||
|
[ -d "$1/.ctx7-cache" ] || { echo missing; return 1; }
|
||||||
|
if [ -n "$(find "$1/.ctx7-cache" -name '*.md' \
|
||||||
|
-mtime "-${CACHE_MAX_AGE_DAYS}" -print -quit 2>/dev/null)" ]; then
|
||||||
|
echo fresh; return 0
|
||||||
|
fi
|
||||||
|
echo stale; return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
|
detect) detect "${2:-.}" ;;
|
||||||
|
cache-status) cache_status "${2:-.}" ;;
|
||||||
|
*) echo "usage: fast-libs.sh detect|cache-status [dir]" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
@@ -239,6 +239,7 @@ gitflow_start feature glwork >/dev/null 2>&1
|
|||||||
# proving this backstop is NOT gated by the branch-protection check above it)
|
# proving this backstop is NOT gated by the branch-protection check above it)
|
||||||
printf 'aws_access_key_id = AKIA%s\n' "GDR5XRBXYARW2I5N" > secret.txt
|
printf 'aws_access_key_id = AKIA%s\n' "GDR5XRBXYARW2I5N" > secret.txt
|
||||||
git add secret.txt
|
git add secret.txt
|
||||||
|
# shellcheck disable=SC2034 # gl_out is used in the deferred chk eval strings
|
||||||
gl_out="$(git commit -q -m "add secret" 2>&1)"; gl_rc=$?
|
gl_out="$(git commit -q -m "add secret" 2>&1)"; gl_rc=$?
|
||||||
chk "T16a fake secret on feature branch → blocked" "[ $gl_rc -ne 0 ]"
|
chk "T16a fake secret on feature branch → blocked" "[ $gl_rc -ne 0 ]"
|
||||||
chk "T16a message mentions gitleaks" 'printf "%s" "$gl_out" | grep -qi gitleaks'
|
chk "T16a message mentions gitleaks" 'printf "%s" "$gl_out" | grep -qi gitleaks'
|
||||||
@@ -252,10 +253,57 @@ chk "T16b clean commit still succeeds" 'git commit -q -m "clean work" 2>/dev/nul
|
|||||||
# T16c — gitleaks missing from PATH → warn, never block (defense in depth
|
# T16c — gitleaks missing from PATH → warn, never block (defense in depth
|
||||||
# must not become a new single point of failure)
|
# must not become a new single point of failure)
|
||||||
echo clean2 > clean2.txt; git add clean2.txt
|
echo clean2 > clean2.txt; git add clean2.txt
|
||||||
|
# shellcheck disable=SC2034 # noleaks_out is used in the deferred chk eval strings
|
||||||
noleaks_out="$(PATH=/usr/bin:/bin git commit -q -m "clean work 2" 2>&1)"; noleaks_rc=$?
|
noleaks_out="$(PATH=/usr/bin:/bin git commit -q -m "clean work 2" 2>&1)"; noleaks_rc=$?
|
||||||
chk "T16c missing-gitleaks → still commits (rc0)" "[ $noleaks_rc -eq 0 ]"
|
chk "T16c missing-gitleaks → still commits (rc0)" "[ $noleaks_rc -eq 0 ]"
|
||||||
chk "T16c missing-gitleaks → warns" 'printf "%s" "$noleaks_out" | grep -qi "not installed"'
|
chk "T16c missing-gitleaks → warns" 'printf "%s" "$noleaks_out" | grep -qi "not installed"'
|
||||||
|
|
||||||
|
echo "T17 — finish auto-purges transient superpowers artifacts (BDR-065)"
|
||||||
|
# T17a — feature carrying docs/superpowers spec+plan: purged before merge,
|
||||||
|
# develop TIP clean, artifacts still recoverable from history (archive property)
|
||||||
|
newrepo purgefeat; echo a>a; hookon; gitflow_init >/dev/null 2>&1
|
||||||
|
gitflow_start feature pf >/dev/null 2>&1
|
||||||
|
mkdir -p docs/superpowers/specs docs/superpowers/plans
|
||||||
|
echo spec > docs/superpowers/specs/s.md
|
||||||
|
echo plan > docs/superpowers/plans/p.md
|
||||||
|
echo code > feat.txt
|
||||||
|
git add -A; git commit -q -m "feat + transient spec/plan"
|
||||||
|
gitflow_finish >/dev/null 2>&1
|
||||||
|
# the add-commit stays reachable from develop via the --no-ff merge's 2nd parent;
|
||||||
|
# --full-history defeats the path simplification that hides it, and `git show
|
||||||
|
# <sha>:path` proves BDR-065's "git history = the archive" recovery.
|
||||||
|
# shellcheck disable=SC2034 # pf_add_sha is used in the deferred chk eval string
|
||||||
|
pf_add_sha="$(git log develop --full-history --format=%H -- docs/superpowers/specs/s.md | tail -1)"
|
||||||
|
chk "T17a merged into develop" 'git log develop --oneline | grep -q "Merge feature/pf into develop"'
|
||||||
|
chk "T17a develop TIP has no transient" '[ -z "$(git ls-tree -r develop --name-only -- docs/superpowers)" ]'
|
||||||
|
chk "T17a purge commit on record" 'git log develop --oneline | grep -q "purge transient planning artifacts"'
|
||||||
|
chk "T17a artifact recoverable from history" '[ "$(git show "$pf_add_sha":docs/superpowers/specs/s.md 2>/dev/null)" = spec ]'
|
||||||
|
chk "T17a non-transient code survives" 'git ls-tree -r develop --name-only | grep -qx feat.txt'
|
||||||
|
chk "T17a feature branch deleted" '! git rev-parse --verify -q refs/heads/feature/pf >/dev/null'
|
||||||
|
|
||||||
|
# T17b — no artifacts → purge is a silent no-op, no spurious commit
|
||||||
|
newrepo purgenone; echo a>a; hookon; gitflow_init >/dev/null 2>&1
|
||||||
|
gitflow_start feature pn >/dev/null 2>&1; echo w>w.txt; git add w.txt; git commit -q -m w
|
||||||
|
gitflow_finish >/dev/null 2>&1
|
||||||
|
chk "T17b merged into develop" 'git log develop --oneline | grep -q "Merge feature/pn into develop"'
|
||||||
|
chk "T17b no purge commit created" '! git log develop --oneline | grep -q "purge transient"'
|
||||||
|
|
||||||
|
# T17c — opt-out (GITFLOW_PURGE_TRANSIENT=0) keeps the artifacts on develop
|
||||||
|
newrepo purgeoff; echo a>a; hookon; gitflow_init >/dev/null 2>&1
|
||||||
|
gitflow_start feature po >/dev/null 2>&1
|
||||||
|
mkdir -p docs/superpowers/specs; echo spec > docs/superpowers/specs/s.md
|
||||||
|
git add -A; git commit -q -m "feat + spec"
|
||||||
|
GITFLOW_PURGE_TRANSIENT=0 gitflow_finish >/dev/null 2>&1
|
||||||
|
chk "T17c opt-out keeps transient on develop TIP" '[ -n "$(git ls-tree -r develop --name-only -- docs/superpowers)" ]'
|
||||||
|
|
||||||
|
# T17d — chore is OUT of purge scope (only feature/bugfix originate artifacts)
|
||||||
|
newrepo purgechore; echo a>a; hookon; gitflow_init >/dev/null 2>&1
|
||||||
|
gitflow_start chore pc >/dev/null 2>&1
|
||||||
|
mkdir -p docs/superpowers/specs; echo spec > docs/superpowers/specs/s.md
|
||||||
|
git add -A; git commit -q -m "chore + spec"
|
||||||
|
gitflow_finish >/dev/null 2>&1
|
||||||
|
chk "T17d chore leaves transient (not in scope)" '[ -n "$(git ls-tree -r develop --name-only -- docs/superpowers)" ]'
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "==== RESULT: $PASS passed, $FAIL failed ===="
|
echo "==== RESULT: $PASS passed, $FAIL failed ===="
|
||||||
[ "$FAIL" -eq 0 ]
|
[ "$FAIL" -eq 0 ]
|
||||||
|
|||||||
+48
-2
@@ -18,6 +18,12 @@ GITFLOW_MAIN="main"
|
|||||||
GITFLOW_DEVELOP="develop"
|
GITFLOW_DEVELOP="develop"
|
||||||
# template resolved relative to the lib; overridable for tests.
|
# template resolved relative to the lib; overridable for tests.
|
||||||
GITFLOW_GITIGNORE_TEMPLATE="${GITFLOW_GITIGNORE_TEMPLATE:-$_GITFLOW_LIB_DIR/../templates/gitignore/standard.gitignore}"
|
GITFLOW_GITIGNORE_TEMPLATE="${GITFLOW_GITIGNORE_TEMPLATE:-$_GITFLOW_LIB_DIR/../templates/gitignore/standard.gitignore}"
|
||||||
|
# Transient planning artifacts (superpowers spec/plan). A feature/bugfix run
|
||||||
|
# COMMITS them (SDD worktree + reviewers read them from disk); finish PURGES
|
||||||
|
# them before the merge reaches develop's tip (BDR-065). Fixed path list;
|
||||||
|
# read GITFLOW_PURGE_TRANSIENT=0 at finish time to opt out (read in the helper,
|
||||||
|
# never cached here, so an inline `VAR=0 gitflow_finish` override works).
|
||||||
|
GITFLOW_TRANSIENT_PATHS=("docs/superpowers/specs" "docs/superpowers/plans")
|
||||||
|
|
||||||
# ── predicates / pure helpers ────────────────────────────────────────────────
|
# ── predicates / pure helpers ────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -97,6 +103,42 @@ _gitflow_delete() { # <branch>
|
|||||||
git branch -q -d "$br" || { echo "gitflow: '$br' not fully merged — branch kept" >&2; return 5; }
|
git branch -q -d "$br" || { echo "gitflow: '$br' not fully merged — branch kept" >&2; return 5; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# _gitflow_purge_transient → remove the committed transient planning artifacts
|
||||||
|
# (BDR-065) from the CURRENT branch just before the directed merge. Result: the
|
||||||
|
# removal rides the feature/bugfix branch, whose earlier commits stay reachable
|
||||||
|
# from develop through the --no-ff merge (`git show <sha>:…` = the archive),
|
||||||
|
# while develop's TIP lands clean. Automates the manual post-merge chore that
|
||||||
|
# BDR-065 left as doctrine (and that slipped once — commit 655e364).
|
||||||
|
#
|
||||||
|
# BEST-EFFORT BY CONTRACT: this NEVER aborts a finish. Nothing tracked → no-op;
|
||||||
|
# uncommitted changes under those paths, or a failed commit → warn + degrade to
|
||||||
|
# the old manual-cleanup behaviour, index/tree restored, merge still proceeds.
|
||||||
|
# The scoped commit (`-- <paths>`) records only the deletions, so a dirty index
|
||||||
|
# is never swept in. Opt out with GITFLOW_PURGE_TRANSIENT=0.
|
||||||
|
_gitflow_purge_transient() {
|
||||||
|
[ "${GITFLOW_PURGE_TRANSIENT:-1}" = 1 ] || return 0
|
||||||
|
local p; local -a tracked=()
|
||||||
|
for p in "${GITFLOW_TRANSIENT_PATHS[@]}"; do
|
||||||
|
[ -n "$(git ls-files -- "$p")" ] && tracked+=("$p")
|
||||||
|
done
|
||||||
|
[ "${#tracked[@]}" -gt 0 ] || return 0 # nothing tracked → no-op
|
||||||
|
# only purge paths with no pending changes → git rm is all-or-nothing safe and
|
||||||
|
# never discards uncommitted work under docs/superpowers.
|
||||||
|
if ! git diff --quiet HEAD -- "${tracked[@]}" 2>/dev/null; then
|
||||||
|
echo "gitflow: transient artifacts have uncommitted changes — purge skipped, finishing without it (clean up by hand)" >&2
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if git rm -r -q -- "${tracked[@]}" >/dev/null 2>&1 \
|
||||||
|
&& git commit -q -m "chore: purge transient planning artifacts (BDR-065)" -- "${tracked[@]}"; then
|
||||||
|
echo "gitflow: purged transient planning artifacts before merge (${tracked[*]})" >&2
|
||||||
|
else
|
||||||
|
echo "gitflow: transient-artifact purge failed — finishing without it (clean up by hand)" >&2
|
||||||
|
git reset -q HEAD -- "${tracked[@]}" 2>/dev/null || true # unstage any partial rm
|
||||||
|
git checkout -q -- "${tracked[@]}" 2>/dev/null || true # restore working tree
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# gitflow_finish [<type> <name>] → directed merge of the CURRENT branch per its
|
# gitflow_finish [<type> <name>] → directed merge of the CURRENT branch per its
|
||||||
# type, then delete. WHEN to call this is the human gate (SKILL.md).
|
# type, then delete. WHEN to call this is the human gate (SKILL.md).
|
||||||
#
|
#
|
||||||
@@ -117,7 +159,10 @@ gitflow_finish() {
|
|||||||
fi
|
fi
|
||||||
type="$(gitflow_branch_type "$br")"
|
type="$(gitflow_branch_type "$br")"
|
||||||
case "$type" in
|
case "$type" in
|
||||||
feature|bugfix|chore)
|
feature|bugfix)
|
||||||
|
_gitflow_purge_transient # BDR-065 auto-cleanup, on HEAD, pre-merge; never blocks
|
||||||
|
_gitflow_merge_into "$GITFLOW_DEVELOP" "$br" && _gitflow_delete "$br" ;;
|
||||||
|
chore)
|
||||||
_gitflow_merge_into "$GITFLOW_DEVELOP" "$br" && _gitflow_delete "$br" ;;
|
_gitflow_merge_into "$GITFLOW_DEVELOP" "$br" && _gitflow_delete "$br" ;;
|
||||||
release)
|
release)
|
||||||
_gitflow_merge_into "$GITFLOW_MAIN" "$br" \
|
_gitflow_merge_into "$GITFLOW_MAIN" "$br" \
|
||||||
@@ -283,8 +328,9 @@ if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
|
|||||||
finish) gitflow_finish "$@" ;;
|
finish) gitflow_finish "$@" ;;
|
||||||
init) gitflow_init "$@" ;;
|
init) gitflow_init "$@" ;;
|
||||||
reconcile) gitflow_reconcile_gitignore "$@" ;;
|
reconcile) gitflow_reconcile_gitignore "$@" ;;
|
||||||
|
purge-transient) _gitflow_purge_transient ;;
|
||||||
install-hook) gitflow_install_hook "$@" ;;
|
install-hook) gitflow_install_hook "$@" ;;
|
||||||
emit-hook) _gitflow_emit_pre_commit ;;
|
emit-hook) _gitflow_emit_pre_commit ;;
|
||||||
*) echo "usage: gitflow.sh {type|protected-base|base-for|release-open|start|finish|init|reconcile|install-hook|emit-hook}" >&2; exit 2 ;;
|
*) echo "usage: gitflow.sh {type|protected-base|base-for|release-open|start|finish|init|reconcile|purge-transient|install-hook|emit-hook}" >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -35,3 +35,13 @@ yet rewritten) — that is why the self-check exists alongside it.
|
|||||||
|
|
||||||
then end the turn. No later step runs, no agent is dispatched, nothing is
|
then end the turn. No later step runs, no agent is dispatched, nothing is
|
||||||
edited.
|
edited.
|
||||||
|
|
||||||
|
## 4. Dispatch tiers (BDR-077 — no inherit)
|
||||||
|
|
||||||
|
The gate guards the MAIN loop only. Dispatched work NEVER inherits the
|
||||||
|
session model: typed agents run on their frontmatter pin; built-ins
|
||||||
|
(general-purpose / Explore / Plan) carry an explicit `model=` at every call
|
||||||
|
site — `model: "fable"` when the child performs reflection/orchestration on
|
||||||
|
the main loop's behalf (skill-runners), otherwise its complexity tier
|
||||||
|
(opus = dispatched judgment, sonnet = execution/collection, haiku = short
|
||||||
|
mechanical probes).
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
# Plugin gate — shared consumer include (plugin-check, onboard, init-project, ship-feature STEP 0)
|
||||||
|
|
||||||
|
Runs in the CONSUMER'S MAIN LOOP. The detection and the reasoning are
|
||||||
|
dispatched (BDR-077 tiers); the validation checkpoint, the report
|
||||||
|
presentation, and the apply gate live HERE — a dispatched agent can neither
|
||||||
|
ask the user nor safely mutate plugin state.
|
||||||
|
|
||||||
|
## 1. PROBE (dispatch — sonnet)
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(subagent_type="plugin-probe", description="plugin gate — probe",
|
||||||
|
prompt="Run your probes from <PROJECT_ROOT>. Emit the PROBE REPORT.")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. VALIDATION CHECKPOINT (main loop — between probe and reasoner)
|
||||||
|
|
||||||
|
Validate the PROBE REPORT before any reasoning:
|
||||||
|
- `EXTERNAL` non-empty AND each listed plugin's directory appears under
|
||||||
|
`CHECKPOINT plugin-dirs`.
|
||||||
|
- At least one project signal present (MANIFESTS / FRAMEWORK-DEPS /
|
||||||
|
TSX-JSX-COUNT > 0 / DOCKER-COUNT > 0 / EMBEDDED hits). Else print
|
||||||
|
`⚠️ No project signals detected — recommendations will be conservative.`
|
||||||
|
and continue.
|
||||||
|
- `CHECKPOINT toggle-script=UNAVAILABLE` → print `⚠️ toggle script
|
||||||
|
unavailable — recommendations will be advisory only, no auto-activation.`
|
||||||
|
and SKIP step 5 (apply) entirely.
|
||||||
|
- PROBE REPORT missing/unparsable → retry the probe ONCE fresh; a 2nd
|
||||||
|
failure → STOP and surface (never reason over invented detection).
|
||||||
|
|
||||||
|
## 3. REASON (dispatch — opus)
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(subagent_type="plugin-advisor", description="plugin gate — reason",
|
||||||
|
prompt="""
|
||||||
|
REQUEST: <the user's request / project description, verbatim>
|
||||||
|
PROBE REPORT (ground truth — do not re-detect):
|
||||||
|
<the full PROBE REPORT from step 1>
|
||||||
|
""")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. PRESENT + BLOCKING GATE (main loop)
|
||||||
|
|
||||||
|
Show the returned PLUGIN CHECK block.
|
||||||
|
- `ACTION REQUIRED? YES` → offer: A) fix plugins B) type "force". STOP until
|
||||||
|
answered.
|
||||||
|
- OK → print `✅ Plugin check passed — [active plugins] — complexity: <score>%`.
|
||||||
|
|
||||||
|
## 5. APPLY GATE (main loop — only when the flow auto-activates)
|
||||||
|
|
||||||
|
If any plugin has ⚡ ENABLE status:
|
||||||
|
1. List the changes:
|
||||||
|
```
|
||||||
|
PROPOSED CHANGES:
|
||||||
|
⚡ Enable ui-ux-pro-max (frontend detected, complexity 65%)
|
||||||
|
⚡ Pre-fetch ctx7 docs for next.js, prisma
|
||||||
|
Apply these changes? (yes / no / customize)
|
||||||
|
```
|
||||||
|
2. "yes" → apply via the exact commands the advisor emitted. "customize" →
|
||||||
|
user picks. "no" → proceed with current config.
|
||||||
|
|
||||||
|
**Never auto-activate without showing the list and getting confirmation.**
|
||||||
|
|
||||||
|
### Rollback on partial failure
|
||||||
|
|
||||||
|
Track each toggle; roll back the partial set rather than leave a
|
||||||
|
half-applied configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
applied=()
|
||||||
|
for change in "${PROPOSED_CHANGES[@]}"; do
|
||||||
|
if bash "$HOME/.claude/lib/toggle-external.sh" enable "$change"; then
|
||||||
|
applied+=("$change")
|
||||||
|
else
|
||||||
|
echo "❌ failed to enable $change — rolling back ${#applied[@]} prior change(s)"
|
||||||
|
for prior in "${applied[@]}"; do
|
||||||
|
bash "$HOME/.claude/lib/toggle-external.sh" disable "$prior" \
|
||||||
|
|| echo "⚠️ rollback of $prior also failed — manual cleanup required: see ~/.claude/plugins/cache"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
Surface: `✅ Applied N change(s).` — or on failure:
|
||||||
|
|
||||||
|
```
|
||||||
|
⚠️ Toggle failed at change <name>. Rolled back the N prior change(s).
|
||||||
|
To inspect manually: ls ~/.claude/plugins/cache; bash ~/.claude/lib/toggle-external.sh list
|
||||||
|
Re-run /plugin-check after fixing the underlying cause (e.g. permissions).
|
||||||
|
```
|
||||||
+80
-15
@@ -14,6 +14,9 @@
|
|||||||
# - MCPs: delegated to lib/toggle-external.sh for known servers (magic),
|
# - MCPs: delegated to lib/toggle-external.sh for known servers (magic),
|
||||||
# advisory otherwise
|
# advisory otherwise
|
||||||
# - CLIs: advisory only (rtk, gsd, ctx7, graphify — installed externally)
|
# - CLIs: advisory only (rtk, gsd, ctx7, graphify — installed externally)
|
||||||
|
# - `set` is SYMMETRIC on managed items (BDR-079): plugins, external packs
|
||||||
|
# and MCPs in the MANAGED_* allowlists are disabled when the profile
|
||||||
|
# does not list them — nothing outside those lists is ever auto-toggled.
|
||||||
#
|
#
|
||||||
# Always-on plugins (never toggled by `set`): security-guidance,
|
# Always-on plugins (never toggled by `set`): security-guidance,
|
||||||
# superpowers + rtk hook + .claude internal. The script refuses to disable
|
# superpowers + rtk hook + .claude internal. The script refuses to disable
|
||||||
@@ -61,6 +64,23 @@ MANAGED_PLUGINS=(
|
|||||||
"pr-review-toolkit@claude-code-plugins"
|
"pr-review-toolkit@claude-code-plugins"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# External skill packs that are toggle-managed by `set` — same allowlist
|
||||||
|
# doctrine as MANAGED_PLUGINS: listed here only when the enabled state is
|
||||||
|
# task-type-driven. `set` disables these when the profile does not list
|
||||||
|
# them; anything else external (e.g. darwin-skill) is never auto-touched.
|
||||||
|
MANAGED_EXTERNALS=(
|
||||||
|
emil-design-eng
|
||||||
|
frontend-design
|
||||||
|
design-motion-principles
|
||||||
|
impeccable
|
||||||
|
)
|
||||||
|
|
||||||
|
# MCP servers that are toggle-managed by `set`, both ways (enable AND
|
||||||
|
# disable), delegated to lib/toggle-external.sh. Same allowlist doctrine.
|
||||||
|
MANAGED_MCPS=(
|
||||||
|
magic
|
||||||
|
)
|
||||||
|
|
||||||
# Plugins that MUST stay enabled — `set` will refuse to disable these even if
|
# Plugins that MUST stay enabled — `set` will refuse to disable these even if
|
||||||
# they're not in the profile. (Defensive: belt-and-suspenders alongside
|
# they're not in the profile. (Defensive: belt-and-suspenders alongside
|
||||||
# MANAGED_PLUGINS allowlist.)
|
# MANAGED_PLUGINS allowlist.)
|
||||||
@@ -271,6 +291,11 @@ enable_skill() {
|
|||||||
ok "enabled: $skill ($type)"
|
ok "enabled: $skill ($type)"
|
||||||
elif [ -e "$SKILLS_DIR/$skill" ]; then
|
elif [ -e "$SKILLS_DIR/$skill" ]; then
|
||||||
:
|
:
|
||||||
|
elif [ "$type" = external ] && [ -d "$REPO/skills-external/$skill" ]; then
|
||||||
|
# Symlink never created (or hand-removed): recreate it from the
|
||||||
|
# vendored pack — mirrors toggle-external.sh's from-source path.
|
||||||
|
ln -sf "$REPO/skills-external/$skill" "$SKILLS_DIR/$skill"
|
||||||
|
ok "enabled: $skill (external, symlink created)"
|
||||||
else
|
else
|
||||||
warn "missing: $skill ($type)"
|
warn "missing: $skill ($type)"
|
||||||
fi
|
fi
|
||||||
@@ -422,6 +447,48 @@ parked_gstack_count() {
|
|||||||
find "$DISABLED_DIR" -maxdepth 1 -name 'gstack__*' 2>/dev/null | wc -l | tr -d ' '
|
find "$DISABLED_DIR" -maxdepth 1 -name 'gstack__*' 2>/dev/null | wc -l | tr -d ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── `set` trim helpers — one per managed category ─────────────
|
||||||
|
# Each disables the managed items NOT listed in the given profile. Allowlist
|
||||||
|
# doctrine: only MANAGED_* entries are ever auto-disabled.
|
||||||
|
|
||||||
|
disable_plugins_not_in() {
|
||||||
|
local prof="$1" keep_file p plugin_name marketplace
|
||||||
|
keep_file="$(mktemp)"
|
||||||
|
read_profile "$prof" \
|
||||||
|
| awk -F'\t' '$2 ~ /^plugin@/ { sub(/^plugin@/, "", $2); print $1"@"$2 }' \
|
||||||
|
| sort -u > "$keep_file"
|
||||||
|
for p in "${MANAGED_PLUGINS[@]}"; do
|
||||||
|
if ! grep -qx "$p" "$keep_file"; then
|
||||||
|
plugin_name="${p%@*}"
|
||||||
|
marketplace="${p#*@}"
|
||||||
|
disable_skill "$plugin_name" "plugin@${marketplace}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
rm -f "$keep_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_externals_not_in() {
|
||||||
|
local prof="$1" keep_file x
|
||||||
|
keep_file="$(mktemp)"
|
||||||
|
read_profile "$prof" | awk -F'\t' '$2 == "external" { print $1 }' \
|
||||||
|
| sort -u > "$keep_file"
|
||||||
|
for x in "${MANAGED_EXTERNALS[@]}"; do
|
||||||
|
grep -qx "$x" "$keep_file" || disable_skill "$x" external
|
||||||
|
done
|
||||||
|
rm -f "$keep_file"
|
||||||
|
}
|
||||||
|
|
||||||
|
disable_mcps_not_in() {
|
||||||
|
local prof="$1" keep_file s
|
||||||
|
keep_file="$(mktemp)"
|
||||||
|
read_profile "$prof" | awk -F'\t' '$2 == "mcp" { print $1 }' \
|
||||||
|
| sort -u > "$keep_file"
|
||||||
|
for s in "${MANAGED_MCPS[@]}"; do
|
||||||
|
grep -qx "$s" "$keep_file" || disable_skill "$s" mcp
|
||||||
|
done
|
||||||
|
rm -f "$keep_file"
|
||||||
|
}
|
||||||
|
|
||||||
# ── Commands ──────────────────────────────────────────────
|
# ── Commands ──────────────────────────────────────────────
|
||||||
|
|
||||||
cmd_list() {
|
cmd_list() {
|
||||||
@@ -506,24 +573,20 @@ cmd_apply() {
|
|||||||
|
|
||||||
cmd_set() {
|
cmd_set() {
|
||||||
local prof="$1"
|
local prof="$1"
|
||||||
info "Setting profile: $prof (exclusive — disables non-listed gstack skills + managed plugins)"
|
info "Setting profile: $prof (exclusive — disables non-listed gstack skills + managed plugins/externals/MCPs)"
|
||||||
|
|
||||||
# Disable gstack-origin skills not in profile.
|
# Disable gstack-origin skills not in profile.
|
||||||
disable_gstack_not_in "$prof"
|
disable_gstack_not_in "$prof"
|
||||||
|
|
||||||
# Disable managed plugins not in profile (PROTECTED_PLUGINS are excluded
|
# Disable managed plugins not in profile (PROTECTED_PLUGINS are excluded
|
||||||
# by disable_skill itself — belt and suspenders).
|
# by disable_skill itself — belt and suspenders).
|
||||||
local plugin_keep_file p plugin_name marketplace
|
disable_plugins_not_in "$prof"
|
||||||
plugin_keep_file="$(mktemp)"
|
|
||||||
read_profile "$prof" | awk -F'\t' '$2 ~ /^plugin@/ { sub(/^plugin@/, "", $2); print $1"@"$2 }' | sort -u > "$plugin_keep_file"
|
# Symmetry (BDR-079): a profile switch also parks the managed external
|
||||||
for p in "${MANAGED_PLUGINS[@]}"; do
|
# packs and unregisters the managed MCPs the new profile does not need —
|
||||||
if ! grep -qx "$p" "$plugin_keep_file"; then
|
# design leftovers (emil, magic…) no longer survive a `set backend`.
|
||||||
plugin_name="${p%@*}"
|
disable_externals_not_in "$prof"
|
||||||
marketplace="${p#*@}"
|
disable_mcps_not_in "$prof"
|
||||||
disable_skill "$plugin_name" "plugin@${marketplace}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
rm -f "$plugin_keep_file"
|
|
||||||
|
|
||||||
# Enable everything listed in the profile.
|
# Enable everything listed in the profile.
|
||||||
cmd_apply "$prof"
|
cmd_apply "$prof"
|
||||||
@@ -679,9 +742,11 @@ EXAMPLES:
|
|||||||
bash lib/profile.sh reset # restore everything
|
bash lib/profile.sh reset # restore everything
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
Plugin and MCP entries print advisory commands — they are NOT toggled
|
"set" toggles the MANAGED items automatically, both ways: plugins
|
||||||
automatically. Run "claude plugin enable|disable" or "claude mcp add|remove"
|
(ui-ux-pro-max, plugin-dev, pr-review-toolkit), external packs
|
||||||
yourself for those.
|
(emil-design-eng, frontend-design, design-motion-principles, impeccable)
|
||||||
|
and the magic MCP. Anything outside those allowlists stays advisory —
|
||||||
|
run "claude plugin enable|disable" or "claude mcp add|remove" yourself.
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# lib/tests/config-protection.test.sh
|
|
||||||
set -u
|
|
||||||
H="$(cd "$(dirname "$0")/../.." && pwd)/hooks/config-protection.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; }
|
|
||||||
# Run hook for a file_path with NO sentinel present (CWD = a clean temp dir).
|
|
||||||
run() { local c r; c="$(mktemp -d)"; ( cd "$c" && printf \
|
|
||||||
'{"tool_name":"Edit","tool_input":{"file_path":"%s"}}' "$1" | bash "$H" ) \
|
|
||||||
>/dev/null 2>&1; r=$?; rm -rf "$c"; return "$r"; }
|
|
||||||
|
|
||||||
# --- Guarded quality-gate files -> blocked (exit 2) ---
|
|
||||||
run "/home/u/Documents/claude/lib/gitflow.sh"; check T1-gitflow "$?" 2
|
|
||||||
run "/home/u/.claude/settings.json"; check T2-live-settings "$?" 2
|
|
||||||
run "/home/u/Documents/claude/.claude/settings.local.json"; check T3-local-settings "$?" 2
|
|
||||||
run "/home/u/Documents/claude/settings.json"; check T4-root-settings "$?" 2
|
|
||||||
run "/home/u/Documents/claude/.githooks/pre-commit"; check T5-githook "$?" 2
|
|
||||||
run "/home/u/Documents/claude/doctor.sh"; check T6-doctor "$?" 2
|
|
||||||
run "/home/u/Documents/claude/.shellcheckrc"; check T7-shellcheckrc "$?" 2
|
|
||||||
# self-guard: the hook itself, other hooks, and the test suite are guarded
|
|
||||||
run "/home/u/Documents/claude/hooks/config-protection.sh"; check T8-self-guard "$?" 2
|
|
||||||
run "/home/u/.claude/hooks/session-start.sh"; check T9-deployed-hook "$?" 2
|
|
||||||
run "/home/u/Documents/claude/lib/tests/config-protection.test.sh"; check T10-tests-guarded "$?" 2
|
|
||||||
|
|
||||||
# --- Non-guarded -> allowed (exit 0) ---
|
|
||||||
run "/home/u/Documents/claude/lib/gitflow-migrate.sh"; check T11-near-miss "$?" 0
|
|
||||||
run "/home/u/project/src/app.js"; check T12-code "$?" 0
|
|
||||||
run "/home/u/project/settings.json"; check T13-foreign-settings "$?" 0
|
|
||||||
|
|
||||||
# --- Fail-open on malformed input (no file_path) -> allowed ---
|
|
||||||
c="$(mktemp -d)"; ( cd "$c" && printf '{}' | bash "$H" ) >/dev/null 2>&1
|
|
||||||
check T14-fail-open "$?" 0; rm -rf "$c"
|
|
||||||
|
|
||||||
# --- Sentinel one-shot: non-empty reason -> allow + log + consume; 2nd edit blocked ---
|
|
||||||
tmp="$(mktemp -d)"; mkdir -p "$tmp/.claude"
|
|
||||||
printf 'fixing eslint false-positive' > "$tmp/.claude/.config-edit-ok"
|
|
||||||
( cd "$tmp" && printf '{"tool_name":"Edit","tool_input":{"file_path":"/x/doctor.sh"}}' \
|
|
||||||
| HOME="$tmp" bash "$H" ) >/dev/null 2>&1
|
|
||||||
check T15-sentinel-allow "$?" 0
|
|
||||||
check T15-consumed "$([ -e "$tmp/.claude/.config-edit-ok" ] && echo present || echo gone)" gone
|
|
||||||
check T15-logged "$(grep -c 'BYPASS.*doctor.sh.*fixing eslint' \
|
|
||||||
"$tmp/.claude/logs/config-protection.log" 2>/dev/null)" 1
|
|
||||||
( cd "$tmp" && printf '{"tool_name":"Edit","tool_input":{"file_path":"/x/doctor.sh"}}' \
|
|
||||||
| HOME="$tmp" bash "$H" ) >/dev/null 2>&1
|
|
||||||
check T16-second-blocked "$?" 2
|
|
||||||
rm -rf "$tmp"
|
|
||||||
|
|
||||||
# --- Sentinel with EMPTY reason -> refused + consumed ---
|
|
||||||
tmp="$(mktemp -d)"; mkdir -p "$tmp/.claude"; : > "$tmp/.claude/.config-edit-ok"
|
|
||||||
( cd "$tmp" && printf '{"tool_name":"Edit","tool_input":{"file_path":"/x/doctor.sh"}}' \
|
|
||||||
| HOME="$tmp" bash "$H" ) >/dev/null 2>&1
|
|
||||||
check T17-empty-refused "$?" 2
|
|
||||||
check T17-consumed "$([ -e "$tmp/.claude/.config-edit-ok" ] && echo present || echo gone)" gone
|
|
||||||
rm -rf "$tmp"
|
|
||||||
|
|
||||||
# --- T18/T19: payload shapes beyond Edit (locks against future Edit-only narrowing) ---
|
|
||||||
c="$(mktemp -d)"; ( cd "$c" && printf \
|
|
||||||
'{"tool_name":"Write","tool_input":{"file_path":"/x/doctor.sh","content":"x"}}' | bash "$H" ) \
|
|
||||||
>/dev/null 2>&1; check T18-write-payload "$?" 2; rm -rf "$c"
|
|
||||||
|
|
||||||
c="$(mktemp -d)"; ( cd "$c" && printf \
|
|
||||||
'{"tool_name":"MultiEdit","tool_input":{"file_path":"/x/doctor.sh","edits":[{"old_string":"a","new_string":"b"}]}}' | bash "$H" ) \
|
|
||||||
>/dev/null 2>&1; check T19-multiedit-payload "$?" 2; rm -rf "$c"
|
|
||||||
|
|
||||||
# --- T20: sentinel with ONLY whitespace bytes (not literally empty) -> refused + consumed ---
|
|
||||||
tmp="$(mktemp -d)"; mkdir -p "$tmp/.claude"; printf ' \n\t' > "$tmp/.claude/.config-edit-ok"
|
|
||||||
( cd "$tmp" && printf '{"tool_name":"Edit","tool_input":{"file_path":"/x/doctor.sh"}}' \
|
|
||||||
| HOME="$tmp" bash "$H" ) >/dev/null 2>&1
|
|
||||||
check T20-whitespace-only-refused "$?" 2
|
|
||||||
check T20-whitespace-only-consumed "$([ -e "$tmp/.claude/.config-edit-ok" ] && echo present || echo gone)" gone
|
|
||||||
rm -rf "$tmp"
|
|
||||||
|
|
||||||
printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ]
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# lib/tests/fast-libs.test.sh — fast-libs.sh verbs + ctx7-reminder hook (BDR-078)
|
||||||
|
set -u
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
L="$ROOT/lib/fast-libs.sh"
|
||||||
|
H="$ROOT/hooks/ctx7-reminder.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; }
|
||||||
|
|
||||||
|
tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
|
||||||
|
|
||||||
|
# --- detect: JS fast-libs matched, stable deps ignored ---
|
||||||
|
mkdir -p "$tmp/js"
|
||||||
|
cat > "$tmp/js/package.json" <<'EOF'
|
||||||
|
{"dependencies":{"react":"^19","express":"^5","@tanstack/react-query":"^5"},
|
||||||
|
"devDependencies":{"vite":"^6","lodash":"^4"}}
|
||||||
|
EOF
|
||||||
|
check T1-js-detect "$(bash "$L" detect "$tmp/js" | tr '\n' ' ')" \
|
||||||
|
"@tanstack/react-query react vite "
|
||||||
|
|
||||||
|
# react-icons must NOT ride the react match (anchored full-key)
|
||||||
|
mkdir -p "$tmp/near"
|
||||||
|
printf '{"dependencies":{"react-icons":"^5","express":"^5"}}' \
|
||||||
|
> "$tmp/near/package.json"
|
||||||
|
check T2-near-miss "$(bash "$L" detect "$tmp/near" >/dev/null 2>&1; echo $?)" 1
|
||||||
|
|
||||||
|
# --- detect: python manifest + stable-tech project (exit 1) ---
|
||||||
|
mkdir -p "$tmp/py"
|
||||||
|
printf 'fastapi==0.115\nrequests>=2\n' > "$tmp/py/requirements.txt"
|
||||||
|
check T3-py-detect "$(bash "$L" detect "$tmp/py")" "fastapi"
|
||||||
|
mkdir -p "$tmp/cpp"
|
||||||
|
check T4-none "$(bash "$L" detect "$tmp/cpp" >/dev/null 2>&1; echo $?)" 1
|
||||||
|
|
||||||
|
# --- cache-status: missing / fresh / stale ---
|
||||||
|
check T5-missing "$(bash "$L" cache-status "$tmp/js" || true)" missing
|
||||||
|
mkdir -p "$tmp/js/.ctx7-cache"; touch "$tmp/js/.ctx7-cache/react-core.md"
|
||||||
|
check T6-fresh "$(bash "$L" cache-status "$tmp/js")" fresh
|
||||||
|
touch -d '10 days ago' "$tmp/js/.ctx7-cache/react-core.md"
|
||||||
|
check T7-stale "$(bash "$L" cache-status "$tmp/js" || true)" stale
|
||||||
|
|
||||||
|
# --- hook: fires once per session, silent on stable projects ---
|
||||||
|
hook() { printf '{"prompt":"add a hook","session_id":"%s","cwd":"%s"}' \
|
||||||
|
"$1" "$2" | TMPDIR="$tmp" bash "$H"; }
|
||||||
|
check H1-fires "$(hook s1 "$tmp/js" | grep -c 'Fast-moving')" 1
|
||||||
|
check H2-once "$(hook s1 "$tmp/js" | wc -l)" 0
|
||||||
|
check H3-cpp-quiet "$(hook s2 "$tmp/cpp" | wc -l)" 0
|
||||||
|
check H4-notif-quiet \
|
||||||
|
"$(printf '{"prompt":"<task-notification>x","session_id":"s3","cwd":"%s"}' \
|
||||||
|
"$tmp/js" | TMPDIR="$tmp" bash "$H" | wc -l)" 0
|
||||||
|
|
||||||
|
printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ]
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# lib/tests/model-routing.test.sh — census: gate wiring + pins + executor shape (BDR-066)
|
# lib/tests/model-routing.test.sh — census: gate wiring + pins + executor shape (BDR-066, BDR-076)
|
||||||
set -u
|
set -u
|
||||||
R="$(cd "$(dirname "$0")/../.." && pwd)"
|
R="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
pass=0; fail=0
|
pass=0; fail=0
|
||||||
@@ -22,7 +22,7 @@ has "agents/feater.md" 'model: sonnet'
|
|||||||
has "agents/hotfixer.md" 'model: sonnet'
|
has "agents/hotfixer.md" 'model: sonnet'
|
||||||
has "agents/verifier.md" 'model: sonnet'
|
has "agents/verifier.md" 'model: sonnet'
|
||||||
has "agents/security-auditor.md" 'model: sonnet'
|
has "agents/security-auditor.md" 'model: sonnet'
|
||||||
fm_lacks "agents/analyzer.md" 'model:'
|
has "agents/analyzer.md" 'model: opus'
|
||||||
# 4) /feat executor shape
|
# 4) /feat executor shape
|
||||||
has "skills/feat/SKILL.md" 'subagent_type="feater"'
|
has "skills/feat/SKILL.md" 'subagent_type="feater"'
|
||||||
has "skills/feat/SKILL.md" 'verify-secure-loop.md'
|
has "skills/feat/SKILL.md" 'verify-secure-loop.md'
|
||||||
@@ -54,17 +54,116 @@ lacks "agents/handover-doc-writer.md" 'AskUserQuestion'
|
|||||||
lacks "agents/handover-doc-writer.md" 'Agent('
|
lacks "agents/handover-doc-writer.md" 'Agent('
|
||||||
has "agents/client-handover-writer.md" 'subagent_type="handover-doc-writer"'
|
has "agents/client-handover-writer.md" 'subagent_type="handover-doc-writer"'
|
||||||
# 10) post-merge edge fixes (ronde): F1 feater applier carve-out, F2 /refactor
|
# 10) post-merge edge fixes (ronde): F1 feater applier carve-out, F2 /refactor
|
||||||
# dispatch + pin, F3 /analyze gated (in loop 1), F4 interviewer un-pinned,
|
# dispatch + pin, F3 /analyze gated (in loop 1)
|
||||||
# F5 audit agents' ABSENT pin locked (a stray sonnet pin would silently
|
|
||||||
# downgrade a live audit even though the skill's gate passed)
|
|
||||||
has "agents/feater.md" 'Applier path'
|
has "agents/feater.md" 'Applier path'
|
||||||
has "skills/refactor/SKILL.md" 'subagent_type="refactorer"'
|
has "skills/refactor/SKILL.md" 'subagent_type="refactorer"'
|
||||||
has "agents/refactorer.md" 'model: sonnet'
|
has "agents/refactorer.md" 'model: sonnet'
|
||||||
fm_lacks "agents/seo-analyzer.md" 'model:'
|
# 11) BDR-076/077 — session model = orchestration + inline reflection ONLY.
|
||||||
fm_lacks "agents/geo-analyzer.md" 'model:'
|
# Dispatched judgment agents pinned OPUS. validator-analyzer TIERED DOWN
|
||||||
fm_lacks "agents/validator-analyzer.md" 'model:'
|
# to sonnet (W3 — deterministic validator-runner + fixed deduction
|
||||||
|
# tables, no deep judgment; approved plan). Inline-load-only agents
|
||||||
|
# (interviewer, client-handover-writer) STAY unpinned: they run IN the
|
||||||
|
# main loop, a frontmatter pin there is inert and misleads.
|
||||||
|
has "agents/seo-analyzer.md" 'model: opus'
|
||||||
|
has "agents/geo-analyzer.md" 'model: opus'
|
||||||
|
has "agents/validator-analyzer.md" 'model: sonnet'
|
||||||
|
has "agents/plan-challenger.md" 'model: opus'
|
||||||
fm_lacks "agents/client-handover-writer.md" 'model:'
|
fm_lacks "agents/client-handover-writer.md" 'model:'
|
||||||
fm_lacks "agents/interviewer.md" 'model:'
|
fm_lacks "agents/interviewer.md" 'model:'
|
||||||
|
has "skills/onboard/SKILL.md" 'model="opus"'
|
||||||
|
has "skills/tour/SKILL.md" 'model="opus"'
|
||||||
|
has "lib/challenge-plan.md" 'BDR-076'
|
||||||
|
# 12) BDR-077 W1 — no-inherit: skill-runner children pinned fable at every
|
||||||
|
# call site; code-review dispatches carry opus; doctrine in model-gate.
|
||||||
|
# (fable dispatch alias spike-verified 2026-07-19: resolves
|
||||||
|
# claude-fable-5, enum-validated, loud failure — never silent fallback)
|
||||||
|
has "agents/client-handover-writer.md" 'model: "fable"'
|
||||||
|
has "skills/ship-feature/SKILL.md" 'model: "opus"'
|
||||||
|
has "skills/init-project/SKILL.md" 'model: "opus"'
|
||||||
|
has "lib/model-gate.md" 'model: "fable"'
|
||||||
|
lacks "lib/model-gate.md" 'model: "sonnet" in the Agent call'
|
||||||
|
# 13) BDR-077 W2 — plugin split: probe (sonnet, facts only) + advisor
|
||||||
|
# reasoner (opus, PROBE REPORT is ground truth, fail-closed); gate
|
||||||
|
# include owns checkpoint + apply; 4 consumers run the include, none
|
||||||
|
# inline-loads the advisor anymore
|
||||||
|
has "agents/plugin-probe.md" 'model: sonnet'
|
||||||
|
lacks "agents/plugin-probe.md" 'AskUserQuestion'
|
||||||
|
has "agents/plugin-advisor.md" 'model: opus'
|
||||||
|
has "agents/plugin-advisor.md" 'PROBE REPORT'
|
||||||
|
lacks "agents/plugin-advisor.md" 'PHASE 1 — DETECT'
|
||||||
|
has "lib/plugin-gate.md" 'subagent_type="plugin-probe"'
|
||||||
|
has "lib/plugin-gate.md" 'subagent_type="plugin-advisor"'
|
||||||
|
for s in plugin-check onboard init-project ship-feature; do
|
||||||
|
has "skills/$s/SKILL.md" 'lib/plugin-gate.md'
|
||||||
|
# shellcheck disable=SC2016 # literal $HOME wanted: matching the exact inline-load string
|
||||||
|
lacks "skills/$s/SKILL.md" 'Load `$HOME/.claude/agents/plugin-advisor.md`'
|
||||||
|
done
|
||||||
|
# 14) BDR-077 W2/S2 — doc pipeline: ONE agent, TWO modes around the
|
||||||
|
# dispatcher's gate (audit = opus via call-site override — documented
|
||||||
|
# precedence over the sonnet pin; patch = sonnet pin). Gate hoisted out
|
||||||
|
# of the agent (a dispatched agent cannot ask); CHANGE SUMMARY crosses
|
||||||
|
# the dispatch boundary into doc-commit (LRN-126); scaffolder carries no
|
||||||
|
# doc step; no consumer inline-loads doc-syncer anymore.
|
||||||
|
has "agents/doc-syncer.md" 'MODE: audit'
|
||||||
|
has "agents/doc-syncer.md" 'MODE: patch'
|
||||||
|
has "agents/doc-syncer.md" 'CHANGE SUMMARY'
|
||||||
|
has "agents/doc-syncer.md" 'DISPATCHER PROTOCOL'
|
||||||
|
has "lib/doc-commit.md" 'CHANGE SUMMARY'
|
||||||
|
has "skills/doc/SKILL.md" 'model="opus"'
|
||||||
|
has "skills/doc/SKILL.md" 'MODE: patch'
|
||||||
|
lacks "agents/scaffolder.md" 'INLINE-LOAD'
|
||||||
|
for s in bugfix hotfix feat ship-feature init-project; do
|
||||||
|
has "skills/$s/SKILL.md" 'MODE: audit'
|
||||||
|
has "skills/$s/SKILL.md" 'doc-syncer", model="opus"'
|
||||||
|
# shellcheck disable=SC2016 # literal $HOME wanted: matching the exact inline-load string
|
||||||
|
lacks "skills/$s/SKILL.md" 'Load `$HOME/.claude/agents/doc-syncer.md`'
|
||||||
|
done
|
||||||
|
# 15) BDR-077 W2 — last inline execution converted: scaffolder + onboarder
|
||||||
|
# are DISPATCHED (pins live); their gates/arbitration stay in the
|
||||||
|
# orchestrator loop
|
||||||
|
has "skills/init-project/SKILL.md" 'subagent_type="scaffolder"'
|
||||||
|
has "skills/onboard/SKILL.md" 'subagent_type="onboarder"'
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
lacks "skills/init-project/SKILL.md" 'Load `$HOME/.claude/agents/scaffolder.md`'
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
lacks "skills/onboard/SKILL.md" 'Load `$HOME/.claude/agents/onboarder.md`'
|
||||||
|
# 16) BDR-077 W3 — commit-changer per-mode override: propose = opus at the
|
||||||
|
# call site (documented precedence over the sonnet pin), apply = pin
|
||||||
|
has "skills/commit-change/SKILL.md" 'model="opus"'
|
||||||
|
has "agents/commit-changer.md" 'MODE: propose'
|
||||||
|
has "agents/commit-changer.md" 'model: sonnet'
|
||||||
|
# 17) BDR-077 W4 — handover two-mode: synthesize = opus at the call site
|
||||||
|
# (STEP 9/10/12 → run-scoped .audit/ draft + DRAFT COMPLETE sentinel),
|
||||||
|
# render = sonnet pin (STEP 13-16, fail-closed on absent/mismatched
|
||||||
|
# draft). Name + dispatch-string locks of §9 survive untouched.
|
||||||
|
has "agents/handover-doc-writer.md" 'MODE: synthesize'
|
||||||
|
has "agents/handover-doc-writer.md" 'MODE: render'
|
||||||
|
has "agents/handover-doc-writer.md" 'DRAFT COMPLETE'
|
||||||
|
has "agents/client-handover-writer.md" 'MODE: synthesize'
|
||||||
|
has "agents/client-handover-writer.md" 'handover-doc-writer", model="opus"'
|
||||||
|
# 18) BDR-077 W5 — seo/geo 3-mode pipelines: collect/template = sonnet at
|
||||||
|
# the call site, judge = opus PIN (fail-safe direction: a forgotten
|
||||||
|
# override over-tiers, never downgrades judgment). Run-scoped signals
|
||||||
|
# handoff + completeness sentinel + fail-closed judge + dispatcher
|
||||||
|
# ERROR contract (mute/ERROR judge never carried into templating).
|
||||||
|
# Body text unmoved — seo-data.test.sh fetch-wiring locks survive.
|
||||||
|
has "agents/seo-analyzer.md" 'MODE: collect'
|
||||||
|
has "agents/seo-analyzer.md" 'MODE: judge'
|
||||||
|
has "agents/seo-analyzer.md" 'MODE: template'
|
||||||
|
has "agents/seo-analyzer.md" 'COLLECTION COMPLETE'
|
||||||
|
has "agents/geo-analyzer.md" 'MODE: collect'
|
||||||
|
has "agents/geo-analyzer.md" 'MODE: judge'
|
||||||
|
has "agents/geo-analyzer.md" 'MODE: template'
|
||||||
|
has "agents/geo-analyzer.md" 'COLLECTION COMPLETE'
|
||||||
|
has "skills/seo/SKILL.md" 'MODE: collect'
|
||||||
|
has "skills/seo/SKILL.md" 'seo-analyzer", model="sonnet"'
|
||||||
|
has "skills/seo/SKILL.md" 'never re-derive a score'
|
||||||
|
has "skills/seo/SKILL.md" 'DISPATCHER ERROR CONTRACT'
|
||||||
|
has "skills/geo/SKILL.md" 'MODE: collect'
|
||||||
|
has "skills/geo/SKILL.md" 'geo-analyzer", model="sonnet"'
|
||||||
|
has "skills/geo/SKILL.md" 'ERROR CONTRACT'
|
||||||
|
has "skills/geo/SKILL.md" 'never re-derive a score'
|
||||||
|
has "agents/handover-doc-writer.md" 'SYNTH REPORT'
|
||||||
|
|
||||||
printf 'model-routing census: %d pass, %d fail\n' "$pass" "$fail"
|
printf 'model-routing census: %d pass, %d fail\n' "$pass" "$fail"
|
||||||
[ "$fail" -eq 0 ]
|
[ "$fail" -eq 0 ]
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# lib/tests/plan-challenger.test.sh — structure lock: the plan-challenger agent,
|
||||||
|
# the reusable lib/challenge-plan.md phase, and every reflection orchestrator that
|
||||||
|
# wires it (3-way adversarial plan challenge, BDR-066). STATIC only — the agent's
|
||||||
|
# adversarial behavior needs a live model (manual smoke), not a CI gate.
|
||||||
|
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; }
|
||||||
|
fm_lacks() { if awk 'NR<=10' "$R/$1" | grep -qF "$2"; then ko "$1 frontmatter must NOT contain: $2"; else ok; fi; }
|
||||||
|
|
||||||
|
A="agents/plan-challenger.md"
|
||||||
|
L="lib/challenge-plan.md"
|
||||||
|
|
||||||
|
# 1) agent shape
|
||||||
|
has "$A" "name: plan-challenger"
|
||||||
|
has "$A" "tools: Read, Grep, Glob, Bash"
|
||||||
|
fm_lacks "$A" "model: sonnet" # BDR-066: audit judgment → NOT sonnet-pinned
|
||||||
|
has "$A" "CHALLENGE — LENS:" # load-bearing verdict grammar
|
||||||
|
has "$A" "VERDICT: SOLID | CONCERNS(n) | FATAL(n)"
|
||||||
|
has "$A" "correctness"
|
||||||
|
has "$A" "robustness"
|
||||||
|
has "$A" "simplicity"
|
||||||
|
has "$A" "Report-only"
|
||||||
|
|
||||||
|
# 2) reusable phase — the mechanism lives here (one canonical include)
|
||||||
|
has "$L" 'subagent_type="plan-challenger"'
|
||||||
|
has "$L" "BDR-066" # challengers on the big model
|
||||||
|
has "$L" "a mute verifier is NEVER a PASS" # fail-safe (never fail open)
|
||||||
|
has "$L" "Severity-driven" # any single-lens BLOCKER = must-address
|
||||||
|
has "$L" "RE-THINK" # findings re-plan the aspect, not just noted
|
||||||
|
has "$L" "correctness | robustness | simplicity"
|
||||||
|
has "$L" "CHALLENGE SUMMARY"
|
||||||
|
has "$L" "build-plan" # the three KINDs
|
||||||
|
has "$L" "proposals"
|
||||||
|
has "$L" "fix-bundle"
|
||||||
|
|
||||||
|
# 3) every reflection orchestrator wires the phase + carries a challenge summary
|
||||||
|
# (hotfix wires it under a logic-only guard — STEP 1.8)
|
||||||
|
for s in ship-feature init-project feat bugfix hotfix onboard audit-delta code-clean seo geo harden web-validate; do
|
||||||
|
has "skills/$s/SKILL.md" "lib/challenge-plan.md"
|
||||||
|
has "skills/$s/SKILL.md" "CHALLENGE SUMMARY"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf 'plan-challenge structure lock: %d pass, %d fail\n' "$pass" "$fail"
|
||||||
|
[ "$fail" -eq 0 ]
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# lib/tests/profile-set-managed.test.sh — `set` symmetry on managed
|
||||||
|
# externals + MCPs, gstack on-demand, external from-source (BDR-079).
|
||||||
|
# Hermetic: fixture repo via *_REPO_OVERRIDE + fake `claude` on PATH.
|
||||||
|
set -u
|
||||||
|
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
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; }
|
||||||
|
|
||||||
|
FX="$(mktemp -d)"; trap 'rm -rf "$FX"' EXIT
|
||||||
|
mkdir -p "$FX/skills" "$FX/skills-disabled" "$FX/lib/profiles" "$FX/bin" \
|
||||||
|
"$FX/skills-external/emil-design-eng" "$FX/skills-external/other-ext"
|
||||||
|
for g in gs-a gs-b gs-c; do
|
||||||
|
mkdir -p "$FX/skills-external/gstack/$g"
|
||||||
|
touch "$FX/skills-external/gstack/$g/SKILL.md"
|
||||||
|
done
|
||||||
|
cp "$ROOT/lib/profile.sh" "$ROOT/lib/toggle-external.sh" "$FX/lib/"
|
||||||
|
printf 'MAGIC_API_KEY=test-secret-000\n' > "$FX/.env"
|
||||||
|
|
||||||
|
# Non-managed external, enabled from the start — must never be touched.
|
||||||
|
ln -s "$FX/skills-external/other-ext" "$FX/skills/other-ext"
|
||||||
|
|
||||||
|
cat > "$FX/lib/profiles/designish.profile" <<'EOF'
|
||||||
|
gs-a
|
||||||
|
gs-b
|
||||||
|
emil-design-eng external
|
||||||
|
magic mcp
|
||||||
|
EOF
|
||||||
|
cat > "$FX/lib/profiles/backendish.profile" <<'EOF'
|
||||||
|
gs-c
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Fake claude: logs every call; keeps MCP registry state in a flat file.
|
||||||
|
cat > "$FX/bin/claude" <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
FX="$FX"
|
||||||
|
echo "\$*" >> "\$FX/claude-calls.log"
|
||||||
|
case "\$1 \${2:-}" in
|
||||||
|
"mcp list") cat "\$FX/mcp-state" 2>/dev/null ;;
|
||||||
|
"mcp add") echo "magic: stub" > "\$FX/mcp-state" ;;
|
||||||
|
"mcp remove") : > "\$FX/mcp-state" ;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
chmod +x "$FX/bin/claude"
|
||||||
|
|
||||||
|
run() { PATH="$FX/bin:$PATH" PROFILE_REPO_OVERRIDE="$FX" \
|
||||||
|
TOGGLE_EXTERNAL_REPO_OVERRIDE="$FX" bash "$FX/lib/profile.sh" "$@"; }
|
||||||
|
|
||||||
|
# --- set designish: gstack on-demand + external from-source + magic on ---
|
||||||
|
run set designish >/dev/null 2>&1
|
||||||
|
check T1-gsa-on "$([ -e "$FX/skills/gs-a" ] && echo on || echo off)" on
|
||||||
|
check T2-gsb-on "$([ -e "$FX/skills/gs-b" ] && echo on || echo off)" on
|
||||||
|
check T3-gsc-off "$([ -e "$FX/skills/gs-c" ] && echo on || echo off)" off
|
||||||
|
check T4-emil-src "$([ -L "$FX/skills/emil-design-eng" ] && echo on || echo off)" on
|
||||||
|
check T5-magic-on "$(grep -c '^magic:' "$FX/mcp-state" 2>/dev/null)" 1
|
||||||
|
check T6-add-call "$(grep -c '^mcp add magic' "$FX/claude-calls.log")" 1
|
||||||
|
|
||||||
|
# --- set backendish: managed leftovers parked/unregistered ---
|
||||||
|
run set backendish >/dev/null 2>&1
|
||||||
|
check T7-gsc-on "$([ -e "$FX/skills/gs-c" ] && echo on || echo off)" on
|
||||||
|
check T8-gsa-park "$([ -e "$FX/skills-disabled/gstack__gs-a" ] && echo p || echo n)" p
|
||||||
|
check T9-emil-off "$([ -e "$FX/skills/emil-design-eng" ] && echo on || echo off)" off
|
||||||
|
check T10-emil-park "$([ -e "$FX/skills-disabled/emil-design-eng" ] && echo p || echo n)" p
|
||||||
|
check T11-magic-off "$(grep -c '^magic:' "$FX/mcp-state" 2>/dev/null || true)" 0
|
||||||
|
check T12-rm-call "$(grep -c '^mcp remove magic' "$FX/claude-calls.log")" 1
|
||||||
|
check T13-other-untouched "$([ -e "$FX/skills/other-ext" ] && echo on || echo off)" on
|
||||||
|
|
||||||
|
# --- back to designish: parked external restored (not re-sourced) ---
|
||||||
|
run set designish >/dev/null 2>&1
|
||||||
|
check T14-emil-back "$([ -e "$FX/skills/emil-design-eng" ] && echo on || echo off)" on
|
||||||
|
check T15-park-gone "$([ -e "$FX/skills-disabled/emil-design-eng" ] && echo p || echo n)" n
|
||||||
|
check T16-magic-back "$(grep -c '^magic:' "$FX/mcp-state" 2>/dev/null)" 1
|
||||||
|
|
||||||
|
printf 'PASS=%s FAIL=%s\n' "$pass" "$fail"; [ "$fail" -eq 0 ]
|
||||||
+7
-11
@@ -250,7 +250,7 @@
|
|||||||
"disableBypassPermissionsMode": "disable",
|
"disableBypassPermissionsMode": "disable",
|
||||||
"additionalDirectories": []
|
"additionalDirectories": []
|
||||||
},
|
},
|
||||||
"model": "opus[1m]",
|
"model": "claude-fable-5[1m]",
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"SessionStart": [
|
"SessionStart": [
|
||||||
{
|
{
|
||||||
@@ -271,16 +271,6 @@
|
|||||||
"command": "bash ~/.claude/hooks/rtk-rewrite.sh"
|
"command": "bash ~/.claude/hooks/rtk-rewrite.sh"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
{
|
|
||||||
"matcher": "Edit|Write|MultiEdit",
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"type": "command",
|
|
||||||
"command": "bash ~/.claude/hooks/config-protection.sh",
|
|
||||||
"timeout": 5
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"UserPromptSubmit": [
|
"UserPromptSubmit": [
|
||||||
@@ -291,6 +281,12 @@
|
|||||||
"command": "bash ~/.claude/hooks/design-toolchain-reminder.sh",
|
"command": "bash ~/.claude/hooks/design-toolchain-reminder.sh",
|
||||||
"timeout": 5,
|
"timeout": 5,
|
||||||
"statusMessage": "Checking design signals..."
|
"statusMessage": "Checking design signals..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "command",
|
||||||
|
"command": "bash ~/.claude/hooks/ctx7-reminder.sh",
|
||||||
|
"timeout": 5,
|
||||||
|
"statusMessage": "Checking fast-libs..."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -166,10 +166,31 @@ Append to `.claude/audits/AUDIT-DELTA.md` (create if absent), append-only:
|
|||||||
|
|
||||||
Then show the user the same compact table inline.
|
Then show the user the same compact table inline.
|
||||||
|
|
||||||
|
### 3b-bis. CHALLENGE THE PROPOSALS (before the gate)
|
||||||
|
|
||||||
|
This axis' findings + proposed fixes are a proposal set worth attacking before
|
||||||
|
the human gate. Persist THIS axis' finding list (not the whole append-only
|
||||||
|
report) to `.claude/tasks/plans/<date>-<axis>-<HHMM>.md`, then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` =
|
||||||
|
`proposals`, `SCOPE` = this axis' STEP 1 audit set, `CONSTRAINTS` = the axis
|
||||||
|
spec + the project CLAUDE.md norms already loaded. Three blind challengers ask
|
||||||
|
whether these are the RIGHT findings/priorities and what the audit under-rated;
|
||||||
|
the main loop RE-THINKS every aspect a BLOCKER lands (a named change to the
|
||||||
|
finding set, or `[deferred <date>]`) and re-challenges once if it materially
|
||||||
|
changed. Feed the REVISED findings + a CHALLENGE SUMMARY into 3c.
|
||||||
|
|
||||||
### 3c. APPROVAL GATE ★ MANDATORY STOP
|
### 3c. APPROVAL GATE ★ MANDATORY STOP
|
||||||
|
|
||||||
|
Show the CHALLENGE SUMMARY (from 3b-bis) with the 3b findings table, then
|
||||||
AskUserQuestion: **fix all / pick which / none**.
|
AskUserQuestion: **fix all / pick which / none**.
|
||||||
|
|
||||||
|
```
|
||||||
|
CHALLENGE SUMMARY (3b-bis — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named finding-set change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
|
```
|
||||||
|
|
||||||
- "Fix what you find" said **in the invocation** does NOT skip this gate:
|
- "Fix what you find" said **in the invocation** does NOT skip this gate:
|
||||||
nobody can approve findings that did not exist yet. The gate is about
|
nobody can approve findings that did not exist yet. The gate is about
|
||||||
*these specific findings*.
|
*these specific findings*.
|
||||||
|
|||||||
+23
-3
@@ -117,6 +117,19 @@ RISK: <low/medium — what could go wrong>
|
|||||||
- If the fix is significant (>10 lines, multiple files,
|
- If the fix is significant (>10 lines, multiple files,
|
||||||
behavior change): wait for user approval.
|
behavior change): wait for user approval.
|
||||||
|
|
||||||
|
## STEP 3b — CHALLENGE THE FIX PLAN (before the contract)
|
||||||
|
Unless the fix is the trivial 1-2 line case STEP 3 already fast-paths, the
|
||||||
|
DIAGNOSIS + FIX PLAN is a reflection worth attacking before it hardens into a
|
||||||
|
contract. Persist it to `.claude/tasks/plans/<date>-<slug>-<HHMM>.md`, then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` = `build-plan`,
|
||||||
|
`SCOPE` = the FIX PLAN files, `CONSTRAINTS` = the STEP 2 in-force BDR/LRN/BLK
|
||||||
|
dispositions. Three blind challengers attack it (correctness = is the root cause
|
||||||
|
right; robustness = blast radius / regressions; simplicity = is the fix minimal);
|
||||||
|
RE-THINK every aspect a BLOCKER lands, re-challenge once if the plan materially
|
||||||
|
changed. STEP 3.5 writes the contract from the REVISED plan. Print a CHALLENGE SUMMARY
|
||||||
|
(BLOCKERs addressed / deferred / lenses returned), folding any deferred BLOCKER into
|
||||||
|
the STEP 3 approval gate.
|
||||||
|
|
||||||
## STEP 3.5 — CONTRACT
|
## STEP 3.5 — CONTRACT
|
||||||
|
|
||||||
Run `$HOME/.claude/lib/contract-interview.md` (main loop). The DIAGNOSIS
|
Run `$HOME/.claude/lib/contract-interview.md` (main loop). The DIAGNOSIS
|
||||||
@@ -212,9 +225,16 @@ Parse the `BUGFIX-EXEC REPORT`:
|
|||||||
|
|
||||||
## STEP 7 — DOC SYNC (automatic)
|
## STEP 7 — DOC SYNC (automatic)
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/doc-syncer.md`.
|
Dispatch the doc pipeline (BDR-077 — audit judgment on opus, patch on the
|
||||||
Execute in automatic mode:
|
sonnet pin, gate HERE):
|
||||||
`auto-mode scope: <list of files modified during this session>`
|
1. `Agent(subagent_type="doc-syncer", model="opus")` — `MODE: audit` +
|
||||||
|
`auto-mode scope: <list of files modified during this session>`.
|
||||||
|
2. Silence (NONE) → done. `[MINOR]` PATCH PLAN → re-dispatch
|
||||||
|
`Agent(subagent_type="doc-syncer")` with `MODE: patch` + the plan
|
||||||
|
verbatim (no gate — auto behavior preserved; a `SHAPE ESCALATION` in
|
||||||
|
its report comes back here, gated as SIGNIFICANT).
|
||||||
|
3. SIGNIFICANT → gate here (`Apply? yes / no / select`), then
|
||||||
|
`MODE: patch` with the approved subset.
|
||||||
|
|
||||||
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
**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
|
ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never
|
||||||
|
|||||||
@@ -29,9 +29,11 @@ Load and follow strictly:
|
|||||||
- $HOME/.claude/agents/client-handover-writer.md
|
- $HOME/.claude/agents/client-handover-writer.md
|
||||||
|
|
||||||
Execute the CLIENT HANDOVER WRITER agent on this project. It runs the
|
Execute the CLIENT HANDOVER WRITER agent on this project. It runs the
|
||||||
audit/fix/gate pipeline INLINE on the big session model (gated above), then
|
audit/fix/gate pipeline INLINE on the big session model (gated above), its
|
||||||
delegates the client deliverable (Markdown + branded HTML + PDF) to the
|
skill-runner children dispatched `model: "fable"`, then delegates the
|
||||||
sonnet-pinned `handover-doc-writer` subagent (BDR-066).
|
client deliverable to the two-mode `handover-doc-writer` subagent —
|
||||||
|
synthesize on opus, render (Markdown + branded HTML + PDF) on the sonnet
|
||||||
|
pin (BDR-077).
|
||||||
|
|
||||||
The agent runs a **ship-and-handover pipeline** with explicit gates:
|
The agent runs a **ship-and-handover pipeline** with explicit gates:
|
||||||
|
|
||||||
|
|||||||
@@ -119,11 +119,29 @@ TOTALS: <N blocking, N warn, N info>
|
|||||||
|
|
||||||
If no issues found: report clean state and stop.
|
If no issues found: report clean state and stop.
|
||||||
|
|
||||||
|
## STEP 3b — CHALLENGE THE SCOPE (before approval)
|
||||||
|
The STEP 3 report is the proposed cleanup scope — worth attacking before the
|
||||||
|
human approves it. It is still inline, so FIRST persist it to
|
||||||
|
`.claude/tasks/plans/<date>-<slug>-<HHMM>.md` (STEP 3 report format, one item
|
||||||
|
per line), then run `$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that
|
||||||
|
file, `KIND` = `proposals`, `SCOPE` = the scanned target ($ARGUMENTS or repo
|
||||||
|
root), `CONSTRAINTS` = the STEP 1 project norms + the iron law (zero behavior
|
||||||
|
change). Three blind challengers ask whether these are the RIGHT items and what
|
||||||
|
the scan under- or over-scoped; the main loop RE-THINKS every aspect a BLOCKER
|
||||||
|
lands (a named scope change re-written into the report, or `[deferred <date>]`)
|
||||||
|
and re-challenges once if the scope materially changed. Feed the REVISED scope +
|
||||||
|
a CHALLENGE SUMMARY into STEP 4. Advisory — the human still approves per item.
|
||||||
|
|
||||||
## STEP 4 — VALIDATION GATE (interactive)
|
## STEP 4 — VALIDATION GATE (interactive)
|
||||||
|
|
||||||
Present the report from STEP 3. Then ask:
|
Present the report from STEP 3 with the STEP 3b CHALLENGE SUMMARY. Then ask:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
CHALLENGE SUMMARY (STEP 3b — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named scope change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
|
|
||||||
AskUserQuestion:
|
AskUserQuestion:
|
||||||
Approve which items for execution? (all / <item numbers> / clarify <item>)
|
Approve which items for execution? (all / <item numbers> / clarify <item>)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ allowed-tools:
|
|||||||
|
|
||||||
# /commit-change — propose → confirm → apply dispatcher
|
# /commit-change — propose → confirm → apply dispatcher
|
||||||
|
|
||||||
Grouping and committing both run on the sonnet-pinned `commit-changer`
|
Grouping (propose, `model="opus"` override — judgment) and committing
|
||||||
|
(apply, sonnet pin — mechanical) both run on the dispatched `commit-changer`
|
||||||
subagent (dispatch makes the pin effective). No inline reflection happens
|
subagent (dispatch makes the pin effective). No inline reflection happens
|
||||||
in this dispatcher to protect, so there is no model gate. This dispatcher
|
in this dispatcher to protect, so there is no model gate. This dispatcher
|
||||||
owns the two approval gates that used to live inside the subagent:
|
owns the two approval gates that used to live inside the subagent:
|
||||||
@@ -52,11 +53,15 @@ protected branch.
|
|||||||
## STEP 1 — Propose
|
## STEP 1 — Propose
|
||||||
|
|
||||||
```
|
```
|
||||||
Agent(subagent_type="commit-changer")
|
Agent(subagent_type="commit-changer", model="opus")
|
||||||
prompt: "MODE: propose
|
prompt: "MODE: propose
|
||||||
$ARGUMENTS"
|
$ARGUMENTS"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
(`model="opus"` — BDR-077: propose = narrative reconstruction + capitalize
|
||||||
|
routing, judgment tier; the call-site override takes precedence over the
|
||||||
|
sonnet frontmatter pin. Apply, STEP 4, stays on the pin.)
|
||||||
|
|
||||||
Read the returned `COMMIT PLAN` + `EDGE CASES` + `CAPITALIZE CANDIDATES`,
|
Read the returned `COMMIT PLAN` + `EDGE CASES` + `CAPITALIZE CANDIDATES`,
|
||||||
terminated by `READY TO APPLY — awaiting dispatcher confirmation`.
|
terminated by `READY TO APPLY — awaiting dispatcher confirmation`.
|
||||||
|
|
||||||
@@ -77,8 +82,9 @@ AskUserQuestion:
|
|||||||
uncommitted for a later run.
|
uncommitted for a later run.
|
||||||
- `edit <n>` → re-dispatch `commit-changer` with `MODE: propose` and the
|
- `edit <n>` → re-dispatch `commit-changer` with `MODE: propose` and the
|
||||||
user's correction for step N folded into the prompt, so all grouping /
|
user's correction for step N folded into the prompt, so all grouping /
|
||||||
message judgment stays on the sonnet subagent (never redrawn inline on
|
message judgment stays on the dispatched propose mode (`model="opus"`,
|
||||||
the session model); show the redrawn plan and re-ask.
|
BDR-077 — never redrawn inline on the session model); show the redrawn
|
||||||
|
plan and re-ask.
|
||||||
- `skip` → exit cleanly, no commits created, no `MODE: apply` dispatch.
|
- `skip` → exit cleanly, no commits created, no `MODE: apply` dispatch.
|
||||||
Note: if the propose run created a `chore/*` branch (gitflow aiguillage
|
Note: if the propose run created a `chore/*` branch (gitflow aiguillage
|
||||||
off a protected base), that branch stays checked out with the work
|
off a protected base), that branch stays checked out with the work
|
||||||
|
|||||||
+23
-8
@@ -18,13 +18,28 @@ allowed-tools:
|
|||||||
- Agent
|
- Agent
|
||||||
---
|
---
|
||||||
|
|
||||||
Dispatch the doc-syncer as a subagent so its `model: sonnet` pin takes
|
Run the two-mode doc pipeline (BDR-077 — audit judgment on opus, patch on
|
||||||
effect (doc-sync = execution, not the session's big model):
|
the sonnet pin, the validation gate in THIS loop; a dispatched agent cannot
|
||||||
|
hold a gate):
|
||||||
|
|
||||||
Agent(subagent_type="doc-syncer")
|
1. AUDIT — dispatch:
|
||||||
prompt: "Audit + sync public docs for this project. Context from the user:
|
`Agent(subagent_type="doc-syncer", model="opus")`
|
||||||
$ARGUMENTS. Report PATCHED_FILES and a summary — do NOT commit."
|
prompt: "MODE: audit. Audit public docs for this project. Context from
|
||||||
|
the user: $ARGUMENTS. Emit the DOC SYNC REPORT + PATCH PLAN — no writes."
|
||||||
|
|
||||||
Then commit the patched docs from THIS loop per `$HOME/.claude/lib/doc-commit.md`
|
2. GATE — present the report and run the DOC SYNC — VALIDATION GATE from
|
||||||
(surgical: only doc-syncer's PATCHED_FILES, never `.claude/`/`CLAUDE.md`,
|
the agent's DISPATCHER PROTOCOL (AUTO yes/select/cancel; HUMAN, CREATE,
|
||||||
no-op if nothing patched).
|
CLEAN per-item; README CREATE has no skip). Wait for explicit approval.
|
||||||
|
`DOC SYNC: all docs current` → stop here.
|
||||||
|
|
||||||
|
3. PATCH — re-dispatch:
|
||||||
|
`Agent(subagent_type="doc-syncer")` (sonnet pin)
|
||||||
|
prompt: "MODE: patch." + the APPROVED PATCH PLAN verbatim (approved item
|
||||||
|
lines + rendered drafts for approved CREATE items). A `SHAPE ESCALATION`
|
||||||
|
in its report → re-gate the named set here, then re-dispatch patch with
|
||||||
|
the kept subset.
|
||||||
|
|
||||||
|
4. COMMIT — from THIS loop per `$HOME/.claude/lib/doc-commit.md` (surgical:
|
||||||
|
only the report's `PATCHED_FILES`, summary composed from its
|
||||||
|
`CHANGE SUMMARY` block, never `.claude/`/`CLAUDE.md`, no-op if nothing
|
||||||
|
patched).
|
||||||
|
|||||||
+22
-4
@@ -117,6 +117,17 @@ PLAN:
|
|||||||
If the approach is ambiguous: ask the user ONE focused question BEFORE
|
If the approach is ambiguous: ask the user ONE focused question BEFORE
|
||||||
dispatching — never after (the executor cannot relay questions).
|
dispatching — never after (the executor cannot relay questions).
|
||||||
|
|
||||||
|
## STEP 1b — CHALLENGE THE PLAN (before branching)
|
||||||
|
The STEP 1 plan is a reflection worth attacking before a branch is spent on it.
|
||||||
|
Persist it to `.claude/tasks/plans/<date>-<slug>-<HHMM>.md`, then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` = `build-plan`,
|
||||||
|
`SCOPE` = the STEP 1 files, `CONSTRAINTS` = the STEP 0.6 in-force BDR/LRN dispositions.
|
||||||
|
Three blind challengers attack it; RE-THINK every aspect a BLOCKER lands (a named
|
||||||
|
plan change, or `[deferred]`), re-challenge once if the plan materially changed. The
|
||||||
|
STEP 3 executor receives the REVISED plan. Before dispatch, print a CHALLENGE SUMMARY
|
||||||
|
(BLOCKERs addressed / deferred / lenses returned), surfacing any deferred BLOCKER via
|
||||||
|
STEP 1's one-question gate.
|
||||||
|
|
||||||
## STEP 2 — BRANCH
|
## STEP 2 — BRANCH
|
||||||
|
|
||||||
**Gitflow aiguillage (before dispatch):** follow `$HOME/.claude/lib/gitflow-aiguillage.md`
|
**Gitflow aiguillage (before dispatch):** follow `$HOME/.claude/lib/gitflow-aiguillage.md`
|
||||||
@@ -175,7 +186,7 @@ feat(<scope>): <what was added>
|
|||||||
If the feature touched multiple concerns (e.g., feature + config +
|
If the feature touched multiple concerns (e.g., feature + config +
|
||||||
test), consider splitting into 2-3 atomic commits grouped by logical
|
test), consider splitting into 2-3 atomic commits grouped by logical
|
||||||
unit — or run `/commit-change` on the pending work (it dispatches the
|
unit — or run `/commit-change` on the pending work (it dispatches the
|
||||||
sonnet commit-changer; never inline-load the bare agent, it is now a
|
commit-changer (propose opus / apply sonnet, BDR-077); never inline-load the bare agent, it is now a
|
||||||
propose/apply executor).
|
propose/apply executor).
|
||||||
|
|
||||||
Print summary:
|
Print summary:
|
||||||
@@ -189,9 +200,16 @@ VERIFIED : <what was checked>
|
|||||||
|
|
||||||
## STEP 6 — DOC SYNC (automatic)
|
## STEP 6 — DOC SYNC (automatic)
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/doc-syncer.md`.
|
Dispatch the doc pipeline (BDR-077 — audit judgment on opus, patch on the
|
||||||
Execute in automatic mode:
|
sonnet pin, gate HERE):
|
||||||
`auto-mode scope: <list of files modified during this session>`
|
1. `Agent(subagent_type="doc-syncer", model="opus")` — `MODE: audit` +
|
||||||
|
`auto-mode scope: <list of files modified during this session>`.
|
||||||
|
2. Silence (NONE) → done. `[MINOR]` PATCH PLAN → re-dispatch
|
||||||
|
`Agent(subagent_type="doc-syncer")` with `MODE: patch` + the plan
|
||||||
|
verbatim (no gate — auto behavior preserved; a `SHAPE ESCALATION` in
|
||||||
|
its report comes back here, gated as SIGNIFICANT).
|
||||||
|
3. SIGNIFICANT → gate here (`Apply? yes / no / select`), then
|
||||||
|
`MODE: patch` with the approved subset.
|
||||||
|
|
||||||
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
**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
|
ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never
|
||||||
|
|||||||
+60
-17
@@ -36,27 +36,65 @@ terminated by `READY TO APPLY — awaiting dispatcher confirmation`, and this
|
|||||||
skill applies it. Applying from here (one dispatch level, no nested spawn)
|
skill applies it. Applying from here (one dispatch level, no nested spawn)
|
||||||
is what makes fixes land on any Claude Code version.
|
is what makes fixes land on any Claude Code version.
|
||||||
|
|
||||||
## STEP 1 — Dispatch geo-analyzer (audit + bundle)
|
## STEP 1 — Run the geo pipeline (collect → judge → template, BDR-077)
|
||||||
|
|
||||||
|
Gather depth + business context HERE first (ask the user in this loop if
|
||||||
|
needed — a dispatched agent cannot ask). Mint `RUNID=$(date +%s)-geo`.
|
||||||
|
Pass the same CONTEXT block ($ARGUMENTS + gathered context) VERBATIM to
|
||||||
|
every phase (LRN-126). Clean `.audit/geo-signals-<RUNID>.md` after apply.
|
||||||
|
|
||||||
|
**A — collect (sonnet):**
|
||||||
|
```
|
||||||
|
Agent(subagent_type="geo-analyzer", model="sonnet")
|
||||||
|
prompt: "MODE: collect
|
||||||
|
RUNID: <RUNID>
|
||||||
|
Dispatched from /geo. Context: <CONTEXT>
|
||||||
|
Execute STEP 0-5 per your spec, write the signals file + COLLECTION
|
||||||
|
COMPLETE sentinel, emit the COLLECT REPORT, stop."
|
||||||
|
```
|
||||||
|
|
||||||
|
**B — judge (opus pin, no override):**
|
||||||
```
|
```
|
||||||
Agent(subagent_type="geo-analyzer")
|
Agent(subagent_type="geo-analyzer")
|
||||||
prompt: """
|
prompt: "MODE: judge
|
||||||
Dispatched from /geo. Execute your full spec at
|
RUNID: <RUNID>
|
||||||
~/.claude/agents/geo-analyzer.md (STEP 0 onward — gather depth + business
|
Context: <CONTEXT>
|
||||||
context as needed; if you must ask the user, ask and I relay).
|
Load .audit/geo-signals-<RUNID>.md (fail closed per your spec), run STEP
|
||||||
|
6-12, report scoring + findings + action plan + triage batches."
|
||||||
Produce your report:
|
|
||||||
- If .claude/audits/SEO.md already exists → merge findings into its
|
|
||||||
§7 — Optimisation GEO / IA.
|
|
||||||
- Else write .claude/audits/GEO.md.
|
|
||||||
|
|
||||||
Then emit the `## FIX BUNDLE` (STEP 13) terminated by the verbatim
|
|
||||||
`READY TO APPLY — awaiting dispatcher confirmation` sentinel. Do NOT apply
|
|
||||||
any fix and do NOT dispatch any sub-agent — /geo applies your bundle.
|
|
||||||
|
|
||||||
$ARGUMENTS
|
|
||||||
"""
|
|
||||||
```
|
```
|
||||||
|
**ERROR CONTRACT:** `GEO JUDGE — VERDICT: ERROR(…)` or a mute judge →
|
||||||
|
STOP: no template, no apply. Surface verbatim, retry ONCE with a fresh
|
||||||
|
collect+judge, then escalate. Never carry a mute/ERROR judge into
|
||||||
|
templating.
|
||||||
|
|
||||||
|
**C — template (sonnet):**
|
||||||
|
```
|
||||||
|
Agent(subagent_type="geo-analyzer", model="sonnet")
|
||||||
|
prompt: "MODE: template
|
||||||
|
Context: <CONTEXT>
|
||||||
|
JUDGE REPORT (verbatim, ground truth — never re-derive a score):
|
||||||
|
<the judge report>
|
||||||
|
Run STEP 13-15. Produce your report: if .claude/audits/SEO.md already
|
||||||
|
exists → merge findings into its §7 — Optimisation GEO / IA; else write
|
||||||
|
.claude/audits/GEO.md. Then emit the `## FIX BUNDLE` terminated by the
|
||||||
|
verbatim `READY TO APPLY — awaiting dispatcher confirmation` sentinel.
|
||||||
|
Do NOT apply any fix and do NOT dispatch any sub-agent — /geo applies
|
||||||
|
your bundle."
|
||||||
|
```
|
||||||
|
|
||||||
|
## STEP 1b — CHALLENGE THE FIX BUNDLE (advisory, before apply)
|
||||||
|
The analyzer returned a `## FIX BUNDLE` — worth attacking before any edit lands.
|
||||||
|
**Skip if intervention mode = conservative** (nothing is applied). Else persist the
|
||||||
|
bundle verbatim to `.claude/tasks/plans/<date>-<slug>-<HHMM>.md`, then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` = `fix-bundle`,
|
||||||
|
`SCOPE` = the target site files the items touch, `CONSTRAINTS` = the geo-analyzer
|
||||||
|
file-ownership (robots.txt, llms.txt, JSON-LD, content shape) + the shared-file edit
|
||||||
|
discipline each item carries + intervention mode. Three blind challengers ask, per item:
|
||||||
|
will it ACHIEVE its goal / could it BREAK or regress the page / is a simpler (or no) fix
|
||||||
|
better. This main loop RE-THINKS every aspect a BLOCKER lands (a named bundle change, or
|
||||||
|
`[deferred <date>]`) and re-challenges once if the bundle materially changed. Advisory —
|
||||||
|
it sits BEFORE (never replaces) the STEP 2 GATED approval; carry its CHALLENGE SUMMARY
|
||||||
|
into that gate.
|
||||||
|
|
||||||
## STEP 2 — Apply the fix bundle (from THIS main loop, at L1)
|
## STEP 2 — Apply the fix bundle (from THIS main loop, at L1)
|
||||||
|
|
||||||
@@ -90,6 +128,11 @@ Present every GATED item (G5.x) in ONE gate:
|
|||||||
```
|
```
|
||||||
GEO — gated content-shape changes need approval (visible):
|
GEO — gated content-shape changes need approval (visible):
|
||||||
G5.1 <change> — impact: <visible change>
|
G5.1 <change> — impact: <visible change>
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 1b — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named bundle change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
Approve all / select (ids) / skip all?
|
Approve all / select (ids) / skip all?
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -518,6 +518,21 @@ Extract the score and critical-alert count from `.claude/audits/HARDEN.md` for t
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## STEP 2b — CHALLENGE THE FIX BUNDLE (MODE=fix only, advisory)
|
||||||
|
Skip if MODE=audit (no bundle exists). Else, before the STEP 3 gate, harden the bundle:
|
||||||
|
extract the `## 8. Fix bundle` section from HARDEN.md to
|
||||||
|
`.claude/tasks/plans/<date>-<slug>-<HHMM>.md` (a clean, blind-judgeable artifact), then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` = `fix-bundle`,
|
||||||
|
`SCOPE` = the config/target files each patch touches (.htaccess, next.config.js, _headers…),
|
||||||
|
`CONSTRAINTS` = the STEP 1 strict scope + framework-native mechanism rule (no `.htaccess`
|
||||||
|
on Next/Astro) + the severity guide. Three blind challengers ask, per patch: will it ACHIEVE
|
||||||
|
the hardening goal / could it BREAK the site (over-broad CSP, redirect loop) / is a simpler
|
||||||
|
fix better. This main loop RE-THINKS every aspect a BLOCKER lands (a named bundle change, or
|
||||||
|
`[deferred <date>]`) and re-challenges once if the bundle materially changed. Advisory — it
|
||||||
|
sits BEFORE (never replaces) the STEP 3 confirmation; carry its CHALLENGE SUMMARY into that gate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STEP 3 — Apply fixes (MODE=fix only)
|
## STEP 3 — Apply fixes (MODE=fix only)
|
||||||
|
|
||||||
Skip this step if MODE=audit.
|
Skip this step if MODE=audit.
|
||||||
@@ -534,6 +549,11 @@ If MODE=fix and `.claude/audits/HARDEN.md` ends with `READY TO APPLY — awaitin
|
|||||||
- .htaccess (3 fixes : HTTP→HTTPS redirect, HSTS, 404 page)
|
- .htaccess (3 fixes : HTTP→HTTPS redirect, HSTS, 404 page)
|
||||||
- next.config.js (2 fixes : CSP header, X-Frame-Options)
|
- next.config.js (2 fixes : CSP header, X-Frame-Options)
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 2b — 3 lenses) :
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named bundle change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
|
|
||||||
Options :
|
Options :
|
||||||
A) Apply all
|
A) Apply all
|
||||||
B) Review each diff before applying
|
B) Review each diff before applying
|
||||||
|
|||||||
+30
-3
@@ -76,6 +76,26 @@ security gate and the escalation report if a gate fails. No verifier is
|
|||||||
dispatched at hotfix weight — STEP 4's smoke result already verifies these
|
dispatched at hotfix weight — STEP 4's smoke result already verifies these
|
||||||
trivial criteria; the gate hotfix adds is security (STEP 4).
|
trivial criteria; the gate hotfix adds is security (STEP 4).
|
||||||
|
|
||||||
|
## STEP 1.8 — CHALLENGE THE FIX (logic fixes only)
|
||||||
|
GUARD — this is the one place the plan-challenge phase is kept proportionate to
|
||||||
|
hotfix's speed. SKIP entirely for a purely cosmetic fix (CSS value, copy/typo, a
|
||||||
|
broken link): there is nothing for three lenses to bite on, and speed is the
|
||||||
|
point. Run it ONLY when the settled fix touches control flow or behaviour — an
|
||||||
|
off-by-one, a wrong operator/variable, a behaviour-changing config value, or a
|
||||||
|
missing import that alters execution. In doubt → it is probably a `/bugfix`.
|
||||||
|
|
||||||
|
For a logic fix: persist the STEP 1 located fix (root cause + the exact edit) to
|
||||||
|
`.claude/tasks/plans/<date>-<slug>-<HHMM>.md`, then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` =
|
||||||
|
`build-plan`, `SCOPE` = the 1-2 target files, `CONSTRAINTS` = the STEP 1.7
|
||||||
|
contract's acceptance criteria. Three blind challengers attack the fix; the main
|
||||||
|
loop RE-THINKS any aspect a BLOCKER lands (a named change to the fix, or
|
||||||
|
`[deferred]`) and re-challenges once if it materially changed. Print a
|
||||||
|
CHALLENGE SUMMARY (BLOCKERs addressed / deferred / lenses returned). A BLOCKER
|
||||||
|
that shows the fix is wrong or incomplete means this was never
|
||||||
|
a hotfix — escalate to `/bugfix` (its STEP 3b runs the same phase under the full
|
||||||
|
verify+secure loop).
|
||||||
|
|
||||||
## STEP 2 — PRE-FLIGHT
|
## STEP 2 — PRE-FLIGHT
|
||||||
|
|
||||||
**Gitflow aiguillage (before dispatch):** follow `$HOME/.claude/lib/gitflow-aiguillage.md`
|
**Gitflow aiguillage (before dispatch):** follow `$HOME/.claude/lib/gitflow-aiguillage.md`
|
||||||
@@ -154,9 +174,16 @@ Parse the `HOTFIX-EXEC REPORT`:
|
|||||||
|
|
||||||
## STEP 5 — DOC SYNC (automatic)
|
## STEP 5 — DOC SYNC (automatic)
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/doc-syncer.md`.
|
Dispatch the doc pipeline (BDR-077 — audit judgment on opus, patch on the
|
||||||
Execute in automatic mode:
|
sonnet pin, gate HERE):
|
||||||
`auto-mode scope: <list of files modified during this session>`
|
1. `Agent(subagent_type="doc-syncer", model="opus")` — `MODE: audit` +
|
||||||
|
`auto-mode scope: <list of files modified during this session>`.
|
||||||
|
2. Silence (NONE) → done. `[MINOR]` PATCH PLAN → re-dispatch
|
||||||
|
`Agent(subagent_type="doc-syncer")` with `MODE: patch` + the plan
|
||||||
|
verbatim (no gate — auto behavior preserved; a `SHAPE ESCALATION` in
|
||||||
|
its report comes back here, gated as SIGNIFICANT).
|
||||||
|
3. SIGNIFICANT → gate here (`Apply? yes / no / select`), then
|
||||||
|
`MODE: patch` with the approved subset.
|
||||||
|
|
||||||
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
**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
|
ONLY the files doc-syncer patched (its `PATCHED_FILES` output), never `git add -A`, never
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ so the user does not assume Claude has hung.
|
|||||||
---
|
---
|
||||||
|
|
||||||
## STEP 0 — PLUGIN CHECK + AUTO-ACTIVATE
|
## STEP 0 — PLUGIN CHECK + AUTO-ACTIVATE
|
||||||
Load `$HOME/.claude/agents/plugin-advisor.md`. Feed request.
|
Run `$HOME/.claude/lib/plugin-gate.md`. Feed request (dispatch plugin-probe →
|
||||||
|
checkpoint → dispatch plugin-advisor; gates stay in this loop — BDR-077).
|
||||||
- ACTION REQUIRED → show RECOMMENDATIONS block, offer: A) fix plugins B) type "force". STOP.
|
- ACTION REQUIRED → show RECOMMENDATIONS block, offer: A) fix plugins B) type "force". STOP.
|
||||||
- PROPOSED CHANGES exist → show list, ask "Apply? (yes / no / customize)". Apply on confirm.
|
- PROPOSED CHANGES exist → show list, ask "Apply? (yes / no / customize)". Apply on confirm.
|
||||||
- OK → `✅ Plugin check passed — [active plugins] — complexity: <score>%`, continue.
|
- OK → `✅ Plugin check passed — [active plugins] — complexity: <score>%`, continue.
|
||||||
@@ -91,15 +92,31 @@ contract, each tagged `[gated <date>]`. STEP 9's verifier judges against this
|
|||||||
enriched contract.
|
enriched contract.
|
||||||
|
|
||||||
## STEP 5 — SCAFFOLD
|
## STEP 5 — SCAFFOLD
|
||||||
Load `$HOME/.claude/agents/scaffolder.md`. Pass: BRIEF + DESIGN + `~/.claude/templates/project-CLAUDE.md` + `~/.claude/CLAUDE.md`.
|
Dispatch `Agent(subagent_type="scaffolder")` (pin sonnet, effort high —
|
||||||
|
BDR-077 : le design est CLOS au gate #1, le scaffold est de l'exécution,
|
||||||
|
plus jamais inline sur le modèle de session). Pass IN THE PROMPT (LRN-126 —
|
||||||
|
every field the scaffolder consumes crosses the dispatch): BRIEF (verbatim)
|
||||||
|
+ DESIGN (verbatim) + paths `~/.claude/templates/project-CLAUDE.md` +
|
||||||
|
`~/.claude/CLAUDE.md`. A STOP (missing input) comes back as its report —
|
||||||
|
resolve here, re-dispatch. The ~30s liveness pings are THIS loop's job
|
||||||
|
while waiting.
|
||||||
Creates: CLAUDE.md, `.claude/settings.json`, `.claudeignore`, `.gitignore`, `.env.example`, empty entry points. NO README, NO features, NO `.claude/tasks/` or `.claude/memory/` (not bootstrapped by this flow — copy from `~/.claude/templates/memory/` manually if wanted before STEP 10b's memory commit).
|
Creates: CLAUDE.md, `.claude/settings.json`, `.claudeignore`, `.gitignore`, `.env.example`, empty entry points. NO README, NO features, NO `.claude/tasks/` or `.claude/memory/` (not bootstrapped by this flow — copy from `~/.claude/templates/memory/` manually if wanted before STEP 10b's memory commit).
|
||||||
Verify: `git init` + build passes.
|
Verify: `git init` + build passes.
|
||||||
|
|
||||||
## STEP 5b — CREATE README
|
## STEP 5b — CREATE README
|
||||||
Load `$HOME/.claude/agents/doc-syncer.md` (AUTO MODE, scope: full project). README.md missing → its README bootstrap creates it. No stop.
|
Dispatch the doc pipeline (BDR-077):
|
||||||
|
`Agent(subagent_type="doc-syncer", model="opus")`
|
||||||
|
— `MODE: audit` (FULL-AUDIT path, NOT `auto-mode scope:` —
|
||||||
|
auto-mode gates a missing README as SIGNIFICANT; the full audit's STEP 5
|
||||||
|
renders it `[CREATE-AUTO]`, unconditional). README.md missing → the
|
||||||
|
report carries the rendered README draft as `[CREATE-AUTO]`; re-dispatch
|
||||||
|
`Agent(subagent_type="doc-syncer")` (sonnet pin) with `MODE: patch` +
|
||||||
|
that plan to write it. No stop (README bootstrap is unconditional).
|
||||||
|
|
||||||
## STEP 5c — CTX7 PRE-FETCH (if fast-libs detected)
|
## STEP 5c — CTX7 PRE-FETCH (if fast-libs detected)
|
||||||
If `fast-libs` signal was detected in STEP 0 (Next.js, React 18+, Prisma, Supabase, Drizzle, etc.):
|
If `fast-libs` signal was detected in STEP 0 — single source of truth:
|
||||||
|
`bash ~/.claude/lib/fast-libs.sh detect .` (Next.js, React, Prisma,
|
||||||
|
Supabase, Drizzle… — BDR-078):
|
||||||
1. Create `.ctx7-cache/` directory in project root.
|
1. Create `.ctx7-cache/` directory in project root.
|
||||||
2. For each detected fast-lib, fetch core docs:
|
2. For each detected fast-lib, fetch core docs:
|
||||||
```bash
|
```bash
|
||||||
@@ -155,12 +172,27 @@ implemented on a `feature/*` branch off `develop` (STEP 8).
|
|||||||
Invoke `superpowers:writing-plans` with BRIEF + skeleton.
|
Invoke `superpowers:writing-plans` with BRIEF + skeleton.
|
||||||
Granular tasks (2-5 min each), exact file paths, TDD: tests before code.
|
Granular tasks (2-5 min each), exact file paths, TDD: tests before code.
|
||||||
|
|
||||||
|
## STEP 6b — CHALLENGE THE PLAN (before the gate)
|
||||||
|
Before the human sees the implementation plan, harden it. Run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = the plan STEP 6 wrote under
|
||||||
|
`docs/superpowers/plans/`, `KIND` = `build-plan`, `SCOPE` = the skeleton + task file
|
||||||
|
paths, `CONSTRAINTS` = the STEP 4-validated architecture + founding decisions.
|
||||||
|
Three blind challengers (correctness / robustness / simplicity) attack it; the main
|
||||||
|
loop RE-THINKS every aspect a BLOCKER lands (a named plan change, or `[deferred]`),
|
||||||
|
re-challenges once if the plan materially changed, and feeds the REVISED plan + a
|
||||||
|
CHALLENGE SUMMARY into STEP 7. Advisory — the human remains the decider.
|
||||||
|
|
||||||
## STEP 7 — VALIDATION GATE #2 ★ MANDATORY STOP
|
## STEP 7 — VALIDATION GATE #2 ★ MANDATORY STOP
|
||||||
```
|
```
|
||||||
INIT PROJECT — IMPLEMENTATION PLAN
|
INIT PROJECT — IMPLEMENTATION PLAN
|
||||||
SKELETON: ✅ build passes
|
SKELETON: ✅ build passes
|
||||||
FEATURES: <N> → <M> tasks
|
FEATURES: <N> → <M> tasks
|
||||||
<numbered task list with paths>
|
<numbered task list with paths>
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 6b — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named plan change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
Approve and start? (yes / request changes)
|
Approve and start? (yes / request changes)
|
||||||
```
|
```
|
||||||
Changes → back to STEP 6. Approved → continue.
|
Changes → back to STEP 6. Approved → continue.
|
||||||
@@ -208,7 +240,10 @@ against the founding contract. Distinct axis from STEP 10 code review
|
|||||||
([[LRN-095]]) — both run.
|
([[LRN-095]]) — both run.
|
||||||
|
|
||||||
## STEP 10 — CODE REVIEW
|
## STEP 10 — CODE REVIEW
|
||||||
Invoke `superpowers:requesting-code-review`. Fix all CRITICAL before proceeding.
|
Invoke `superpowers:requesting-code-review`. **Model routing (BDR-077):** the
|
||||||
|
review subagent it dispatches MUST carry `model: "opus"` in the Agent call —
|
||||||
|
craft review is dispatched judgment, never inherited from the session. Fix
|
||||||
|
all CRITICAL before proceeding.
|
||||||
|
|
||||||
## STEP 10b — CAPITALIZE FOUNDING DECISIONS (memory registries)
|
## STEP 10b — CAPITALIZE FOUNDING DECISIONS (memory registries)
|
||||||
A greenfield's founding architecture decisions are the highest-value BDRs — the
|
A greenfield's founding architecture decisions are the highest-value BDRs — the
|
||||||
@@ -267,8 +302,12 @@ does NOT commit them, and `gitflow finish` integrates only COMMITTED history
|
|||||||
— so a patch left uncommitted never reaches the merge/PR. Same PR-stranding class as the
|
— so a patch left uncommitted never reaches the merge/PR. Same PR-stranding class as the
|
||||||
STEP 10b capitalize fix (BDR-034).
|
STEP 10b capitalize fix (BDR-034).
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/doc-syncer.md` (AUTO MODE, scope: files changed this session).
|
Dispatch the doc pipeline (BDR-077):
|
||||||
Detect drift, update cmds/vars/structure, add recent changes entry.
|
`Agent(subagent_type="doc-syncer", model="opus")`
|
||||||
|
— `MODE: audit` + `auto-mode scope: <files changed this
|
||||||
|
session>`; NONE → done; `[MINOR]` plan → `MODE: patch` re-dispatch (sonnet
|
||||||
|
pin, no gate; SHAPE ESCALATION comes back gated); SIGNIFICANT → gate here,
|
||||||
|
then `MODE: patch` with the approved subset.
|
||||||
|
|
||||||
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
||||||
ONLY the files doc-syncer patched (its `PATCHED_FILES` output, one path per line → one argv
|
ONLY the files doc-syncer patched (its `PATCHED_FILES` output, one path per line → one argv
|
||||||
|
|||||||
+42
-12
@@ -21,7 +21,7 @@ $ARGUMENTS
|
|||||||
|
|
||||||
## STEP 0 — PLUGIN CHECK + AUTO-ACTIVATE
|
## STEP 0 — PLUGIN CHECK + AUTO-ACTIVATE
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/plugin-advisor.md` with hint "onboarding existing project + $ARGUMENTS".
|
Run `$HOME/.claude/lib/plugin-gate.md` with hint "onboarding existing project + $ARGUMENTS" (dispatch plugin-probe → checkpoint → dispatch plugin-advisor → gates in this loop, BDR-077).
|
||||||
|
|
||||||
- ACTION REQUIRED → show RECOMMENDATIONS block, offer: A) apply recos B) type "force". STOP.
|
- ACTION REQUIRED → show RECOMMENDATIONS block, offer: A) apply recos B) type "force". STOP.
|
||||||
- PROPOSED CHANGES exist → show list, ask "Apply? (yes / no / customize)". Apply on confirm.
|
- PROPOSED CHANGES exist → show list, ask "Apply? (yes / no / customize)". Apply on confirm.
|
||||||
@@ -89,7 +89,11 @@ STOP. La réponse détermine si STEP 1 tourne une fois (A) ou N fois (C) ou avec
|
|||||||
|
|
||||||
## STEP 2 — BASELINE CONFIG (onboarder agent)
|
## STEP 2 — BASELINE CONFIG (onboarder agent)
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/onboarder.md`. Passer un BRIEF minimal issu du filesystem scan :
|
Dispatch `Agent(subagent_type="onboarder")` (pin sonnet — BDR-077 : config
|
||||||
|
templating = exécution, plus jamais inline sur le modèle de session). Un
|
||||||
|
BLOCAGE (clé manquante, CLAUDE.md existant) revient en rapport — l'agent ne
|
||||||
|
peut pas te demander ; TU arbitres ici puis re-dispatches. Passer un BRIEF
|
||||||
|
minimal issu du filesystem scan :
|
||||||
- `archetype` (depuis STEP 1)
|
- `archetype` (depuis STEP 1)
|
||||||
- `project_name` (depuis package.json/pyproject.toml/README.md/dir name)
|
- `project_name` (depuis package.json/pyproject.toml/README.md/dir name)
|
||||||
- `stack` (depuis manifests détectés)
|
- `stack` (depuis manifests détectés)
|
||||||
@@ -203,13 +207,10 @@ ls .ctx7-cache/ 2>/dev/null
|
|||||||
```
|
```
|
||||||
|
|
||||||
### Détection fast-libs
|
### Détection fast-libs
|
||||||
Parse manifests selon l'archétype :
|
Source unique : `bash ~/.claude/lib/fast-libs.sh detect .` (deps JS/TS via
|
||||||
- **nextjs-app-router** → chercher : next, react, prisma, @supabase/*, drizzle-orm, next-auth, @clerk/*
|
package.json + Python via requirements/pyproject — liste centralisée,
|
||||||
- **react-spa** → chercher : react, @tanstack/*, zustand, jotai
|
BDR-078). Archétypes wordpress / cli-tool / library / dotfiles-meta /
|
||||||
- **rest-api-node** → chercher : fastify, @nestjs/*, prisma, drizzle-orm
|
static-html → souvent aucune fast-lib, audit léger.
|
||||||
- **rest-api-python** → chercher : fastapi, pydantic, sqlalchemy (si ≥ 2.0)
|
|
||||||
- **astro-static** → chercher : astro, @astrojs/*
|
|
||||||
- **wordpress / cli-tool / library / dotfiles-meta / static-html** → souvent aucune fast-lib, audit léger
|
|
||||||
|
|
||||||
### Vérification cache
|
### Vérification cache
|
||||||
Pour chaque fast-lib détectée :
|
Pour chaque fast-lib détectée :
|
||||||
@@ -354,7 +355,7 @@ Lire le bloc `audit_stack:` du fichier `~/.claude/lib/project-archetypes/<archet
|
|||||||
| Entry | Action | Livraison |
|
| Entry | Action | Livraison |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `analyze` | Déjà fait en STEP 5 | L3a |
|
| `analyze` | Déjà fait en STEP 5 | L3a |
|
||||||
| `code-clean` | Spawn subagent `general-purpose` (audit-only, inherits session = big model) | L3a |
|
| `code-clean` | Spawn subagent `general-purpose` (audit-only, `model="opus"` — BDR-076: dispatched audits off the session model) | L3a |
|
||||||
| `cso` | Si gstack ON → Skill(cso). Sinon → Agent general-purpose avec checklist OWASP + deps audit | L3a |
|
| `cso` | Si gstack ON → Skill(cso). Sinon → Agent general-purpose avec checklist OWASP + deps audit | L3a |
|
||||||
| `doc` | Spawn subagent `doc-syncer` (auto-mode OFF, report-only) | L3a |
|
| `doc` | Spawn subagent `doc-syncer` (auto-mode OFF, report-only) | L3a |
|
||||||
| `seo` | Subagents seo-analyzer + geo-analyzer en parallèle | L3b |
|
| `seo` | Subagents seo-analyzer + geo-analyzer en parallèle | L3b |
|
||||||
@@ -370,7 +371,8 @@ Lancer EN PARALLÈLE (un seul message, plusieurs Agent calls) les audits corresp
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="general-purpose",
|
subagent_type="general-purpose",
|
||||||
description="Onboard — code-clean audit only (read-only, big session model)",
|
model="opus",
|
||||||
|
description="Onboard — code-clean audit only (read-only, opus)",
|
||||||
prompt="""
|
prompt="""
|
||||||
AUDIT-ONLY mode — NO fixes, NO refactoring, NO file modifications.
|
AUDIT-ONLY mode — NO fixes, NO refactoring, NO file modifications.
|
||||||
Target: <PROJECT_ROOT>. ARCHETYPE: <archetype>.
|
Target: <PROJECT_ROOT>. ARCHETYPE: <archetype>.
|
||||||
@@ -406,6 +408,7 @@ bash $HOME/.claude/lib/toggle-external.sh list 2>/dev/null | grep -E "^gstack\s+
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="general-purpose",
|
subagent_type="general-purpose",
|
||||||
|
model="opus",
|
||||||
description="Onboard — security audit fallback (archetype-adaptive)",
|
description="Onboard — security audit fallback (archetype-adaptive)",
|
||||||
prompt="""
|
prompt="""
|
||||||
READ-ONLY security audit. No file modifications.
|
READ-ONLY security audit. No file modifications.
|
||||||
@@ -529,9 +532,11 @@ flux de dev sont deux formes distinctes ([[BDR-050]] pipeline dev ≠ audit).
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="doc-syncer",
|
subagent_type="doc-syncer",
|
||||||
|
model="opus",
|
||||||
description="Onboard — doc drift audit only",
|
description="Onboard — doc drift audit only",
|
||||||
prompt="""
|
prompt="""
|
||||||
REPORT-ONLY mode — NO edits, NO auto-sync.
|
MODE: audit — REPORT-ONLY, NO edits, NO auto-sync (no patch dispatch
|
||||||
|
follows: the report feeds the onboard backlog).
|
||||||
Target: full project at <PROJECT_ROOT>.
|
Target: full project at <PROJECT_ROOT>.
|
||||||
Scope:
|
Scope:
|
||||||
1. README drift (build/test commands, install steps, usage examples vs actual code)
|
1. README drift (build/test commands, install steps, usage examples vs actual code)
|
||||||
@@ -647,6 +652,7 @@ Si le skill ne supporte pas `--output`, capturer la sortie et écrire à la main
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="general-purpose",
|
subagent_type="general-purpose",
|
||||||
|
model="opus",
|
||||||
description="Onboard — static design review fallback",
|
description="Onboard — static design review fallback",
|
||||||
prompt="""
|
prompt="""
|
||||||
AUDIT-ONLY mode — NO edits. Static design review du code UI.
|
AUDIT-ONLY mode — NO edits. Static design review du code UI.
|
||||||
@@ -690,6 +696,7 @@ Puis parser le JSON Lighthouse (scores perf/a11y/bp/seo/pwa + top opportunities)
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="general-purpose",
|
subagent_type="general-purpose",
|
||||||
|
model="opus",
|
||||||
description="Onboard — static perf audit",
|
description="Onboard — static perf audit",
|
||||||
prompt="""
|
prompt="""
|
||||||
AUDIT-ONLY mode — NO edits.
|
AUDIT-ONLY mode — NO edits.
|
||||||
@@ -732,6 +739,7 @@ Parser axe-core résultats (violations, incomplete, inapplicable, passes) → `.
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="general-purpose",
|
subagent_type="general-purpose",
|
||||||
|
model="opus",
|
||||||
description="Onboard — static a11y audit",
|
description="Onboard — static a11y audit",
|
||||||
prompt="""
|
prompt="""
|
||||||
AUDIT-ONLY mode — NO edits.
|
AUDIT-ONLY mode — NO edits.
|
||||||
@@ -777,6 +785,7 @@ Spawn un subagent synthétiseur (isolé, chargé uniquement du contenu de `.onbo
|
|||||||
```
|
```
|
||||||
Agent(
|
Agent(
|
||||||
subagent_type="general-purpose",
|
subagent_type="general-purpose",
|
||||||
|
model="opus",
|
||||||
description="Onboard — synthèse vers .claude/audits/",
|
description="Onboard — synthèse vers .claude/audits/",
|
||||||
prompt="""
|
prompt="""
|
||||||
Lire tous les fichiers de <PROJECT_ROOT>/.onboard-audit/ :
|
Lire tous les fichiers de <PROJECT_ROOT>/.onboard-audit/ :
|
||||||
@@ -869,6 +878,22 @@ Vérifier que les 4 fichiers `.claude/audits/ONBOARD_REPORT.md`, `.claude/audits
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## STEP 7b — CHALLENGE THE PROPOSALS (before the human gate)
|
||||||
|
The 4 audit files are on disk; `AUDIT_PROPOSALS.md` is the artifact worth
|
||||||
|
attacking before the human spends a gate on it. Run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` =
|
||||||
|
`.claude/audits/AUDIT_PROPOSALS.md`, `KIND` = `proposals`, `SCOPE` = the audited
|
||||||
|
project paths (the `audit_stack` coverage), `CONSTRAINTS` = the STEP 1 archetype
|
||||||
|
profile + the STEP 3 interview constraints (stade, légal, budget perf). Three
|
||||||
|
blind challengers ask whether these are the RIGHT priorities and what the audit
|
||||||
|
under-rated; the main loop RE-THINKS every aspect a BLOCKER lands (a named
|
||||||
|
proposals change re-written into `AUDIT_PROPOSALS.md`, or `[deferred <date>]`)
|
||||||
|
and re-challenges once if the file materially changed. Feed the REVISED
|
||||||
|
proposals + a CHALLENGE SUMMARY into STEP 8. Advisory — the human remains the
|
||||||
|
decider.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STEP 8 — VALIDATION GATE ★ MANDATORY STOP
|
## STEP 8 — VALIDATION GATE ★ MANDATORY STOP
|
||||||
|
|
||||||
Afficher à l'utilisateur :
|
Afficher à l'utilisateur :
|
||||||
@@ -893,6 +918,11 @@ TOP 5 PRIORITÉS :
|
|||||||
4. [P1 Haute] <titre>
|
4. [P1 Haute] <titre>
|
||||||
5. [P2 Moyenne] <titre>
|
5. [P2 Moyenne] <titre>
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 7b — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named proposals change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
|
|
||||||
Prochaine étape : générer .claude/tasks/TODO.md depuis .claude/audits/AUDIT_PROPOSALS.md approuvé.
|
Prochaine étape : générer .claude/tasks/TODO.md depuis .claude/audits/AUDIT_PROPOSALS.md approuvé.
|
||||||
|
|
||||||
Options :
|
Options :
|
||||||
|
|||||||
@@ -2,13 +2,19 @@
|
|||||||
name: plugin-check
|
name: plugin-check
|
||||||
description: 'Audit active plugins vs project needs. Read-only advisory recommending enable/disable. Triggers: "plugin-check", "quels plugins".'
|
description: 'Audit active plugins vs project needs. Read-only advisory recommending enable/disable. Triggers: "plugin-check", "quels plugins".'
|
||||||
argument-hint: '[ex: "React + FastAPI" or "Rust CLI, no frontend"]'
|
argument-hint: '[ex: "React + FastAPI" or "Rust CLI, no frontend"]'
|
||||||
allowed-tools: Read, Bash, Glob, Grep
|
allowed-tools: Read, Bash, Glob, Grep, Agent
|
||||||
---
|
---
|
||||||
|
|
||||||
Load and follow strictly: `$HOME/.claude/agents/plugin-advisor.md`.
|
Run `$HOME/.claude/lib/plugin-gate.md` on the context below — dispatch
|
||||||
|
plugin-probe (sonnet) → validation checkpoint → dispatch plugin-advisor
|
||||||
|
(opus) → present the PLUGIN CHECK block (BDR-077: detection and reasoning
|
||||||
|
dispatched, gates in this loop).
|
||||||
|
|
||||||
Analyze active plugins + context below, produce PLUGIN ADVISOR REPORT.
|
/plugin-check is READ-ONLY advisory: SKIP the gate's step 5 (apply) — show
|
||||||
|
the advisor's exact toggle commands for the user instead. Never write; user
|
||||||
|
toggles via `claude plugin enable/disable`.
|
||||||
|
|
||||||
If `$HOME/.claude/agents/plugin-advisor.md` unreachable: emit `Plugin advisor agent missing.` and STOP. Never write — user toggles via `claude plugin enable/disable`.
|
If `$HOME/.claude/lib/plugin-gate.md` unreachable: emit `Plugin gate include
|
||||||
|
missing.` and STOP.
|
||||||
|
|
||||||
$ARGUMENTS
|
$ARGUMENTS
|
||||||
|
|||||||
+15
-3
@@ -61,6 +61,15 @@ protected — `set` will refuse to disable them even if the profile omits them.
|
|||||||
**Managed plugins** that `set` may disable when not in profile:
|
**Managed plugins** that `set` may disable when not in profile:
|
||||||
`ui-ux-pro-max@ui-ux-pro-max-skill`, `plugin-dev@claude-code-plugins`,
|
`ui-ux-pro-max@ui-ux-pro-max-skill`, `plugin-dev@claude-code-plugins`,
|
||||||
`pr-review-toolkit@claude-code-plugins`. Other plugins are never auto-toggled.
|
`pr-review-toolkit@claude-code-plugins`. Other plugins are never auto-toggled.
|
||||||
|
**Managed externals** (`emil-design-eng`, `frontend-design`,
|
||||||
|
`design-motion-principles`, `impeccable`) and **managed MCPs** (`magic`)
|
||||||
|
follow the same symmetry (BDR-079): `set` enables them when the profile
|
||||||
|
lists them (from parked state, or from `skills-external/` if the symlink
|
||||||
|
never existed) and parks/unregisters them when it does not — e.g. `set
|
||||||
|
backend` after design work turns emil and magic off. `darwin-skill` and any
|
||||||
|
other unlisted external are never auto-touched. gstack works the same
|
||||||
|
all the way down: a profile listing gstack skills while the whole pack is
|
||||||
|
off (via `toggle-external.sh`) re-enables JUST those skills on demand.
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
@@ -117,8 +126,11 @@ bash "$HOME/.claude/lib/profile.sh" $ARGUMENTS
|
|||||||
update-check, learnings — script doesn't touch that infra. Disabled skills
|
update-check, learnings — script doesn't touch that infra. Disabled skills
|
||||||
are just hidden from Claude Code's scanner; the gstack repo stays installed.
|
are just hidden from Claude Code's scanner; the gstack repo stays installed.
|
||||||
- Profile changes DO toggle the managed Claude Code plugins (ui-ux-pro-max,
|
- Profile changes DO toggle the managed Claude Code plugins (ui-ux-pro-max,
|
||||||
plugin-dev, pr-review-toolkit) and the `magic` MCP — see the Mechanism table
|
plugin-dev, pr-review-toolkit), the managed external packs (emil-design-eng,
|
||||||
above (BDR-008). Anything outside that managed set stays manual:
|
frontend-design, design-motion-principles, impeccable) and the `magic` MCP —
|
||||||
`claude plugin enable|disable`, `claude mcp add|remove`.
|
in BOTH directions: `set` enables what the profile lists and disables the
|
||||||
|
managed leftovers it doesn't (BDR-008, BDR-079). Anything outside those
|
||||||
|
allowlists stays manual: `claude plugin enable|disable`, `claude mcp
|
||||||
|
add|remove`.
|
||||||
- `set` is destructive in the sense that it disables non-listed gstack skills.
|
- `set` is destructive in the sense that it disables non-listed gstack skills.
|
||||||
Use `apply` if the user wants additive behavior.
|
Use `apply` if the user wants additive behavior.
|
||||||
|
|||||||
+98
-21
@@ -302,14 +302,31 @@ still carries this rule for its applier:
|
|||||||
If `Edit` is insufficient (full-template refactor), the item is escalated
|
If `Edit` is insufficient (full-template refactor), the item is escalated
|
||||||
as a cross-agent note → §11 user action instead.
|
as a cross-agent note → §11 user action instead.
|
||||||
|
|
||||||
## STEP 1 — Spawn both agents IN PARALLEL
|
## STEP 1 — Run both domain pipelines (3 phases; domains parallel per phase)
|
||||||
|
|
||||||
Issue both `Agent` tool calls **in the same message** (parallel tool
|
BDR-077: each domain runs collect (sonnet) → judge (opus pin) → template
|
||||||
calls). The harness runs them concurrently.
|
(sonnet), the two domains IN PARALLEL at every phase (both `Agent` calls
|
||||||
|
in the same message). Mint run ids first: `RUNID_SEO=$(date +%s)-seo`,
|
||||||
|
`RUNID_GEO=$(date +%s)-geo`. The CONTEXT payloads below are the SHARED
|
||||||
|
CONTEXT of each domain — pass them VERBATIM to every phase dispatch of
|
||||||
|
that domain (LRN-126). Clean both `.audit/*-signals-*.md` files after
|
||||||
|
STEP 2.
|
||||||
|
|
||||||
|
**DISPATCHER ERROR CONTRACT (fail-closed at the pipeline, not just the
|
||||||
|
judge):** a `SEO JUDGE — VERDICT: ERROR(…)` / `GEO JUDGE — VERDICT:
|
||||||
|
ERROR(…)`, a mute judge, or a BLOCKED collect → STOP that domain: NO
|
||||||
|
template dispatch, NO L1 apply for it. Surface the error verbatim, retry
|
||||||
|
ONCE with a fresh collect+judge for that domain; a 2nd failure →
|
||||||
|
escalate to the human. A mute or ERROR judge is NEVER carried into
|
||||||
|
templating.
|
||||||
|
|
||||||
|
**PHASE A — collect (both domains, one message):**
|
||||||
|
|
||||||
```
|
```
|
||||||
Agent(subagent_type="seo-analyzer")
|
Agent(subagent_type="seo-analyzer", model="sonnet")
|
||||||
prompt: """
|
prompt: """
|
||||||
|
MODE: collect
|
||||||
|
RUNID: <RUNID_SEO>
|
||||||
Dispatched from /seo. Context:
|
Dispatched from /seo. Context:
|
||||||
|
|
||||||
AUDIT DEPTH: <LOCAL|FULL>
|
AUDIT DEPTH: <LOCAL|FULL>
|
||||||
@@ -379,18 +396,15 @@ SHARED-FILE EDIT DISCIPLINE (carried into each bundle item):
|
|||||||
legal pages, new city/service pages.
|
legal pages, new city/service pages.
|
||||||
- If full-template refactor is needed, emit as a cross-agent note → §11.
|
- If full-template refactor is needed, emit as a cross-agent note → §11.
|
||||||
|
|
||||||
Execute your agent spec at ~/.claude/agents/seo-analyzer.md starting
|
Execute MODE: collect per your spec — STEP 2-5 only (context above
|
||||||
at STEP 2 (skip STEP 0 and STEP 1 — context is provided above).
|
replaces STEP 0-1). Write the signals file + COLLECTION COMPLETE
|
||||||
|
sentinel, emit the COLLECT REPORT, stop. No scoring, no bundle.
|
||||||
At STEP 13, emit the STRUCTURED ENVELOPE for merging (not a standalone
|
|
||||||
SEO.md), INCLUDING the `## FIX BUNDLE` section terminated by the verbatim
|
|
||||||
`READY TO APPLY — awaiting dispatcher confirmation` sentinel. Do NOT apply
|
|
||||||
any fix, do NOT dispatch any sub-agent, do NOT write SEO.md — /seo applies
|
|
||||||
your bundle in STEP 1.5 and merges the reports.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Agent(subagent_type="geo-analyzer")
|
Agent(subagent_type="geo-analyzer", model="sonnet")
|
||||||
prompt: """
|
prompt: """
|
||||||
|
MODE: collect
|
||||||
|
RUNID: <RUNID_GEO>
|
||||||
Dispatched from /seo. Context:
|
Dispatched from /seo. Context:
|
||||||
|
|
||||||
AUDIT DEPTH: <LOCAL|FULL>
|
AUDIT DEPTH: <LOCAL|FULL>
|
||||||
@@ -436,17 +450,75 @@ SHARED-FILE EDIT DISCIPLINE (carried into each bundle item):
|
|||||||
llms-full.txt.
|
llms-full.txt.
|
||||||
- If full-template refactor is needed, emit as a cross-agent note → §11.
|
- If full-template refactor is needed, emit as a cross-agent note → §11.
|
||||||
|
|
||||||
Execute your agent spec at ~/.claude/agents/geo-analyzer.md starting
|
Execute MODE: collect per your spec — STEP 2-5 only (context above
|
||||||
at STEP 2 (skip STEP 0 and STEP 1 — context is provided above).
|
replaces STEP 0-1). Write the signals file + COLLECTION COMPLETE
|
||||||
|
sentinel, emit the COLLECT REPORT, stop. No scoring, no bundle.
|
||||||
At STEP 14, emit the STRUCTURED ENVELOPE for merging (not a standalone
|
|
||||||
GEO.md), INCLUDING the `## FIX BUNDLE` section terminated by the verbatim
|
|
||||||
`READY TO APPLY — awaiting dispatcher confirmation` sentinel. Do NOT apply
|
|
||||||
any fix, do NOT dispatch any sub-agent, do NOT write GEO.md/SEO.md — /seo
|
|
||||||
applies your bundle in STEP 1.5 and merges the reports.
|
|
||||||
"""
|
"""
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**PHASE B — judge (both domains, one message, AFTER both COLLECT REPORTs
|
||||||
|
are DONE):** no `model=` override — the opus frontmatter pins apply.
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(subagent_type="seo-analyzer")
|
||||||
|
prompt: "MODE: judge
|
||||||
|
RUNID: <RUNID_SEO>
|
||||||
|
<the seo SHARED CONTEXT verbatim>
|
||||||
|
Load .audit/seo-signals-<RUNID_SEO>.md (fail closed per your spec), run
|
||||||
|
STEP 6-11, report scoring + findings + action plan + triage batches."
|
||||||
|
|
||||||
|
Agent(subagent_type="geo-analyzer")
|
||||||
|
prompt: "MODE: judge
|
||||||
|
RUNID: <RUNID_GEO>
|
||||||
|
<the geo SHARED CONTEXT verbatim>
|
||||||
|
Load .audit/geo-signals-<RUNID_GEO>.md (fail closed per your spec), run
|
||||||
|
STEP 6-12, report scoring + findings + action plan + triage batches."
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply the DISPATCHER ERROR CONTRACT above on each returned verdict.
|
||||||
|
|
||||||
|
**PHASE C — template (both domains, one message, only for domains whose
|
||||||
|
judge is DONE):**
|
||||||
|
|
||||||
|
```
|
||||||
|
Agent(subagent_type="seo-analyzer", model="sonnet")
|
||||||
|
prompt: "MODE: template
|
||||||
|
<the seo SHARED CONTEXT verbatim>
|
||||||
|
JUDGE REPORT (verbatim, ground truth — never re-derive a score):
|
||||||
|
<the seo judge report>
|
||||||
|
Run STEP 12-14: emit the STRUCTURED ENVELOPE for merging (not a
|
||||||
|
standalone SEO.md), INCLUDING the `## FIX BUNDLE` section terminated by
|
||||||
|
the verbatim `READY TO APPLY — awaiting dispatcher confirmation`
|
||||||
|
sentinel. Do NOT apply any fix, do NOT dispatch any sub-agent, do NOT
|
||||||
|
write SEO.md — /seo applies your bundle in STEP 1.5 and merges the
|
||||||
|
reports."
|
||||||
|
|
||||||
|
Agent(subagent_type="geo-analyzer", model="sonnet")
|
||||||
|
prompt: "MODE: template
|
||||||
|
<the geo SHARED CONTEXT verbatim>
|
||||||
|
JUDGE REPORT (verbatim, ground truth — never re-derive a score):
|
||||||
|
<the geo judge report>
|
||||||
|
Run STEP 13-15: emit the STRUCTURED ENVELOPE for merging (not a
|
||||||
|
standalone GEO.md), INCLUDING the `## FIX BUNDLE` section terminated by
|
||||||
|
the verbatim `READY TO APPLY — awaiting dispatcher confirmation`
|
||||||
|
sentinel. Do NOT apply any fix, do NOT dispatch any sub-agent, do NOT
|
||||||
|
write GEO.md/SEO.md — /seo applies your bundle in STEP 1.5 and merges
|
||||||
|
the reports."
|
||||||
|
```
|
||||||
|
|
||||||
|
## STEP 1b — CHALLENGE THE FIX BUNDLE (advisory, before apply)
|
||||||
|
Both envelopes now carry a `## FIX BUNDLE` — worth attacking before any edit lands.
|
||||||
|
**Skip if intervention mode = conservative** (nothing is applied). Else persist both
|
||||||
|
bundles (seo + geo, verbatim) to `.claude/tasks/plans/<date>-<slug>-<HHMM>.md`, then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` = `fix-bundle`,
|
||||||
|
`SCOPE` = the target site files the items touch, `CONSTRAINTS` = the STEP 0 file-ownership
|
||||||
|
matrix + shared-file edit discipline + confirmed Canonical NAP + intervention mode. Three
|
||||||
|
blind challengers ask, per item: will it ACHIEVE its goal / could it BREAK or regress the
|
||||||
|
page / is a simpler (or no) fix better. This main loop RE-THINKS every aspect a BLOCKER
|
||||||
|
lands (a named bundle change, or `[deferred <date>]`) and re-challenges once if the bundle
|
||||||
|
materially changed. Advisory — it sits BEFORE (never replaces) the STEP 1.5 GATED approval;
|
||||||
|
carry its CHALLENGE SUMMARY into that gate.
|
||||||
|
|
||||||
## STEP 1.5 — Apply fix bundles (from THIS main loop, at L1)
|
## STEP 1.5 — Apply fix bundles (from THIS main loop, at L1)
|
||||||
|
|
||||||
Both analyzers returned an envelope containing a `## FIX BUNDLE` section
|
Both analyzers returned an envelope containing a `## FIX BUNDLE` section
|
||||||
@@ -493,6 +565,11 @@ Collect every GATED item from BOTH bundles and present ONE gate:
|
|||||||
SEO/GEO — gated changes need approval (visible / structural):
|
SEO/GEO — gated changes need approval (visible / structural):
|
||||||
D1 <change> — impact: <visible change> [seo]
|
D1 <change> — impact: <visible change> [seo]
|
||||||
G5.1 <change> — impact: <visible change> [geo]
|
G5.1 <change> — impact: <visible change> [geo]
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 1b — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named bundle change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
Approve all / select (ids) / skip all?
|
Approve all / select (ids) / skip all?
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ $ARGUMENTS
|
|||||||
---
|
---
|
||||||
|
|
||||||
## STEP 0 — PLUGIN CHECK + AUTO-ACTIVATE
|
## STEP 0 — PLUGIN CHECK + AUTO-ACTIVATE
|
||||||
Load `$HOME/.claude/agents/plugin-advisor.md`. Feed request.
|
Run `$HOME/.claude/lib/plugin-gate.md`. Feed request (dispatch plugin-probe →
|
||||||
|
checkpoint → dispatch plugin-advisor; gates stay in this loop — BDR-077).
|
||||||
- ACTION REQUIRED → show RECOMMENDATIONS block, offer: A) fix plugins B) type "force". STOP.
|
- ACTION REQUIRED → show RECOMMENDATIONS block, offer: A) fix plugins B) type "force". STOP.
|
||||||
- PROPOSED CHANGES exist → show list, ask "Apply? (yes / no / customize)". Apply on confirm.
|
- PROPOSED CHANGES exist → show list, ask "Apply? (yes / no / customize)". Apply on confirm.
|
||||||
- OK → `✅ Plugin check passed — [active plugins] — complexity: <score>%`, continue.
|
- OK → `✅ Plugin check passed — [active plugins] — complexity: <score>%`, continue.
|
||||||
@@ -51,7 +52,8 @@ ls .gsd/ROADMAP.md 2>/dev/null | head -1
|
|||||||
STOP.
|
STOP.
|
||||||
|
|
||||||
## STEP 0c — CTX7 CACHE CHECK (if fast-libs in project)
|
## STEP 0c — CTX7 CACHE CHECK (if fast-libs in project)
|
||||||
Check if the project uses fast-evolving libs (scan `package.json` for next, react, prisma, supabase, drizzle, expo):
|
Check if the project uses fast-moving libs — single source of truth:
|
||||||
|
`bash ~/.claude/lib/fast-libs.sh detect .` (exit 1 = none; BDR-078):
|
||||||
1. If `.ctx7-cache/` exists with recent files (<7 days old) → print `📚 ctx7 cache found: <libs>` and continue.
|
1. If `.ctx7-cache/` exists with recent files (<7 days old) → print `📚 ctx7 cache found: <libs>` and continue.
|
||||||
2. If `.ctx7-cache/` missing or stale AND `ctx7` is installed AND fast-libs detected:
|
2. If `.ctx7-cache/` missing or stale AND `ctx7` is installed AND fast-libs detected:
|
||||||
```bash
|
```bash
|
||||||
@@ -115,6 +117,19 @@ Invoke `superpowers:writing-plans` with the validated design AND the 0d digest:
|
|||||||
must be consistent with the in-force constraints; where a task implements or affects one,
|
must be consistent with the in-force constraints; where a task implements or affects one,
|
||||||
note the ID inline. Break design into tasks (2-5 min each). Each task: exact file paths, full code, verification steps.
|
note the ID inline. Break design into tasks (2-5 min each). Each task: exact file paths, full code, verification steps.
|
||||||
|
|
||||||
|
## STEP 2b — CHALLENGE THE PLAN (adversarial, before the gate)
|
||||||
|
Before the human sees the plan, harden it. Run `$HOME/.claude/lib/challenge-plan.md`:
|
||||||
|
- `PLAN` = the plan STEP 2 wrote under `docs/superpowers/plans/`
|
||||||
|
- `KIND` = `build-plan`
|
||||||
|
- `SCOPE` = the files/dirs the plan touches
|
||||||
|
- `CONSTRAINTS` = the STEP 1 validated design's decided trade-offs / rejected options
|
||||||
|
|
||||||
|
Three blind `plan-challenger` subagents (correctness / robustness / simplicity)
|
||||||
|
attack it in parallel on the big model; the main loop RE-THINKS every aspect a
|
||||||
|
BLOCKER lands (a named plan change, or `[deferred <date>]`), re-challenges once if
|
||||||
|
the plan materially changed, and feeds the REVISED plan + a CHALLENGE SUMMARY into
|
||||||
|
STEP 3. Advisory — the human remains the decider.
|
||||||
|
|
||||||
## STEP 3 — VALIDATION GATE ★ MANDATORY STOP
|
## STEP 3 — VALIDATION GATE ★ MANDATORY STOP
|
||||||
```
|
```
|
||||||
SHIP FEATURE — VALIDATION GATE
|
SHIP FEATURE — VALIDATION GATE
|
||||||
@@ -127,6 +142,11 @@ RELATED MEMORY — disposition CLAIMED by this plan (review each):
|
|||||||
- BLK-009 [already seen] — <how avoided / why N-A>
|
- BLK-009 [already seen] — <how avoided / why N-A>
|
||||||
|
|
||||||
Review the claims above — flag any item the plan does NOT actually honor.
|
Review the claims above — flag any item the plan does NOT actually honor.
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 2b — 3 lenses):
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named plan change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
Approve and execute? (yes / request changes)
|
Approve and execute? (yes / request changes)
|
||||||
```
|
```
|
||||||
This block EXPOSES each in-force item with the plan's CLAIMED disposition, for human
|
This block EXPOSES each in-force item with the plan's CLAIMED disposition, for human
|
||||||
@@ -204,7 +224,10 @@ conformity + security vs. craft/design) — both run, neither subsumes the
|
|||||||
other ([[LRN-095]]).
|
other ([[LRN-095]]).
|
||||||
|
|
||||||
## STEP 6 — CODE REVIEW
|
## STEP 6 — CODE REVIEW
|
||||||
Invoke `superpowers:requesting-code-review`. Fix all CRITICAL before proceeding.
|
Invoke `superpowers:requesting-code-review`. **Model routing (BDR-077):** the
|
||||||
|
review subagent it dispatches MUST carry `model: "opus"` in the Agent call —
|
||||||
|
craft review is dispatched judgment, never inherited from the session. Fix
|
||||||
|
all CRITICAL before proceeding.
|
||||||
|
|
||||||
## STEP 7 — CAPITALIZE (memory registries)
|
## STEP 7 — CAPITALIZE (memory registries)
|
||||||
Feature shipped implies at least one design decision worth capturing. Run this BEFORE STEP 9 FINISH — the implementation commits (STEP 4) already exist, so the entries' hash references are valid, and the memory commit lands on the branch that FINISH integrates (otherwise it strands outside the PR):
|
Feature shipped implies at least one design decision worth capturing. Run this BEFORE STEP 9 FINISH — the implementation commits (STEP 4) already exist, so the entries' hash references are valid, and the memory commit lands on the branch that FINISH integrates (otherwise it strands outside the PR):
|
||||||
@@ -246,8 +269,13 @@ Run BEFORE STEP 9 FINISH. doc-syncer PATCHES public docs but does NOT commit the
|
|||||||
uncommitted (or committed after) never reaches the merge/PR. Same PR-stranding class as the
|
uncommitted (or committed after) never reaches the merge/PR. Same PR-stranding class as the
|
||||||
STEP 7 capitalize fix (BDR-034).
|
STEP 7 capitalize fix (BDR-034).
|
||||||
|
|
||||||
Load `$HOME/.claude/agents/doc-syncer.md`. Execute in automatic mode:
|
Dispatch the doc pipeline (BDR-077 — audit judgment on opus, patch on the
|
||||||
`auto-mode scope: <list of files modified during this session>`
|
sonnet pin, gate HERE): `Agent(subagent_type="doc-syncer", model="opus")` —
|
||||||
|
`MODE: audit` + `auto-mode scope: <list of files modified during this
|
||||||
|
session>`. NONE → done; `[MINOR]` PATCH PLAN → re-dispatch
|
||||||
|
`Agent(subagent_type="doc-syncer")` with `MODE: patch` + the plan verbatim
|
||||||
|
(SHAPE ESCALATION comes back here, gated); SIGNIFICANT → gate here, then
|
||||||
|
`MODE: patch` with the approved subset.
|
||||||
|
|
||||||
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
**Then commit the docs** — follow `$HOME/.claude/lib/doc-commit.md`: it surgically commits
|
||||||
ONLY the files doc-syncer patched (its `PATCHED_FILES` output, one path per line → one argv
|
ONLY the files doc-syncer patched (its `PATCHED_FILES` output, one path per line → one argv
|
||||||
|
|||||||
@@ -111,9 +111,9 @@ honestly in the summary. Never loop past 3.
|
|||||||
|
|
||||||
### Phase B — CLEAN
|
### Phase B — CLEAN
|
||||||
|
|
||||||
1. Dispatch a read-only cleanup audit (analyzer or general-purpose —
|
1. Dispatch a read-only cleanup audit (analyzer — opus-pinned, BDR-076 —
|
||||||
inherits the big session model; NOT the sonnet code-cleaner, which is
|
or general-purpose with `model="opus"`; NOT the sonnet code-cleaner,
|
||||||
now a fix executor): dead code, unused imports/exports,
|
which is now a fix executor): dead code, unused imports/exports,
|
||||||
commented-out blocks, stale flags, norm violations. Findings as
|
commented-out blocks, stale flags, norm violations. Findings as
|
||||||
`id | file:line | finding | proposed fix`.
|
`id | file:line | finding | proposed fix`.
|
||||||
2. Apply **behavior-preserving** fixes only. A finding that would change
|
2. Apply **behavior-preserving** fixes only. A finding that would change
|
||||||
|
|||||||
@@ -251,6 +251,22 @@ grep -c '^### \[Critique\]' .claude/audits/VALIDATE.md
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## STEP 2b — CHALLENGE THE FIX BUNDLE (MODE=fix only, advisory)
|
||||||
|
Skip if MODE=audit (no bundle exists). Else, before the STEP 3 gate, harden the bundle:
|
||||||
|
extract the `## 5. Fix bundle` section from VALIDATE.md to
|
||||||
|
`.claude/tasks/plans/<date>-<slug>-<HHMM>.md` (a clean, blind-judgeable artifact), then run
|
||||||
|
`$HOME/.claude/lib/challenge-plan.md` with `PLAN` = that file, `KIND` = `fix-bundle`,
|
||||||
|
`SCOPE` = the HTML/CSS files each fix touches, `CONSTRAINTS` = the STEP 1 strict scope (W3C
|
||||||
|
validity + WCAG 2.1) + the conservative auto-fix rule (structural/syntactic only, content →
|
||||||
|
§6) + the shared-template discipline (targeted Edit, never Write — templates carry /seo +
|
||||||
|
/geo content). Three blind challengers ask, per fix: will it ACHIEVE conformance / could it
|
||||||
|
BREAK rendering or regress another SC / is a simpler fix better. This main loop RE-THINKS
|
||||||
|
every aspect a BLOCKER lands (a named bundle change, or `[deferred <date>]`) and re-challenges
|
||||||
|
once if the bundle materially changed. Advisory — it sits BEFORE (never replaces) the STEP 3
|
||||||
|
confirmation; carry its CHALLENGE SUMMARY into that gate.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STEP 3 — Apply fixes (MODE=fix only)
|
## STEP 3 — Apply fixes (MODE=fix only)
|
||||||
|
|
||||||
Skip this step if `MODE=audit`.
|
Skip this step if `MODE=audit`.
|
||||||
@@ -271,6 +287,11 @@ Files to modify (N) :
|
|||||||
|
|
||||||
Critical : X | Haute : Y | Moyenne : Z | Basse : W
|
Critical : X | Haute : Y | Moyenne : Z | Basse : W
|
||||||
|
|
||||||
|
CHALLENGE SUMMARY (STEP 2b — 3 lenses) :
|
||||||
|
BLOCKERs addressed : <n> — <finding → the named bundle change that closes it>
|
||||||
|
Deferred (human-ack): <list | none>
|
||||||
|
Lenses returned : correctness / robustness / simplicity (NAME any that failed to return)
|
||||||
|
|
||||||
Options :
|
Options :
|
||||||
A) Apply all
|
A) Apply all
|
||||||
B) Review each diff before applying
|
B) Review each diff before applying
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.1.0
|
1.4.0
|
||||||
|
|||||||
Reference in New Issue
Block a user