Compare commits
30
Commits
c816b11bc4
...
18c37a5505
@@ -34,6 +34,7 @@ rules:
|
||||
| BLK-012 | 2026-06-29 | gitflow_init half-applied: socle-commit failure swallowed → hook activated on partial run → re-run self-blocks | resolved |
|
||||
| BLK-013 | 2026-06-30 | `make plugin` Error 127 — npm absent on apt-`nodejs` host (Step 4 gsd-pi aborts, Steps 5-10 + residual cleanup never run) | resolved (env) |
|
||||
| BLK-014 | 2026-07-01 | `make install` aborts npm EEXIST on `~/.local/bin/claude` when claude already installed via native installer — no presence guard | resolved |
|
||||
| BLK-015 | 2026-07-03 | `gitflow_finish` ignored its `<type> <name>` args → merged the CHECKED-OUT branch not the one named → wrong-branch merge (audit LOT3) | resolved |
|
||||
|
||||
---
|
||||
|
||||
@@ -179,3 +180,12 @@ rules:
|
||||
- **Status**: resolved. Fix `8dc4027`, branch `bugfix/install-claude-idempotent`, pending merge validation.
|
||||
- **Reference**: [[BLK-013]] npm prefix `~/.local` = contributing factor (npm bin over native bin). install-plugins.sh already pointed to code.claude.com (native) — install.sh was the npm outlier. Fresh-machine `elif npm` branch channel-consistency = open design question (potential BDR). Pattern → [[LRN-085]].
|
||||
- **Update 2026-07-01**: MERGED `2393ca5` (bugfix/install-claude-idempotent → develop), pushed — supersedes "pending merge validation". The open channel-consistency question is RESOLVED by [[BDR-046]] (fresh install → native installer, npm dropped for claude); install.sh has no `elif npm` branch → nothing left to trancher.
|
||||
|
||||
## BLK-015 — `gitflow_finish` ignored its args, merged the CURRENT branch not the one asked
|
||||
|
||||
- **Date**: 2026-07-03
|
||||
- **Friction**: audit 2026-07-02 — `gitflow.sh finish bugfix audit-bugs` run while checked out on `feature/audit-tokens` merged audit-tokens (LOT3), NOT audit-bugs. Final develop state identical (disjoint hunks) so no data damage, but the merge order was silently wrong. UX trap: the command LOOKS like it targets `bugfix/audit-bugs`.
|
||||
- **Real cause**: CLI dispatch (`lib/gitflow.sh:257` `finish) gitflow_finish "$@"`) forwards args, but the function derived its source from `HEAD` (`git symbolic-ref`) and NEVER read `$1/$2` → the `<type> <name>` were silently dropped. Merge source = ambient state (checked-out branch), not the named target. Design intended finish to always operate on HEAD (human gate = "be on the branch"), but nothing enforced that passed args, if any, MATCH the branch you're on.
|
||||
- **Solution**: `gitflow_finish [<type> <name>]` — args now an optional safety ASSERTION: present AND `"$req_type/$req_name" != "$br"` → error `operates on the current branch 'X', but you asked 'Y' — checkout 'Y' first`, rc 2. No args = behavior unchanged (only real caller `skills/gitflow/SKILL.md:36` + every test pass none → zero regression). +7 regression assertions (`gitflow-test.sh` T12, numbered to dodge collision with reconcile's own T6c).
|
||||
- **Status**: resolved. Commit `d9fdd4c`, branch `bugfix/gitflow-finish-args`.
|
||||
- **Reference**: journal 2026-07-02 (trap noted, not fixed) → fixed 2026-07-03. Pattern → [[LRN-089]] (pass-through wrapper deriving target from ambient state = silent contract violation).
|
||||
|
||||
@@ -477,6 +477,7 @@ rules:
|
||||
- Secret in `repo/.env`, gitignored (status quo) — one `git add -f` or a `.gitignore` slip leaks it; the secret physically sits in the tree.
|
||||
- Scripts read `~/.claude/.env` directly — makes the symlink redundant but rewrites every read path and loses repo-local visibility.
|
||||
- **Reference**: `link.sh` `link_env()`, `.gitignore`, `lib/toggle-external.sh`, `install-plugins.sh`, `.env.example`, commits 131d0bc / f9cc866. Linked to [[BDR-025]] (magic's `MAGIC_API_KEY`, consumed by the gate's required-but-manual class).
|
||||
- **Update 2026-07-02 (incident — copies of secrets)**: `claude mcp add --env` MATERIALIZES the key into `~/.claude.json` (`mcpServers.magic.env`) — a 2nd live copy OUTSIDE the `~/.claude/.env` canonical and outside the repo deny rules' reach. An audit query printed it into a session transcript → key rotated (21st.dev). Rule: secrets have COPIES (tool configs, transcripts, caches) — protect/audit the copies, not just the canonical; when inspecting MCP config, filter env fields (`jq 'del(.. | .env?)'`). Same audit: `~/.claude/.env` hardened 0664→0600.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -295,3 +295,16 @@ rules:
|
||||
- /reconcile show-only (claude repo, engine-verified): confronted TODO+registries vs git/fs. Real state = 1 actionable (install-plugins npm harden), 3 blocked-upstream (BLK-001 rtk / BLK-003 darwin / BLK-009 CC #21858, re-test on CC MAJ), 3 deferred-on-trigger, release-decision live (develop 20 ahead of v4.0.0). Engine false-flagged BLK-014 (last-status-wins caught Reference "open" vs Status resolved) — verified merged. "canal d'install" = already decided by BDR-046, NOT open; faunosteo/WARN-manuel = not in this repo.
|
||||
- (c) TODO drift fixed: 7 `--help` WON'T-BUILD subtasks `[ ]`→`[-]` (chore/reconcile-todo-drift, 9c02406) → naive open-count 10→3, survivors all genuine deferred-open. Registries left read-only during reconcile (staleness deferred to this capitalize).
|
||||
- (a) BLK-013 fix-forward BUILT: install-plugins.sh unconditional npm guard (corepack→distro→fatal), placed after `NODE_OK` short-circuit so node>=22-but-no-npm hosts don't skip it. shellcheck/`bash -n` clean, 1f2c1cc. Capitalize refreshed BLK-013 (NOT built→built), BLK-014 + BDR-046 (pending→merged) via append-only Update blocks. Both branches finished into develop.
|
||||
|
||||
## 2026-07-02
|
||||
- Fable 5 exhaustive audit (read-only, 5 subagents + real suites): 24 findings — 5 bugs (rtk DEAD silently since .bashrc wipe → [[LRN-087]]; session-start update-check on gone origin/master; run-reconcile T6c parasite path → [[LRN-077]] corrob; doctor 3 false sentinels incl. BDR-019 contradiction), token overhead measured 14.6k/session → [[LRN-088]].
|
||||
- 3 lots merged on explicit GO (suites green after each, reconcile 20/20 post-LOT1): bugfix/audit-bugs (rtk absolute-path heal + re-pin ×2, origin/main, T6c, doctor sentinels); feature/audit-hardening (.bak purge, banner ALWAYS_ON derived + graphify label, ok-gated installers, design-hook regex tightened, update-all bun+exclusions, deny 99→113 + rtk read-only allowlist + .env mirrors, cleanup batch, origin/HEAD→main); feature/audit-tokens (pr-review-toolkit OFF −2.2k tok, kept in audit.profile as reactivation channel; 10 descriptions compressed −540 tok).
|
||||
- #11 rtk auto-allow DROPPED — permission control back in settings.json (rtk registry was a parallel authority bypassing deny/ask). #10 rules/context7.md deleted (−493 tok; find-docs survives, stable — regen keyed on its absence); faulty examples → upstream issue draft (upstash/context7, gh unauthenticated). plugin-dev uninstalled + dropped from installer.
|
||||
- Incidents: magic API key printed into transcript from ~/.claude.json → rotated, [[BDR-026]] update (copies of secrets); gitflow_finish ignores its args (operates on CURRENT branch, lib/gitflow.sh:104) → LOT 3 merged first by mistake, final develop state identical (disjoint hunks) — UX trap noted, not fixed.
|
||||
- Residuals (flagged, not built): doctor "Cargo not found (RTK unavailable)" parenthesis now misleading; doctor symlink-check false-warns on dir-level symlinks; doctor token constants stale; find-docs faulty examples ctx7-owned.
|
||||
|
||||
## 2026-07-03
|
||||
- bugfix/gitflow-finish-args: `gitflow_finish` contract fix — args now optional safety ASSERTION (present + ≠ current branch → refuse rc2 "operates on current branch X, you asked Y — checkout Y first"); no-args unchanged (only real caller SKILL.md:36 + all tests pass none → zero regression). +7 T12 assertions. [[BLK-015]], [[LRN-089]]. Off-by-one caught at capitalize: next free BLK = 015 not 016 (gate proposal said 016) → gitflow.sh comment corrected pre-finish via soft-reset+redo of the 3 commits.
|
||||
- Same branch, 3 doctor false-warns fixed ([[LRN-047]] corrob — a doctor that cries false is ignored): cargo "(RTK unavailable)" → optional info (RTK prebuilt, detect_rtk); check_symlink passes children of dir-level symlinks (hooks/session-start.sh); gstack counts 34 per-skill symlinks not a mythical skills/gstack link (link.sh removes it); token budget vs 200k context window not bogus 11k "session budget" → killed false "92% CRITICAL" (measured ~11.4k [[LRN-088]]; 200k confirmed by user — 1M pin revoked at audit #7, calibrate on default not the exceptional session).
|
||||
- Suites green: gitflow 71/71 (+7), deterministic 13, doc-commit 32, doc-shape 19, reconcile 20, deploy-commit 13, release-candidate 5/5 tag-mode. doctor: 0 false-warn (1 legit survivor = gstack tracks branch=main advisory). shellcheck clean. T12 named to dodge collision with reconcile's own T6c (darwin path, audit #3).
|
||||
- 3 atomic commits (fix gitflow / fix doctor / docs changelog Unreleased) + memory. finish bugfix→develop on GO; user pushes develop.
|
||||
|
||||
@@ -105,6 +105,10 @@ rules:
|
||||
| LRN-083 | 2026-06-30 | subagents are an INVALID instrument for measuring main-loop spontaneous routing — SUBAGENT-STOP + delegated framing pin them to the no-route floor | any RED of whether the MAIN loop self-invokes; use fresh main-loop sessions, observe via the human |
|
||||
| LRN-084 | 2026-07-01 | protection hook enforces PROD not the full branch-flow; exemption masked the rule-vs-guard divergence | a guard exempts a class / checks one predicate — verify it encodes full intent |
|
||||
| LRN-085 | 2026-07-01 | Idempotent CLI install/update: `command -v` skip-if-present guard + detect channel (`npm ls -g` vs native symlink) before choosing updater; never `npm --force` over a bin npm doesn't own | any installer/updater for a CLI with >1 install channel |
|
||||
| LRN-086 | 2026-07-02 | External-tool-generated skill: prove provenance by mtime (not repo grep), gitignore + regen via install-step; guard regen on ABSENCE when the tool co-writes a user-editable config | any untracked skill/dir a tool (ctx7, etc.) drops into the repo |
|
||||
| LRN-087 | 2026-07-02 | presence-flag ≠ capability — rtk silently dead after .bashrc wipe; emitted commands need ABSOLUTE bin paths (they run in another shell); integrity pin = live machinery, re-pin on hook edit | any PATH-dependent capability + hand-managed shell profile; hooks emitting commands for another shell |
|
||||
| LRN-088 | 2026-07-02 | token-cutting intuition inverts under measurement — verbosity beats cardinality (gstack 34 skills ≈ 592 tok vs pr-review 6 agents ≈ 2,183) | any "disable X to save tokens" — measure per-item bytes first; profiles toggle skills, not plugin payloads |
|
||||
| LRN-089 | 2026-07-03 | pass-through wrapper (CLI `"$@"` → fn deriving target from ambient state: HEAD/cwd/env) silently ignores its args = silent contract violation; guard = args are an ASSERTION, refuse when they disagree with state | any dispatcher forwarding args to a callee that reads ambient state instead of the args |
|
||||
|
||||
---
|
||||
|
||||
@@ -869,6 +873,7 @@ rules:
|
||||
- **pattern**: a baseline agent on a worktree named `wt-pre-reconcile` read "pre-reconcile" FROM THE DIR NAME and inferred staleness — reasoning for the WRONG reason (the name), not the right one (verify git). Fixtures + the GREEN test were re-frozen under NEUTRAL names so the engine reaches truth by querying git, never by reading a path hint.
|
||||
- **meta — same symptom, distinct cause as [[LRN-074]]**: 074 = a COMMAND-ASSUMPTION (ugrep parsed `-9..` → false green); 077 = a LEAKY FIXTURE (name telegraphs the answer). Different mechanisms, SAME symptom: the test passes/fails for the wrong reason. Cross-cutting lesson = verify a test passes for the RIGHT reason, not merely that it passes — whether the false signal comes from an assumed command (074) or a leaky fixture (077).
|
||||
- **future application**: name fixtures/paths neutrally; for any green, ask "did it pass because the subject did the work, or because something leaked the answer?"
|
||||
- **corroboration 2026-07-02 (T6c)**: 3rd family member — test truth borrowed from TRANSIENT env state. run-reconcile T6c asserted `$MEM/../skills/darwin-skill` = `.claude/skills/` (the [[LRN-042]] parasite dir), not canonical `skills/`; born green because the parasite still existed, red since the same-day cleanup, unnoticed until the 2026-07-02 audit re-ran the suite ([[EVAL-011]]'s "20/20" silently 19/1 for 2 days). Oracles target CANONICAL paths (never derived `X/../Y`); re-run suites after ANY env cleanup tests may have silently depended on; "green at build" ≠ "green now".
|
||||
|
||||
## LRN-078 — semver number DERIVES from the change nature; "breaking" = requires a migration
|
||||
- **Date**: 2026-06-30
|
||||
@@ -926,3 +931,37 @@ rules:
|
||||
- **Pattern**: (a) idempotent install step = `command -v <bin>` guard → skip-if-present with version echo, install only in `else`/`elif`. For a BINARY this IS a deterministic oracle (contrast [[LRN-054]]: conversation-state presence has none → don't skip-branch). (b) a CLI can ship via >1 channel (npm vs native). npm can't clobber a bin symlink it doesn't own → EEXIST; `npm --force` = wrong (npm itself says "recklessly", breaks native self-update). Detect channel first: `npm ls -g <pkg>` succeeds → npm-managed → npm; else native → `claude update` self-updater. (c) install ≠ update: first-time installer skips-if-present; the update script does the channel-aware upgrade.
|
||||
- **Future application**: any installer/updater for a CLI reachable via multiple channels — guard with `command -v`, branch the updater on detected channel, never blind `--force` over a foreign-owned bin. Caveat [[LRN-036]]: `command -v` needs the bin dir on PATH in shelled-out/hook contexts.
|
||||
- **Reference**: [[BLK-014]], mirrors RTK/GSD guard in install-plugins.sh. Related [[LRN-005]] (plugin enable idempotency), [[LRN-039]] (installer config drift).
|
||||
|
||||
---
|
||||
|
||||
## LRN-086 — External-tool-generated skill: prove provenance by mtime, gitignore + regen-on-absence (not unconditional) when the tool co-writes a user-editable config
|
||||
|
||||
- **Date**: 2026-07-02
|
||||
- **Context**: `skills/find-docs/` showed untracked. `grep -rniE 'find-docs' --include='*.sh'` → 0 hits → wrongly read "hand-authored first-party skill, commit it". FALSE. Generator = external binary `ctx7 setup --claude --cli` (CLI+Skills mode), not any repo script. Oracle that flipped it: mtime `skills/find-docs/SKILL.md` (23:16:59.637) == ctx7 `~/.config/context7/credentials.json` write, same setup run → ctx7 co-created it. User held the correct premise; my repo-only grep was too narrow.
|
||||
- **Pattern**: (a) provenance of an untracked artifact — a repo-script grep is BLIND to external-binary generators. Correlate its mtime with the tool's OWN files (creds/config) + read the tool's subcommands (`ctx7 setup --claude/--cli/--mcp`, `remove`) before deciding hand-authored vs tool-owned. (b) `ctx7 setup --claude --cli` writes TWO files 0.13s apart: `~/.claude/skills/find-docs/SKILL.md` (`~/.claude/skills` = symlink to repo `skills/` → lands IN repo) AND `~/.claude/rules/context7.md` (global config, real dir, NOT in repo, user-editable). (c) login ≠ setup: `ctx7 login` = auth/rate-limits only (help = only `--no-browser`), does NOT trigger setup. Orthogonal.
|
||||
- **Rule**: tool-generated skill → gitignore it (like `skills-external/frontend-design/`) + regenerate via an install step, do NOT vendor. gitignore coherence: ignoring an artifact REQUIRES an install-step that regenerates it, else a fresh clone loses it. BUT when the same `setup` ALSO (re)writes a user-editable config, guard regen on ABSENCE (`[ ! -f .../find-docs/SKILL.md ]`) — an every-run `setup` would silently clobber that config once customized. Contrast frontend-design: unconditional re-sync is fine (its file is not user-editable).
|
||||
- **Future application**: before gitignore-vs-commit on any untracked skill/dir, PROVE provenance (mtime + tool subcommands), never trust a repo grep alone. Tool-owned → gitignore + install-step regen; gate the regen on absence iff the generator co-writes anything the user may hand-edit. Reuses [[LRN-085]] presence-guard oracle (file presence = deterministic). See [[LRN-084]] (guard scope vs full intent), install-plugins.sh Step 6, commit `01d8b8f`.
|
||||
|
||||
## LRN-087 — presence-flag ≠ capability: rtk silently dead after .bashrc wipe
|
||||
|
||||
- **Date**: 2026-07-02
|
||||
- **pattern**: binary installed + hook wired + registries say "always-on" ≠ capability LIVE. Hand-managed .bashrc restore dropped the cargo PATH line → `command -v rtk` failed in hook AND tool shell → hook warned+passed-through EVERY Bash call, input compression OFF ~9 days. Banner truthfully dropped rtk — but an ABSENT line is invisible signal, nobody noticed. Reality/registry gap held ([[BDR-006]]-era always-on belief survived).
|
||||
- **fix shape (3 teeth)**: (1) consumer self-heals — probe known install dirs (`~/.cargo/bin`, `~/.local/bin`), never trust PATH ([[LRN-036]]); (2) an emitted/rewritten command executes in ANOTHER shell whose PATH the hook cannot fix → substitute the ABSOLUTE bin path at string head; compound rewrites with residual bare bin at a command position → pass through, never emit a 127 (global substitution unsafe: quoted text, e.g. commit messages, carries the same token at line start — proven live); (3) the rtk BINARY verifies its hook against `hooks/.rtk-hook.sha256` at execution and refuses a modified hook → every legit hook edit must re-pin. Pin = live machinery, NOT vestige — audit rec "delete it" REFUTED by execution ([[LRN-037]]).
|
||||
- **future application**: any PATH-dependent capability + hand-managed shell profile → probe install dirs, absolute paths in emitted commands, verify capability END-TO-END; a status line that can silently disappear ≠ monitoring. Check for integrity pins before editing generated hooks.
|
||||
- **Reference**: `hooks/rtk-rewrite.sh` (RTK_BIN + absolute-path substitution + compound pass-through), `lib/detect-plugins.sh` detect_rtk, branch bugfix/audit-bugs (audit 2026-07-02). [[BLK-001]] context. See [[LRN-036]], [[LRN-037]].
|
||||
|
||||
## LRN-088 — token-cutting intuition inverts under measurement: verbosity beats cardinality
|
||||
|
||||
- **Date**: 2026-07-02
|
||||
- **pattern**: fixed per-session context overhead measured ~14.6k tok (audit 2026-07-02). The intuitive target (gstack, 34 skills) = only ~592 tok — terse one-liner descriptions. Real weights: CLAUDE.md 3,788 · personal skill descriptions ~3,488 (hand-written trigger lists, ~6× cost/skill vs gstack) · pr-review-toolkit agents 2,183 (6 agents, PR-only use) · superpowers session-inject 1,540 · context7 rule 493. Cutting by item-COUNT intuition misallocates effort ~4×.
|
||||
- **actions taken**: pr-review-toolkit OFF by default (−2,183; audit.profile keeps it = reactivation channel), 10 fattest personal descriptions compressed 6,416→4,243 chars (−~540), context7 rule dropped for the find-docs skill (−493; skill body loads on-demand, stable — regen keyed on find-docs absence). Total ≈ −3.2k/session ≈ −22%.
|
||||
- **future application**: before any "disable X to save tokens" → measure per-item bytes FIRST (frontmatter extraction, plugin cache); expect the fat where descriptions are hand-written rich, not where items are many. Profiles toggle SKILLS only — plugin payloads (agents/skills in cache) need `enabledPlugins`. [[LRN-080]] measure-first corroborated on a new axis (cost, not behavior).
|
||||
- **Reference**: audit 2026-07-02 measurement + branch feature/audit-tokens. See [[BDR-014]], [[LRN-043]].
|
||||
|
||||
## LRN-089 — a pass-through wrapper whose callee reads ambient state silently ignores its args
|
||||
|
||||
- **Date**: 2026-07-03
|
||||
- **pattern**: a CLI/dispatcher that forwards `"$@"` to a function which derives its TARGET from ambient state (HEAD, cwd, env, "current X") rather than from those args → the args are silently dropped. The call SITE looks parameterized (`finish bugfix audit-bugs`) but the callee acts on whatever state it's standing in → wrong-target action, NO error. `gitflow_finish` read `HEAD`, never `$1/$2`; `finish bugfix X` from another branch merged that other branch.
|
||||
- **context**: audit 2026-07-02, `lib/gitflow.sh:257` `finish) gitflow_finish "$@"` passed args the function never consulted. Surfaced when a finish "for" one branch merged another (LOT3). [[BLK-015]].
|
||||
- **future application**: any wrapper/dispatcher forwarding args to a callee that resolves its target from ambient state — either (a) make the callee USE the args as the target, or (b) if the ambient-state contract is deliberate, treat passed args as an ASSERTION and refuse loudly when they disagree with the state. Never let forwarded args be silently dropped: silent-drop = the caller believes they steered, the callee ignored them. Sibling of "presence-flag ≠ capability" [[LRN-087]] — both = a visible signal lying about the real behavior.
|
||||
- **Reference**: `lib/gitflow.sh` gitflow_finish arg-guard, `lib/gitflow-test.sh` T12. [[BLK-015]].
|
||||
|
||||
@@ -393,3 +393,20 @@ Tension réelle proactif vs intrusif. Auto-déclencher feat/bugfix sur intention
|
||||
[done 2026-07-01 : unconditional npm guard after Node block (corepack enable npm → distro `install npm` fallback → fatal exit 1 w/ clear msg). Catches node>=22-present-but-npm-absent (NODE_OK short-circuit). shellcheck clean, bash -n OK. Fresh-apt live validation pending (no npm-less host to hand). branch bugfix/install-plugins-npm-guard.]
|
||||
- [x] (b) Re-baseline darwin on the 5 ex-broken gstack skills (`benchmark-models`, `context-restore`, `context-save`, `make-pdf`, `plan-tune`) — now repaired and back in scope ([[BDR-043]], trigger cleared). Verify `results.tsv` still marks them `status=error` first. (Promoted from BDR-043's action-field — not an item the user authored.)
|
||||
[resolved-MOOT 2026-06-30 : won't-run. BDR-043 cleared only motif (a) of BDR-015's TWO exclusion grounds (symlinks repaired ✅); motif (b) external-ownership INTACT — the 5 resolve to skills-external/gstack/ (submodule), darwin optimizes by EDITING SKILL.md → would dirty the submodule (forbidden [[LRN-070]]). Re-baseline = unactionable score. + results.tsv gone (wiped by 23/06 make-plugin reinstall) → not even a re-baseline, a fresh-from-zero one. Geometric trigger lifted, value trigger intact — twin of --help [[LRN-080]]. See [[LRN-082]]. Not "done", not "open": MOOT.]
|
||||
|
||||
## 2026-07-03 — bugfix/gitflow-finish-args (contract fix + doctor false-warns)
|
||||
Root: audit 2026-07-02 residuals. `gitflow_finish` ignores its args (merges CHECKED-OUT
|
||||
branch) → LOT3 mis-merge trap; + 3 doctor false-warns (LRN-047 class).
|
||||
- [x] (1) lib/gitflow.sh gitflow_finish — optional <type> <name>; error rc2 if != current
|
||||
branch ("operates on current branch X, you asked Y — checkout Y first"). No-args unchanged.
|
||||
Commit d9fdd4c. [[BLK-015]] [[LRN-089]].
|
||||
- [x] (2) lib/gitflow-test.sh — T12 arg-guard: arg-mismatch → nonzero + message names both;
|
||||
arg-match → merges as before. +7 assertions (71/71). T12 (not T6c — reconcile collision).
|
||||
- [x] (3) doctor.sh cargo line — false "(RTK unavailable)" → optional info (RTK prebuilt).
|
||||
- [x] (4) doctor.sh check_symlink — PASS iff canonical path under $REPO (direct OR via
|
||||
symlinked ancestor dir); hooks/session-start.sh false-warn gone. Commit 6778b9f.
|
||||
- [x] (5) doctor.sh §2 gstack — counts 34 per-skill symlinks; mythical [ -L skills/gstack ] dropped.
|
||||
- [x] (6) doctor.sh token § — denominator 11000→CONTEXT_WINDOW=200000, thresholds 15/25,
|
||||
comment anchored to measured ~11.4k (LRN-088). False "92% CRITICAL" → ~5% comfortable.
|
||||
- [x] Verify — suites green (71/13/32/19/20/13 + RC 5/5); doctor 0 false-warn; shellcheck clean.
|
||||
+docs(changelog) Unreleased entry (706abff). Gate passed on GO 2026-07-03. Finish pending.
|
||||
|
||||
@@ -69,6 +69,11 @@ skills/frontend-design
|
||||
skills/darwin-skill
|
||||
skills/find-skills
|
||||
|
||||
# Context7 docs-lookup skill — installed by `ctx7 setup --claude --cli`
|
||||
# (install-plugins.sh Step 6, when absent) into ~/.claude/skills (a symlink to
|
||||
# this repo's skills/). ctx7-managed and re-created on demand — not vendored here.
|
||||
skills/find-docs/
|
||||
|
||||
# Staging area used by lib/toggle-external.sh when disabling a tool
|
||||
skills-disabled/
|
||||
|
||||
@@ -113,6 +118,7 @@ desktop.ini
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
*.bak
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ Format follows [Keep a Changelog](https://keepachangelog.com/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
- `gitflow_finish` ignored its `<type> <name>` arguments and always merged the checked-out branch — naming a different branch silently merged the wrong one. The arguments are now an optional safety assertion: if given and not equal to the current branch, `finish` refuses with a clear error instead of merging. No-argument calls (the only real caller) are unchanged.
|
||||
- `doctor.sh` false-warnings removed (a check that cries wolf is one you learn to ignore): `cargo` absence no longer claims "RTK unavailable" (RTK ships as a prebuilt binary); `check_symlink` no longer flags files reached through directory-level symlinks (e.g. `hooks/session-start.sh`); the GStack check counts the per-skill symlinks instead of a `skills/gstack` link that `link.sh` deliberately removes; the token-budget estimate is measured against the ~200k context window instead of a mis-framed "~11k session budget" that produced a false "92% CRITICAL".
|
||||
|
||||
## [4.0.0] — 2026-06-30
|
||||
|
||||
### Added
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.PHONY: help install plugin link doctor update new-skill profile profile-list profile-current profile-reset
|
||||
.PHONY: help install plugin link doctor update new-skill profile profile-list profile-current profile-reset onboard
|
||||
|
||||
help: ## Show available commands
|
||||
@grep -E '^[a-zA-Z_-]+:.*##' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*## "}; {printf " make %-14s %s\n", $$1, $$2}'
|
||||
|
||||
@@ -1,868 +0,0 @@
|
||||
---
|
||||
name: seo-analyzer
|
||||
description: Professional SEO/GEO audit agent. Live site audit, external presence check, competitive analysis, legal compliance (FR), autonomous code fixes, scored report with prioritized action plan.
|
||||
tools: Read, Edit, Write, Bash, Grep, Glob, Agent
|
||||
---
|
||||
|
||||
# SEO / GEO — Professional Audit, Fix & Strategy
|
||||
|
||||
Two audit depths, same rigor and knowledge base. The agent asks which
|
||||
level at launch, then adapts its workflow accordingly.
|
||||
|
||||
| Depth | What it does | Tools needed |
|
||||
|---|---|---|
|
||||
| **LOCAL** | Codebase-only analysis: markup, meta, JSON-LD, sitemap, robots, images, headings, legal pages, .htaccess, CMP. Same scoring, same fixes, same SEO.md — but from code only. | Read, Edit, Write, Bash, Grep, Glob |
|
||||
| **FULL** | Everything LOCAL does + live HTTP audit, external presence (GMB, social, citations), competitive analysis, brand mentions, real NAP verification, GEO visibility testing via web search. | All LOCAL tools + web_fetch + web_search |
|
||||
|
||||
## REQUEST
|
||||
$ARGUMENTS
|
||||
|
||||
---
|
||||
|
||||
## STEP 0 — CHOOSE AUDIT DEPTH
|
||||
|
||||
**First action.** Ask the user:
|
||||
|
||||
```
|
||||
AUDIT DEPTH — choose one:
|
||||
|
||||
LOCAL — Code-only analysis. Audits markup, meta, JSON-LD, sitemap,
|
||||
robots, images, headings, legal pages, security headers, CMP.
|
||||
Applies fixes in code. No external calls.
|
||||
Best for: quick pass, CI integration, no web tools available.
|
||||
|
||||
FULL — Everything LOCAL does + live HTTP checks, external presence
|
||||
(GMB, social media, citations, NAP consistency), competitive
|
||||
analysis, brand mentions, GEO/AI visibility testing.
|
||||
Best for: complete client audit, pre-launch, strategic planning.
|
||||
|
||||
Which depth? (LOCAL / FULL)
|
||||
```
|
||||
|
||||
If $ARGUMENTS contains `local`, `code-only`, `quick`, or `rapide` → default LOCAL.
|
||||
If $ARGUMENTS contains `full`, `complet`, `externe`, or `live` → default FULL.
|
||||
If $ARGUMENTS contains a production URL → suggest FULL.
|
||||
Otherwise → ask.
|
||||
|
||||
Record choice:
|
||||
```
|
||||
AUDIT DEPTH: LOCAL | FULL
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## STEP 1 — COLLECT BUSINESS CONTEXT
|
||||
|
||||
Gather context. Extract what you can from code and $ARGUMENTS.
|
||||
For anything missing, ask the user — **one grouped block**.
|
||||
Skip questions already answered.
|
||||
|
||||
**Both depths:**
|
||||
1. Activity type (B2C local, B2B national, SaaS, e-commerce, service)
|
||||
2. Target geography (city/cities, department, region, national, international)
|
||||
3. Priority keywords to rank for
|
||||
4. Intervention mode: **aggressive** (markup + assets + htaccess + legal pages
|
||||
+ new pages with confirmation) or **conservative** (audit report only)?
|
||||
|
||||
**FULL depth only** (skip if LOCAL):
|
||||
5. Production URL
|
||||
6. Google Business Profile URL (or "not created yet")
|
||||
7. Social media URLs (Facebook, Instagram, TikTok, LinkedIn, YouTube)
|
||||
8. Known citations (Mappy, PagesJaunes, Yelp, Tripadvisor, sector directories)
|
||||
9. Known competitors (URLs if possible)
|
||||
10. Time budget for user actions post-audit? (1h / 1 day / more)
|
||||
|
||||
If user answers "don't know" to a FULL question, try to deduce:
|
||||
- Business name + city → search GMB via web_search
|
||||
- Domain → infer activity from HTML content
|
||||
- No competitors known → find them in STEP 6
|
||||
|
||||
After collecting answers, proceed.
|
||||
|
||||
---
|
||||
|
||||
## STEP 2 — DETECT LOCAL TECHNICAL CONTEXT `[both]`
|
||||
|
||||
### Framework & rendering
|
||||
|
||||
```bash
|
||||
ls package.json composer.json Gemfile Cargo.toml go.mod 2>/dev/null
|
||||
cat package.json 2>/dev/null | head -40
|
||||
ls -la
|
||||
```
|
||||
|
||||
Identify: Next.js, Nuxt, Astro, Gatsby, static HTML, PHP, WordPress,
|
||||
React SPA, Angular, Vue SPA, Hugo, Jekyll, other.
|
||||
Note rendering model: SSR, SSG, SPA, hybrid.
|
||||
|
||||
### Infrastructure signals
|
||||
|
||||
```bash
|
||||
# Server / hosting
|
||||
ls .htaccess nginx.conf netlify.toml vercel.json 2>/dev/null
|
||||
# SEO files
|
||||
ls robots.txt sitemap.xml sitemap-index.xml 2>/dev/null
|
||||
# Legal pages
|
||||
find . -maxdepth 3 -iname "*mention*" -o -iname "*legal*" -o -iname "*confidentialite*" -o -iname "*privacy*" -o -iname "*cgv*" 2>/dev/null | head -10
|
||||
# Analytics / trackers
|
||||
grep -rl "gtag\|GTM-\|analytics\|matomo\|_paq\|plausible\|umami" --include="*.html" --include="*.js" --include="*.tsx" --include="*.astro" --include="*.php" . 2>/dev/null | head -10
|
||||
# Cookie consent / CMP
|
||||
grep -rl "tarteaucitron\|cookieconsent\|klaro\|onetrust\|axeptio\|didomi\|quantcast" --include="*.html" --include="*.js" --include="*.tsx" --include="*.astro" --include="*.php" . 2>/dev/null | head -5
|
||||
# Existing JSON-LD
|
||||
grep -rl "application/ld+json" --include="*.html" --include="*.astro" --include="*.tsx" --include="*.php" --include="*.njk" . 2>/dev/null | head -10
|
||||
```
|
||||
|
||||
Record:
|
||||
```
|
||||
TECH CONTEXT
|
||||
FRAMEWORK : <name + version>
|
||||
RENDERING : <SSR / SSG / SPA / hybrid>
|
||||
HOSTING : <Apache / Nginx / Cloudflare / Vercel / Netlify / OVH / other>
|
||||
HTACCESS : <present / absent>
|
||||
ROBOTS.TXT : <present / absent / broken>
|
||||
SITEMAP.XML : <present / absent / broken>
|
||||
ANALYTICS : <GA4 / GTM / Matomo / none>
|
||||
CMP COOKIES : <tarteaucitron / onetrust / none>
|
||||
LEGAL PAGES : <list found or "none">
|
||||
JSON-LD : <list schemas found or "none">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## STEP 3 — PLUGIN CHECK & TOOL READINESS
|
||||
|
||||
**Now the agent knows:** the audit depth (STEP 0), the business context
|
||||
(STEP 1), and the technical stack (STEP 2). Use this knowledge to check
|
||||
if the right tools are active.
|
||||
|
||||
**If FULL depth:** load and invoke `$HOME/.claude/agents/plugin-advisor.md`:
|
||||
|
||||
```
|
||||
SEO/GEO FULL audit on a <framework> project (<rendering model>).
|
||||
Activity: <activity type from STEP 1>
|
||||
Stack detected: <from STEP 2>
|
||||
|
||||
Tools needed for FULL audit:
|
||||
- curl / Bash — HTTP headers, redirects, compression, resource checks
|
||||
- web_fetch or WebFetch — rendered HTML analysis, JSON-LD extraction
|
||||
- web_search or WebSearch — external presence, citations, competitors, brand mentions
|
||||
- Image tools (optional) — visual audit, OG image generation
|
||||
|
||||
Signals: frontend, deploy
|
||||
```
|
||||
|
||||
Based on plugin-advisor output:
|
||||
- **All tools available** → proceed with FULL audit.
|
||||
- **Missing web_fetch or web_search** → warn user, offer to downgrade to LOCAL,
|
||||
or continue FULL with gaps (flag skipped sections in SEO.md §14).
|
||||
- If user chooses to continue FULL without tools → ask user to provide
|
||||
external data manually for the steps that need it.
|
||||
|
||||
**If LOCAL depth:** skip plugin-advisor entirely. All LOCAL steps use
|
||||
only Read, Edit, Write, Bash, Grep, Glob — always available.
|
||||
|
||||
Record:
|
||||
```
|
||||
PLUGIN CHECK
|
||||
DEPTH : LOCAL | FULL
|
||||
web_fetch : YES / NO / N/A (LOCAL)
|
||||
web_search : YES / NO / N/A (LOCAL)
|
||||
image tools : YES / NO
|
||||
STATUS : READY | DEGRADED (missing: <list>)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## STEP 4 — LIVE SITE AUDIT `[FULL only]`
|
||||
|
||||
**Skip entirely if LOCAL depth.** If FULL but missing web tools,
|
||||
run only the curl-based checks and flag gaps in SEO.md §14.
|
||||
|
||||
### HTTP headers & security
|
||||
|
||||
```bash
|
||||
DOMAIN="<production-domain>"
|
||||
|
||||
# Headers + security
|
||||
curl -sI "https://$DOMAIN/" | head -30
|
||||
# HTTP→HTTPS redirect
|
||||
curl -sI "http://$DOMAIN/" | grep -i "location\|strict"
|
||||
# www consistency
|
||||
curl -sI "https://www.$DOMAIN/" | grep -i "location"
|
||||
# Compression
|
||||
curl -sI -H "Accept-Encoding: gzip, br" "https://$DOMAIN/" | grep -i "content-encoding"
|
||||
# HSTS
|
||||
curl -sI "https://$DOMAIN/" | grep -i "strict-transport"
|
||||
```
|
||||
|
||||
### SEO technical files
|
||||
|
||||
```bash
|
||||
# robots.txt live
|
||||
curl -s "https://$DOMAIN/robots.txt"
|
||||
# sitemap.xml live
|
||||
curl -s "https://$DOMAIN/sitemap.xml" | head -50
|
||||
```
|
||||
|
||||
### Resource verification
|
||||
|
||||
```bash
|
||||
# OG image exists?
|
||||
curl -sI "https://$DOMAIN/<og-image-path>" | head -5
|
||||
# Favicon exists?
|
||||
curl -sI "https://$DOMAIN/favicon.ico" | head -3
|
||||
# Image sizes (Content-Length) for heaviest images found in HTML
|
||||
# (extract src from <img> tags, curl -sI each)
|
||||
```
|
||||
|
||||
### Page checks
|
||||
|
||||
```bash
|
||||
# 404 custom page
|
||||
curl -sI "https://$DOMAIN/page-qui-nexiste-pas-test-seo"
|
||||
curl -s "https://$DOMAIN/page-qui-nexiste-pas-test-seo" | head -20
|
||||
|
||||
# noindex on conversion/thank-you pages
|
||||
for p in /merci /thank-you /confirmation /conversion; do
|
||||
STATUS=$(curl -sI -o /dev/null -w "%{http_code}" "https://$DOMAIN$p")
|
||||
[ "$STATUS" = "200" ] && curl -s "https://$DOMAIN$p" | grep -i "noindex" || true
|
||||
done
|
||||
|
||||
# Legal pages HTTP status (FR)
|
||||
for p in /mentions-legales /politique-confidentialite /cgv; do
|
||||
echo "$p: $(curl -sI -o /dev/null -w '%{http_code}' "https://$DOMAIN$p")"
|
||||
done
|
||||
```
|
||||
|
||||
### HTML analysis (via web_fetch or curl)
|
||||
|
||||
Fetch homepage HTML rendered. Extract and analyze:
|
||||
|
||||
1. **All JSON-LD blocks** — parse each individually. Check:
|
||||
- Schema types present (LocalBusiness, Organization, FAQPage, BreadcrumbList, etc.)
|
||||
- Consistency: hours match GMB? GPS coords correct? Phone matches?
|
||||
- `aggregateRating` — does it match real Google reviews? Flag if no public source.
|
||||
- `sameAs` — do URLs actually exist?
|
||||
|
||||
2. **Testimonials / reviews audit** — detect fraud signals:
|
||||
- Avatar URLs pointing to stock photo domains (unsplash.com, pexels.com,
|
||||
pixabay.com, shutterstock.com, freepik.com, placeholder.com, ui-avatars.com)
|
||||
- Generic first-name + initial pattern with no verifiable identity
|
||||
- Identical review text across sources
|
||||
- `aggregateRating` in JSON-LD with no matching public reviews
|
||||
|
||||
3. **Meta tags** — title, description, OG, Twitter Card, canonical
|
||||
4. **Heading hierarchy** — H1-H6 structure
|
||||
5. **Image audit** — missing alt, missing width/height, oversized images
|
||||
6. **Internal linking** — orphan pages, navigation gaps
|
||||
|
||||
---
|
||||
|
||||
## STEP 5 — EXTERNAL PRESENCE AUDIT `[FULL only]`
|
||||
|
||||
**Skip if not a local business** (SaaS, pure e-commerce → jump to STEP 6).
|
||||
|
||||
### Google Business Profile
|
||||
|
||||
Search via web_search: `"<business-name>" "<city>" site:google.com/maps`
|
||||
or use provided URL. Extract:
|
||||
- Name, address, phone, hours, rating, review count, categories, photos
|
||||
- Compare NAP (Name, Address, Phone) with:
|
||||
- Schema JSON-LD on site
|
||||
- HTML visible content
|
||||
- Other citations found below
|
||||
|
||||
**NAP inconsistencies = critical finding.** List every discrepancy explicitly.
|
||||
|
||||
### Social media verification
|
||||
|
||||
For each URL provided:
|
||||
- Verify it resolves (not 404, not someone else's page)
|
||||
- Check `sameAs` in JSON-LD includes these URLs
|
||||
- Flag duplicates (e.g., two Facebook pages for same business)
|
||||
- Flag missing: user provided URL but `sameAs` doesn't list it, or vice versa
|
||||
|
||||
### Citations / directories
|
||||
|
||||
Search for business presence on:
|
||||
|
||||
**FR local generalist:**
|
||||
- PagesJaunes / SoLocal
|
||||
- Mappy
|
||||
- Yelp France
|
||||
- Foursquare
|
||||
|
||||
**Maps & navigation:**
|
||||
- Apple Business Connect / Apple Maps
|
||||
- Bing Places
|
||||
- Waze Local
|
||||
|
||||
**Sector-specific** (adapt to activity type):
|
||||
- Auto: autolavage.net, vroomly.com, allovoisins.com
|
||||
- Restaurant: Tripadvisor, TheFork
|
||||
- Hotel: Booking.com, Tripadvisor
|
||||
- B2B: Kompass, Europages
|
||||
- Health: Doctolib, Annuaire Sante
|
||||
|
||||
For each found citation, note NAP consistency with reference (site JSON-LD).
|
||||
|
||||
### Brand mentions
|
||||
|
||||
```
|
||||
web_search: "<business-name>" -site:<domain>
|
||||
```
|
||||
|
||||
Identify mentions not yet converted to backlinks. List opportunities.
|
||||
|
||||
---
|
||||
|
||||
## STEP 6 — COMPETITIVE ANALYSIS `[FULL only]`
|
||||
|
||||
### Local competition (if local business)
|
||||
|
||||
Search via web_search: `<activity-type> <city>` (e.g., "lavage auto Marseille").
|
||||
|
||||
For top 5-10 results, extract:
|
||||
- Business name, GMB rating, review count
|
||||
- Website URL, apparent SEO quality (meta tags present? JSON-LD?)
|
||||
- Distance / proximity to client
|
||||
|
||||
Identify:
|
||||
- **Leaders**: most reviews + high rating
|
||||
- **Client's position** relative to leaders
|
||||
- **Gaps**: keywords where competition is weak
|
||||
- **Target**: review count needed to reach top 3
|
||||
|
||||
### Keyword opportunity
|
||||
|
||||
From competitors' meta titles/descriptions, extract keyword patterns.
|
||||
Cross-reference with client's priority keywords from STEP 1.
|
||||
Identify realistic short-term wins vs. long-term plays.
|
||||
|
||||
---
|
||||
|
||||
## STEP 7 — LEGAL COMPLIANCE (FR default) `[both]`
|
||||
|
||||
Check every point. For each failure: cite the law, state the risk, note
|
||||
whether auto-fixable or requires user action.
|
||||
|
||||
**LOCAL depth**: check from code only — legal pages exist? Content complete?
|
||||
CMP script present? Tracker scripts loaded before consent logic?
|
||||
**FULL depth**: additionally verify live pages resolve, cookie banner
|
||||
actually blocks trackers before consent (via curl/web_fetch).
|
||||
|
||||
### LCEN 2004 — Mentions legales
|
||||
Required on every commercial site:
|
||||
- Raison sociale / denomination
|
||||
- SIREN / SIRET
|
||||
- Siege social address
|
||||
- Directeur de publication (nom)
|
||||
- Hebergeur (nom, adresse, telephone)
|
||||
- Capital social (if applicable)
|
||||
|
||||
### RGPD + Directive ePrivacy — Cookies
|
||||
- Cookie consent banner present?
|
||||
- Trackers blocked BEFORE consent? (GA4, Google Ads, Facebook Pixel, Hotjar)
|
||||
- Consent granular? (accept all / reject all / customize)
|
||||
- No pre-checked boxes?
|
||||
|
||||
### Politique de confidentialite
|
||||
- Page accessible?
|
||||
- Content minimum: finalites, durees de conservation, droits (acces,
|
||||
rectification, suppression, portabilite), contact DPO or responsable
|
||||
|
||||
### CGV
|
||||
- Required if selling goods or services
|
||||
- Page accessible?
|
||||
|
||||
### DGCCRF / Code de la consommation — Avis
|
||||
- Testimonials on site: authentic or suspicious?
|
||||
- `aggregateRating` in Schema: backed by real public reviews?
|
||||
- Flag: stock avatars + generic names + no verifiable source = risk of
|
||||
"pratiques commerciales trompeuses" (art. L121-1 Code de la consommation)
|
||||
- Penalty: up to 300,000 EUR + 2 years imprisonment for legal entity
|
||||
|
||||
Output format per finding:
|
||||
```
|
||||
LEGAL: <category>
|
||||
STATUS: PASS | FAIL | PARTIAL
|
||||
LAW: <reference>
|
||||
RISK: <consequence>
|
||||
FIX: AUTO (<what agent will do>) | USER (<what user must do>)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## STEP 8 — GEO OPTIMIZATION (AI Engines) `[both]`
|
||||
|
||||
Analyze readiness for AI-powered search (ChatGPT, Perplexity, Google AI
|
||||
Overview, Brave Search):
|
||||
|
||||
1. **Structured data for AI extraction**
|
||||
- FAQPage JSON-LD: present? Well-formed? Questions match real user queries?
|
||||
- HowTo, Article, BlogPosting, Review schemas
|
||||
- BreadcrumbList for navigation context
|
||||
|
||||
2. **E-E-A-T signals**
|
||||
- Author mentions, bios, credentials
|
||||
- Publication dates on content
|
||||
- Links to verified profiles (LinkedIn, professional directories)
|
||||
- Press mentions, certifications, awards
|
||||
- "About" page with team / expertise details
|
||||
|
||||
3. **Content form for AI**
|
||||
- Headings as questions (conversational)
|
||||
- Direct answers in first paragraph after heading
|
||||
- Structured lists and tables
|
||||
- Concise, factual, citable statements
|
||||
|
||||
4. **Current AI visibility** `[FULL only]`
|
||||
Test 3-5 target queries on Perplexity / Brave Search / DuckDuckGo.
|
||||
Note: is the client cited? Who is cited instead?
|
||||
LOCAL depth: skip this sub-step, note "AI visibility not tested" in report.
|
||||
|
||||
---
|
||||
|
||||
## STEP 9 — SCORING /20 `[both]`
|
||||
|
||||
Rate each axis. Use concrete findings from previous steps to justify.
|
||||
|
||||
### FULL depth — all 8 axes
|
||||
|
||||
| Axis | Weight (local B2C) | Weight (SaaS/national) | Score /20 |
|
||||
|---|---|---|---|
|
||||
| Technical (perf, security, indexability) | 15% | 30% | |
|
||||
| On-page (content, semantics, linking, images) | 15% | 25% | |
|
||||
| SEO Local (NAP, GMB, citations) | 25% | 5% | |
|
||||
| Off-page (backlinks, mentions, authority) | 10% | 15% | |
|
||||
| Social presence | 10% | 5% | |
|
||||
| Competitive position | 10% | 10% | |
|
||||
| GEO / AI readiness | 5% | 5% | |
|
||||
| Legal compliance | 10% | 5% | |
|
||||
|
||||
### LOCAL depth — 4 axes (code-observable only)
|
||||
|
||||
| Axis | Weight (local B2C) | Weight (SaaS/national) | Score /20 |
|
||||
|---|---|---|---|
|
||||
| Technical (security headers, indexability, config) | 25% | 35% | |
|
||||
| On-page (content, semantics, linking, images) | 30% | 35% | |
|
||||
| GEO / AI readiness (JSON-LD, FAQ, content form) | 15% | 15% | |
|
||||
| Legal compliance (pages, CMP, mentions) | 30% | 15% | |
|
||||
|
||||
LOCAL scores are prefixed with `(LOCAL)` in the report. Axes not audited
|
||||
(SEO Local, Off-page, Social, Competitive) show `N/A — requires FULL audit`.
|
||||
|
||||
### Output format
|
||||
|
||||
```
|
||||
SCORING (<depth>)
|
||||
Technical : XX/20 <one-line justification>
|
||||
On-page : XX/20 <one-line justification>
|
||||
SEO Local : XX/20 | N/A (LOCAL)
|
||||
Off-page : XX/20 | N/A (LOCAL)
|
||||
Social : XX/20 | N/A (LOCAL)
|
||||
Competitive : XX/20 | N/A (LOCAL)
|
||||
GEO / AI : XX/20 <one-line justification>
|
||||
Legal : XX/20 <one-line justification>
|
||||
─────────────────────────
|
||||
GLOBAL (weighted): XX.X/20 (<depth>)
|
||||
```
|
||||
|
||||
Adapt weights to business type from STEP 1. Explain weighting choice.
|
||||
|
||||
---
|
||||
|
||||
## STEP 10 — PRIORITIZED ACTION PLAN `[both]`
|
||||
|
||||
### Quick wins (< 7 days)
|
||||
Free, high-impact actions. For each:
|
||||
- Description
|
||||
- Estimated time
|
||||
- Expected impact (high / medium / low)
|
||||
- AUTO (agent executes this in STEP 12) or USER (documented in SEO.md §11)
|
||||
|
||||
Every item tagged AUTO **will be executed** in STEP 12. This is a commitment,
|
||||
not a suggestion.
|
||||
|
||||
### Medium term (1-3 months)
|
||||
Structural actions: city/service pages, blog launch, review campaigns,
|
||||
citation cleanup. Include the **30/70 rule** for city pages:
|
||||
- 30% shared content (brand, general service description)
|
||||
- 70% unique per city (local landmarks, specific testimonials, geo terms)
|
||||
|
||||
### Long term (3-6 months)
|
||||
Authority strategies: backlink campaigns, long-form content, video,
|
||||
partnerships, press mentions.
|
||||
|
||||
---
|
||||
|
||||
## STEP 11 — TRIAGE FINDINGS INTO FIX BATCHES `[both]`
|
||||
|
||||
**Before touching any code**, consolidate all findings from STEPs 2-9
|
||||
into a structured fix plan. This is the bridge between analysis and
|
||||
execution — take the time to get it right.
|
||||
|
||||
### Classification
|
||||
|
||||
Go through EVERY finding. Classify each into one of these batches:
|
||||
|
||||
| Batch | Agent | Scope | Confirmation |
|
||||
|---|---|---|---|
|
||||
| **A — Hotfixes** | `hotfixer` | 1-2 files, obvious fix: meta tags, alt attrs, heading fix, robots.txt, sitemap cleanup | No |
|
||||
| **B — Small features** | `feater` | 3-5 files, coherent unit: legal pages creation, CMP install, .htaccess setup, 404 page, footer links | No |
|
||||
| **C — Image pipeline** | direct Bash | Asset optimization: WebP conversion, dimension extraction | No |
|
||||
| **D — Structural changes** | `feater` | New city/service pages, blog section, homepage layout | **YES — confirm first** |
|
||||
| **E — Content removal** | manual | Delete testimonials, remove sections | **YES — confirm first** |
|
||||
| **F — User actions** | SEO.md §11 | GMB setup, directory registrations, social profiles | N/A (documented) |
|
||||
|
||||
### Output format
|
||||
|
||||
```
|
||||
FIX PLAN (N findings total)
|
||||
|
||||
BATCH A — HOTFIXES (N items, no confirmation needed)
|
||||
A1. <file> — <fix description>
|
||||
A2. <file> — <fix description>
|
||||
...
|
||||
|
||||
BATCH B — SMALL FEATURES (N items, no confirmation needed)
|
||||
B1. <description> — files: <list>
|
||||
B2. <description> — files: <list>
|
||||
...
|
||||
|
||||
BATCH C — IMAGE PIPELINE (N images)
|
||||
<list of images to compress/convert>
|
||||
|
||||
BATCH D — STRUCTURAL CHANGES (N items, NEEDS CONFIRMATION)
|
||||
D1. <description> — impact: <what changes visually>
|
||||
D2. <description> — impact: <what changes visually>
|
||||
...
|
||||
|
||||
BATCH E — CONTENT REMOVAL (N items, NEEDS CONFIRMATION)
|
||||
E1. <what to remove> — reason: <why>
|
||||
...
|
||||
|
||||
BATCH F — USER ACTIONS (N items, documented in SEO.md)
|
||||
F1. <action> — tool/link: <where>
|
||||
...
|
||||
```
|
||||
|
||||
**Do not proceed to STEP 12 until this plan is printed.**
|
||||
|
||||
---
|
||||
|
||||
## STEP 12 — EXECUTE FIXES VIA SUB-AGENTS `[both]`
|
||||
|
||||
**Orchestration step.** Delegate each batch to the appropriate specialist
|
||||
agent. Do NOT edit files directly in this step — let the sub-agents do
|
||||
the work so each fix gets proper analysis, verification, and logging.
|
||||
|
||||
### Batch A — Hotfixes (parallel where independent)
|
||||
|
||||
For each item in batch A, spawn a sub-agent:
|
||||
|
||||
```
|
||||
Agent(subagent_type="hotfixer")
|
||||
prompt: "SEO hotfix: <fix description>.
|
||||
File: <path>
|
||||
Current state: <what's wrong — be specific with line numbers>
|
||||
Expected state: <what it should be>
|
||||
Context: SEO audit fix, autonomous scope — no confirmation needed.
|
||||
Do NOT commit — just fix and verify."
|
||||
```
|
||||
|
||||
Group independent fixes into parallel sub-agent calls.
|
||||
Sequential if fixes touch the same file.
|
||||
|
||||
### Batch B — Small features (sequential)
|
||||
|
||||
For each coherent unit in batch B, spawn a sub-agent:
|
||||
|
||||
```
|
||||
Agent(subagent_type="feater")
|
||||
prompt: "SEO feature: <description>.
|
||||
Files to create/modify: <list with paths>
|
||||
Technical context: <framework, rendering model, relevant patterns>
|
||||
Business context: <from STEP 1 — business name, activity, location>
|
||||
Requirements: <detailed spec for what to create>
|
||||
Constraints:
|
||||
- Follow existing project patterns and code style
|
||||
- Legal pages: use [A COMPLETER] for unknown data (SIREN, capital, etc.)
|
||||
- Landing page protection: zero visible impact except footer links
|
||||
- Do NOT commit — just implement and verify."
|
||||
```
|
||||
|
||||
Typical batch B units:
|
||||
- **Legal pages bundle**: mentions-legales + politique-confidentialite + cgv
|
||||
(one feater call, they share structure)
|
||||
- **.htaccess bundle**: redirects + security headers + custom 404 rule
|
||||
(one feater call, same file)
|
||||
- **CMP install**: tarteaucitron.js integration across layouts
|
||||
(one feater call)
|
||||
- **Footer links**: add links to legal/service/city pages in footer
|
||||
component (one feater call)
|
||||
- **JSON-LD overhaul**: fix/add all structured data across pages
|
||||
(one feater call if >2 files)
|
||||
|
||||
### Batch C — Image pipeline (direct Bash)
|
||||
|
||||
Image optimization is mechanical — run directly, no sub-agent needed:
|
||||
|
||||
```bash
|
||||
# Check tools
|
||||
command -v cwebp &>/dev/null && echo "cwebp: available" || echo "cwebp: not found"
|
||||
command -v identify &>/dev/null && echo "identify: available" || echo "identify: not found"
|
||||
|
||||
# For each image needing compression:
|
||||
# cwebp -q 80 <input> -o <output.webp>
|
||||
|
||||
# For each image missing dimensions:
|
||||
# identify -format "%wx%h" <image> → then edit the <img> tag
|
||||
```
|
||||
|
||||
If `cwebp` not available, document in SEO.md §11 as user action:
|
||||
"Install libwebp-tools and run: `cwebp -q 80 input.jpg -o output.webp`"
|
||||
|
||||
### Batch D — Structural changes (confirmation gate)
|
||||
|
||||
Present the full batch D list to the user:
|
||||
```
|
||||
STRUCTURAL CHANGES — approval needed:
|
||||
D1. <description> — impact: <what changes>
|
||||
D2. <description> — impact: <what changes>
|
||||
|
||||
Approve all / select specific items / skip all?
|
||||
```
|
||||
|
||||
For each approved item, spawn `feater` with detailed spec.
|
||||
Unapproved items → document in SEO.md §9 (moyen terme).
|
||||
|
||||
### Batch E — Content removal (confirmation gate)
|
||||
|
||||
Same pattern as batch D. Present list, get approval, execute approved items.
|
||||
|
||||
### Batch F — User actions
|
||||
|
||||
No execution. These are documented in SEO.md §11 during STEP 13.
|
||||
|
||||
### Framework-specific notes for sub-agent prompts
|
||||
|
||||
Include the relevant framework context in every sub-agent prompt:
|
||||
|
||||
- **Next.js**: `metadata` export (App Router) or `Head` (Pages Router).
|
||||
`next-sitemap` for sitemap. Redirects in `next.config.js`.
|
||||
- **Astro**: direct `<meta>` in layouts. `@astrojs/sitemap`.
|
||||
Redirects in `astro.config.mjs` or `_redirects`.
|
||||
- **Nuxt**: `useHead()` or `nuxt.config`. `@nuxtjs/sitemap`.
|
||||
- **Static HTML / PHP**: edit `<head>` directly. `.htaccess` for redirects.
|
||||
- **React SPA**: flag that SEO is severely limited without SSR. Add
|
||||
`react-helmet` but warn in report. Recommend migration to SSR framework.
|
||||
|
||||
### Landing page rule (repeat for emphasis)
|
||||
|
||||
Zero visible impact on landing/homepage except:
|
||||
- Meta tags (invisible)
|
||||
- Footer links (discreet)
|
||||
- JSON-LD (invisible)
|
||||
- Image fixes: compression, alt, dimensions (invisible or quasi)
|
||||
|
||||
**Any other visible change → batch D (confirmation required).**
|
||||
|
||||
### Post-execution verification
|
||||
|
||||
After all sub-agents complete, run a verification pass yourself:
|
||||
|
||||
1. **Syntax check** — validate modified HTML, JSON-LD, .htaccess
|
||||
2. **Consistency check** — JSON-LD data matches what was decided in audit
|
||||
3. **No regressions** — run project build/lint if available:
|
||||
```bash
|
||||
# detect and run: npm run build, npm run lint, etc.
|
||||
```
|
||||
4. If a sub-agent broke something, revert its changes and note the failure.
|
||||
|
||||
### Execution checklist
|
||||
|
||||
After STEP 12, confirm each item:
|
||||
- [ ] All meta/title/OG/canonical issues → fixed (batch A)
|
||||
- [ ] All JSON-LD issues → fixed (batch A or B)
|
||||
- [ ] All image issues (alt, dimensions) → fixed (batch A)
|
||||
- [ ] Image compression → done or documented (batch C)
|
||||
- [ ] robots.txt / sitemap.xml → fixed (batch A)
|
||||
- [ ] .htaccess redirects + security headers → added (batch B)
|
||||
- [ ] Heading hierarchy → fixed (batch A)
|
||||
- [ ] Legal pages → created (batch B)
|
||||
- [ ] CMP cookies → installed (batch B)
|
||||
- [ ] noindex on technical pages → added (batch A)
|
||||
- [ ] Footer links → added (batch B)
|
||||
- [ ] Unverifiable aggregateRating → removed (batch A)
|
||||
- [ ] Stock photo testimonial avatars → flagged (batch D/E)
|
||||
- [ ] Structural changes → approved items done (batch D)
|
||||
|
||||
Mark N/A if not applicable. Explain failures.
|
||||
|
||||
### Change log
|
||||
|
||||
Collect logs from all sub-agents. Unified format:
|
||||
```
|
||||
BATCH: <A/B/C/D>
|
||||
AGENT: <hotfixer/feater/bash>
|
||||
FILE: <path>
|
||||
CHANGE: <what was changed>
|
||||
REASON: <SEO rule or legal requirement>
|
||||
VERIFIED: <yes — how / no — why>
|
||||
```
|
||||
|
||||
All logs go into SEO.md §15.
|
||||
|
||||
---
|
||||
|
||||
## STEP 13 — GENERATE SEO.md `[both]`
|
||||
|
||||
Create or **update** `SEO.md` at project root (or `docs/SEO.md` if that
|
||||
convention exists). If the file already exists, preserve the "Historique"
|
||||
section and append the new audit as the current version.
|
||||
|
||||
### Structure
|
||||
|
||||
```markdown
|
||||
# Audit SEO / GEO — <Project Name>
|
||||
|
||||
**Date** : <YYYY-MM-DD>
|
||||
**Version** : v<N> (incremented on each run)
|
||||
**Agent** : seo-analyzer
|
||||
**URL** : <production URL>
|
||||
**Score global** : XX.X / 20
|
||||
|
||||
---
|
||||
|
||||
## 0. Alertes majeures (conformite legale et risques)
|
||||
<!-- Critical legal/compliance issues that need immediate attention -->
|
||||
|
||||
## 1. Notes globales (/20 par axe + ponderee)
|
||||
<!-- Full scoring table from STEP 9 -->
|
||||
|
||||
## 2. Audit technique
|
||||
<!-- HTTP headers, redirects, compression, security, performance -->
|
||||
<!-- Mark what was fixed automatically vs what remains -->
|
||||
|
||||
## 3. Audit on-page
|
||||
<!-- Meta, headings, content, images, internal linking -->
|
||||
|
||||
## 4. Audit SEO local / NAP
|
||||
<!-- NAP consistency matrix across all sources -->
|
||||
|
||||
## 5. Audit presence externe (GMB, reseaux sociaux, citations)
|
||||
<!-- Status of each platform, missing registrations -->
|
||||
|
||||
## 6. Analyse concurrentielle
|
||||
<!-- Top competitors, positioning, gaps, targets -->
|
||||
|
||||
## 7. Optimisation GEO / IA
|
||||
<!-- AI readiness assessment, current visibility in AI engines -->
|
||||
|
||||
## 8. Plan d'action — QUICK WINS (< 7 jours)
|
||||
<!-- Actionable list with time estimates and impact -->
|
||||
|
||||
## 9. Plan d'action — MOYEN TERME (1-3 mois)
|
||||
<!-- Structural improvements, content strategy, city pages -->
|
||||
|
||||
## 10. Plan d'action — LONG TERME (3-6 mois)
|
||||
<!-- Authority building, backlinks, partnerships -->
|
||||
|
||||
## 11. Actions utilisateur requises
|
||||
<!-- Each action with direct links to tools/interfaces -->
|
||||
<!-- Example: "Revendiquer la fiche GMB → https://business.google.com" -->
|
||||
|
||||
## 12. Recommandations gratuites (outils, methodes, budget 0 EUR)
|
||||
<!-- Free tools and methods: GSC, PageSpeed, Schema validator, etc. -->
|
||||
|
||||
## 13. Synthese 90 jours — objectifs realistes
|
||||
<!-- Measurable targets: review count, ranking positions, traffic -->
|
||||
|
||||
## 14. Annexe — informations impossibles a auditer automatiquement
|
||||
<!-- What couldn't be checked and why (missing tools, access, etc.) -->
|
||||
|
||||
## 15. Log des modifications appliquees par l'agent
|
||||
<!-- Every file changed, what was changed, why -->
|
||||
|
||||
---
|
||||
|
||||
## Historique
|
||||
<!-- Previous audit summaries preserved here -->
|
||||
<!-- ### v1 — 2025-01-15 — Score: 8.2/20 -->
|
||||
<!-- ### v2 — 2025-04-01 — Score: 12.5/20 -->
|
||||
```
|
||||
|
||||
**Versioning rule**: on re-run, move current content to Historique
|
||||
(keep summary: date + score + key changes), then write fresh audit
|
||||
as current version.
|
||||
|
||||
---
|
||||
|
||||
## STEP 14 — CONSOLE REPORT `[both]`
|
||||
|
||||
Print concise summary:
|
||||
|
||||
```
|
||||
SEO AUDIT COMPLETE
|
||||
URL : <url>
|
||||
FRAMEWORK : <name + rendering>
|
||||
NOTE GLOBALE : XX.X / 20
|
||||
|
||||
CHANGEMENTS APPLIQUES (N) : voir SEO.md §15
|
||||
CHANGEMENTS EN ATTENTE (N) : voir SEO.md §11
|
||||
CONFORMITE LEGALE : OK | N points bloquants → voir SEO.md §0
|
||||
ALERTES MAJEURES : <short list or "none">
|
||||
|
||||
PROCHAINE ETAPE : <highest-priority immediate action>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## RULES
|
||||
|
||||
### Orchestration
|
||||
- **Analyze before fixing.** STEPs 0-11 are pure analysis and planning.
|
||||
No file is modified until STEP 12. The triage (STEP 11) is the bridge.
|
||||
- **Delegate to specialists.** Never edit files directly during STEP 12.
|
||||
Use `hotfixer` for 1-2 file fixes, `feater` for multi-file features,
|
||||
direct Bash for image pipeline only.
|
||||
- **Depth-aware.** Respect the LOCAL/FULL choice from STEP 0. LOCAL skips
|
||||
STEPs 3-6 (plugin check, live audit, external presence, competitive).
|
||||
Same rigor on the steps that do run.
|
||||
- **Plugin-advisor at the right time.** STEP 3 (after stack detection),
|
||||
not before. Only for FULL depth. If tools are missing, offer to
|
||||
downgrade to LOCAL — don't fail silently.
|
||||
- **Sub-agent prompts must be self-contained.** Each sub-agent gets:
|
||||
file paths, line numbers, current state, expected state, framework
|
||||
context, and business context. Never assume the sub-agent has seen
|
||||
the audit findings.
|
||||
|
||||
### Scope
|
||||
- **Autonomous fixes = markup, assets, config, legal pages only.**
|
||||
Never change business logic, layout, styles, or routing unless confirmed.
|
||||
- **Landing page protection.** Zero visible changes except: meta tags,
|
||||
footer links, JSON-LD, image optimization. Everything else requires
|
||||
confirmation via batch D.
|
||||
- **Preserve existing valid SEO.** Don't rewrite correct tags.
|
||||
- **Flag SPA limitations.** Client-side SPA without SSR = SEO severely
|
||||
limited. Warn explicitly and recommend SSR migration.
|
||||
- **One H1 per page.** Fix hierarchy if broken.
|
||||
- **JSON-LD over microdata.** Prefer `application/ld+json` script blocks.
|
||||
|
||||
### Data integrity
|
||||
- **No invented content.** Meta descriptions and titles must reflect actual
|
||||
page content. Use `<!-- SEO: TODO — describe X -->` for unknowns.
|
||||
- **No fake data.** Never invent reviews, ratings, or testimonials.
|
||||
Remove unverifiable `aggregateRating` rather than keeping a lie.
|
||||
- **Legal accuracy.** Legal page content must be factually correct for
|
||||
the business. Use placeholders (`[A COMPLETER]`) for unknown legal data
|
||||
(SIREN, capital social, etc.) rather than inventing values.
|
||||
|
||||
### Process
|
||||
- **Iterative document.** SEO.md is updated, never overwritten from scratch.
|
||||
Preserve audit history.
|
||||
- **Transparency.** Every automated change is logged with file, change,
|
||||
and reason. Nothing is done silently.
|
||||
- **Verify after fix.** Post-execution verification (STEP 12) is mandatory.
|
||||
Build/lint must pass. Broken fixes are reverted immediately.
|
||||
@@ -42,18 +42,24 @@ check_symlink() {
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -L "$target" ]; then
|
||||
# readlink -f is not available on macOS BSD — use -f with fallback
|
||||
local real
|
||||
real=$(readlink -f "$target" 2>/dev/null) || real=$(readlink "$target")
|
||||
if [ ! -e "$real" ]; then
|
||||
fail "$HOME/.claude/$name → $real — BROKEN SYMLINK"
|
||||
else
|
||||
pass "$HOME/.claude/$name"; _LINK_PASS=$((_LINK_PASS + 1))
|
||||
fi
|
||||
else
|
||||
warn "$HOME/.claude/$name exists but is NOT a symlink (expected symlink to repo)"
|
||||
# Broken symlink: points at a target that no longer exists.
|
||||
if [ -L "$target" ] && [ ! -e "$target" ]; then
|
||||
fail "$HOME/.claude/$name → $(readlink "$target") — BROKEN SYMLINK"
|
||||
return
|
||||
fi
|
||||
|
||||
# Correctly wired iff the canonical path lands inside the repo. This is true
|
||||
# for a direct symlink (CLAUDE.md, settings.json) AND for a real file reached
|
||||
# through a symlinked ANCESTOR dir (hooks/, skills/, agents/, lib/, templates/
|
||||
# are dir-level symlinks — their children are real files under $REPO). A stray
|
||||
# real copy in ~/.claude resolves to itself (outside $REPO) → still flagged as
|
||||
# drift. (LRN-047: the dir-symlink layout is legitimate, must not false-warn.)
|
||||
local real
|
||||
real=$(readlink -f "$target" 2>/dev/null) || real="$target"
|
||||
case "$real" in
|
||||
"$REPO"/*) pass "$HOME/.claude/$name"; _LINK_PASS=$((_LINK_PASS + 1)) ;;
|
||||
*) warn "$HOME/.claude/$name resolves to $real (outside repo — expected a link into $REPO)" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_symlink "CLAUDE.md"
|
||||
@@ -83,24 +89,17 @@ else
|
||||
warn "GStack submodule missing — run: git submodule update --init"
|
||||
fi
|
||||
|
||||
if [ -L "$HOME/.claude/skills/gstack" ]; then
|
||||
real=$(readlink -f "$HOME/.claude/skills/gstack" 2>/dev/null || readlink "$HOME/.claude/skills/gstack")
|
||||
if [ -d "$real" ]; then
|
||||
pass "Symlink OK → $real"
|
||||
# Check for skills/ subdirectory (referenced by plugin-advisor PHASE 1).
|
||||
# `|| echo 0` is required because under `set -o pipefail`, a missing
|
||||
# gstack/skills/ dir makes find exit non-zero, killing the script.
|
||||
gstack_skills_count=$( { find "$HOME/.claude/skills/gstack/skills/" -maxdepth 1 -mindepth 1 2>/dev/null || true; } | wc -l | tr -d ' ')
|
||||
if [ "${gstack_skills_count:-0}" -gt 0 ]; then
|
||||
pass "GStack: ${gstack_skills_count} skills available"
|
||||
else
|
||||
warn "GStack symlink OK but no skills/ subdirectory found — may need: cd skills-external/gstack && ./setup"
|
||||
fi
|
||||
else
|
||||
fail "Symlink broken → $real"
|
||||
fi
|
||||
# GStack skills are exposed as PER-SKILL symlinks directly under skills/ (browse,
|
||||
# cso, review, …) pointing into skills-external/gstack/ — there is NO single
|
||||
# skills/gstack symlink (link.sh deliberately removes it: it duplicated the
|
||||
# top-level gstack SKILL.md alongside the per-skill entries). The bin/ +
|
||||
# browse/dist/ helper links under skills/gstack/ are checked in §7 Consistency.
|
||||
# `|| true` guards pipefail if skills/ is unexpectedly absent (checked above).
|
||||
gstack_skill_links=$( { find "$HOME/.claude/skills/" -maxdepth 1 -type l -lname '*skills-external/gstack/*' 2>/dev/null || true; } | wc -l | tr -d ' ')
|
||||
if [ "${gstack_skill_links:-0}" -gt 0 ]; then
|
||||
pass "GStack: ${gstack_skill_links} skills linked (per-skill symlinks)"
|
||||
else
|
||||
warn "GStack not symlinked — run: bash link.sh"
|
||||
warn "GStack skills not linked — run: cd skills-external/gstack && ./setup"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
@@ -136,7 +135,10 @@ fi
|
||||
if command -v cargo &>/dev/null; then
|
||||
pass "Cargo $(cargo --version | awk '{print $2}')"
|
||||
else
|
||||
warn "Cargo not found (RTK unavailable)"
|
||||
# Cargo does NOT gate RTK: RTK ships as a prebuilt binary and detect_rtk finds
|
||||
# it via ~/.cargo/bin or ~/.local/bin (RTK status is shown under Plugins).
|
||||
# Cargo is only the Rust toolchain to BUILD RTK from source → optional, info.
|
||||
info "Cargo not found (optional — only needed to build RTK from source)"
|
||||
fi
|
||||
|
||||
if command -v python3 &>/dev/null; then
|
||||
@@ -213,11 +215,20 @@ print(len(d.get('permissions',{}).get('deny',[])))
|
||||
if [ "$DENY_COUNT" = "?" ]; then
|
||||
warn "Could not parse deny count (python3 unavailable or JSON parse error)"
|
||||
else
|
||||
EXPECTED_DENY=100
|
||||
if [ "$DENY_COUNT" -eq "$EXPECTED_DENY" ] 2>/dev/null; then
|
||||
pass "Deny rules: $DENY_COUNT"
|
||||
# Expected = deny count in the last COMMITTED settings.json. A hardcoded
|
||||
# number drifts on every legit deny-list edit (false-warned for weeks at
|
||||
# 100 vs 99 — LRN-047 class); deriving from HEAD auto-tracks legit edits
|
||||
# and still flags live-vs-committed divergence.
|
||||
EXPECTED_DENY=$(git -C "$REPO" show HEAD:settings.json 2>/dev/null | python3 -c "
|
||||
import json,sys
|
||||
print(len(json.load(sys.stdin).get('permissions',{}).get('deny',[])))
|
||||
" 2>/dev/null || echo "?")
|
||||
if [ "$EXPECTED_DENY" = "?" ]; then
|
||||
warn "Could not derive expected deny count from committed settings.json"
|
||||
elif [ "$DENY_COUNT" -eq "$EXPECTED_DENY" ] 2>/dev/null; then
|
||||
pass "Deny rules: $DENY_COUNT (matches committed settings.json)"
|
||||
else
|
||||
warn "Deny rules: $DENY_COUNT (expected $EXPECTED_DENY) — settings may have been manually modified"
|
||||
warn "Deny rules: $DENY_COUNT (committed: $EXPECTED_DENY) — live settings diverge from last commit"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@@ -230,8 +241,12 @@ echo ""
|
||||
# 6. Token budget estimate
|
||||
# ────────────────────────────────────────────────────────────
|
||||
echo "── Token budget estimate ──"
|
||||
# Reference: Claude Code Pro plan ~11k tokens/5h session (session budget, not context window).
|
||||
# Seuils: WARNING >15%, CRITICAL >30% of session budget.
|
||||
# The passive footprint (CLAUDE.md + skill descriptions + plugin session-injects)
|
||||
# loads into the CONTEXT WINDOW every session — it competes with the ~200k default
|
||||
# context, NOT a per-session token quota (the old "~11k/5h budget" denominator was
|
||||
# a category error → false "92% CRITICAL", LRN-047). Measured ~11.4k post-audit
|
||||
# 2026-07-02 (LRN-088); the chars/4 sum below is a coarse proxy of that footprint.
|
||||
# Thresholds: WARNING >15% of context (~30k), CRITICAL >25% (~50k).
|
||||
|
||||
CLAUDE_MD_CHARS=$(wc -c < "$REPO/CLAUDE.md" 2>/dev/null || echo 0)
|
||||
CLAUDE_MD_TOKENS=$((CLAUDE_MD_CHARS / 4))
|
||||
@@ -255,25 +270,25 @@ if detect_context7 2>/dev/null; then PLUGIN_TOKENS=$((PLUGIN_TOKENS + 200));
|
||||
if detect_graphifyy 2>/dev/null; then PLUGIN_TOKENS=$((PLUGIN_TOKENS + 300)); fi
|
||||
|
||||
TOTAL_TOKENS=$((CLAUDE_MD_TOKENS + SKILL_DESC_TOKENS + PLUGIN_TOKENS))
|
||||
SESSION_BUDGET=11000
|
||||
PCT=$((TOTAL_TOKENS * 100 / SESSION_BUDGET))
|
||||
CONTEXT_WINDOW=200000 # Claude Code default context window (conservative; 1M is opt-in)
|
||||
PCT=$((TOTAL_TOKENS * 100 / CONTEXT_WINDOW))
|
||||
|
||||
echo ""
|
||||
echo " CLAUDE.md: ~${CLAUDE_MD_TOKENS}t"
|
||||
echo " Skill descriptions: ~${SKILL_DESC_TOKENS}t (${SKILL_COUNT} skills)"
|
||||
echo " Plugin passive cost: ~${PLUGIN_TOKENS}t (active plugins)"
|
||||
echo " ─────────────────────────────────────────"
|
||||
info " Total: ~${TOTAL_TOKENS}t"
|
||||
info " Session budget (Pro): ${SESSION_BUDGET}t"
|
||||
info " Usage: ~${PCT}%"
|
||||
info " Total: ~${TOTAL_TOKENS}t (measured ~11.4k post-audit, LRN-088)"
|
||||
info " Context window: ${CONTEXT_WINDOW}t (default; 1M opt-in)"
|
||||
info " Usage: ~${PCT}% of context"
|
||||
echo ""
|
||||
|
||||
if [ "$PCT" -gt 30 ]; then
|
||||
warn "CRITICAL: ${PCT}% of session budget — /plugin-check to disable unused plugins"
|
||||
if [ "$PCT" -gt 25 ]; then
|
||||
warn "CRITICAL: ~${PCT}% of the ${CONTEXT_WINDOW}t context — /plugin-check to disable unused plugins"
|
||||
elif [ "$PCT" -gt 15 ]; then
|
||||
warn "WARNING: ${PCT}% of session budget — consider disabling unused toggle plugins"
|
||||
warn "WARNING: ~${PCT}% of the ${CONTEXT_WINDOW}t context — consider disabling unused toggle plugins"
|
||||
else
|
||||
pass "Budget: ${PCT}% (comfortable)"
|
||||
pass "Budget: ~${PCT}% of context (comfortable)"
|
||||
fi
|
||||
|
||||
# Per-file breakdown (skill bodies — loaded on demand, shown for awareness)
|
||||
@@ -310,8 +325,11 @@ else
|
||||
warn "gstack/browse/dist/ symlink missing — run: bash link.sh"
|
||||
fi
|
||||
|
||||
# Check owned skills have disable-model-invocation (skip external/symlinked skills)
|
||||
MISSING_DMI=()
|
||||
# BDR-019 (2026-06-09) stripped disable-model-invocation repo-wide so the
|
||||
# model/orchestrators can self-route. The old check required the key on
|
||||
# every owned skill — permanent false-warn since. Inverted: warn if any
|
||||
# owned skill REintroduces the key (regression watch on BDR-019).
|
||||
PRESENT_DMI=()
|
||||
for f in "$HOME/.claude/skills/"*/SKILL.md; do
|
||||
[ -f "$f" ] || continue
|
||||
dir=$(dirname "$f")
|
||||
@@ -319,19 +337,22 @@ for f in "$HOME/.claude/skills/"*/SKILL.md; do
|
||||
[ -L "$dir" ] && continue
|
||||
[ -L "$f" ] && continue
|
||||
name=$(basename "$dir")
|
||||
if ! grep -q "disable-model-invocation" "$f" 2>/dev/null; then
|
||||
MISSING_DMI+=("$name")
|
||||
if grep -q "disable-model-invocation" "$f" 2>/dev/null; then
|
||||
PRESENT_DMI+=("$name")
|
||||
fi
|
||||
done
|
||||
if [ ${#MISSING_DMI[@]} -eq 0 ]; then
|
||||
pass "All owned skills have disable-model-invocation"
|
||||
if [ ${#PRESENT_DMI[@]} -eq 0 ]; then
|
||||
pass "No owned skill carries disable-model-invocation (BDR-019)"
|
||||
else
|
||||
warn "Owned skills missing disable-model-invocation: ${MISSING_DMI[*]}"
|
||||
warn "Owned skills reintroduce disable-model-invocation (BDR-019 regression): ${PRESENT_DMI[*]}"
|
||||
fi
|
||||
|
||||
# Check expected skills are present
|
||||
# Check expected skills are present. Repo-owned skills only: gstack skills
|
||||
# (health, status, …) are OFF by default and toggled per profile — requiring
|
||||
# them here false-warns on a default install, and "run link.sh" cannot
|
||||
# restore them (they are profile-managed, not link.sh-managed).
|
||||
EXPECTED_SKILLS=(
|
||||
"analyze" "doc" "health" "init-project" "onboard" "plugin-check"
|
||||
"analyze" "doc" "init-project" "onboard" "plugin-check"
|
||||
"refactor" "ship-feature" "status"
|
||||
)
|
||||
MISSING_SKILLS=()
|
||||
@@ -341,7 +362,7 @@ for skill in "${EXPECTED_SKILLS[@]}"; do
|
||||
fi
|
||||
done
|
||||
if [ ${#MISSING_SKILLS[@]} -eq 0 ]; then
|
||||
pass "All ${#EXPECTED_SKILLS[@]} expected skills present (analyze, doc, health, init-project, onboard, plugin-check, refactor, ship-feature, status)"
|
||||
pass "All ${#EXPECTED_SKILLS[@]} expected skills present (${EXPECTED_SKILLS[*]})"
|
||||
else
|
||||
warn "Missing skills: ${MISSING_SKILLS[*]} — run: bash link.sh"
|
||||
fi
|
||||
|
||||
@@ -1 +1 @@
|
||||
ef0d630994fd7ef5f2b84fb66cd6249c493bb8736bcacd4734d7c798125018fb rtk-rewrite.sh
|
||||
871efa28daf7c06a9c9039a2875407e2536646f5d82f7e7a9c6a80dd3742929c rtk-rewrite.sh
|
||||
|
||||
@@ -24,10 +24,13 @@ prompt="$(printf '%s' "$input" \
|
||||
lc="$(printf '%s' "$prompt" | tr '[:upper:]' '[:lower:]')"
|
||||
|
||||
# UI/design build and review signals (FR + EN). Word boundaries (\b) avoid
|
||||
# substring false matches like perform/platform/information. Some broad tokens
|
||||
# (page, color, screen, card, menu) are kept deliberately for coverage — they
|
||||
# over-fire on non-UI prompts, which is harmless: the reminder self-cancels.
|
||||
pattern='design|redesign|refonte|refont|ui/ux|ux/ui|\bui\b|\bux\b|ui kit|design system|design-system|interface|frontend|front-end|front end|composant|component|\bnavbar\b|\bsidebar\b|\bmodal\b|\bbouton\b|\bbutton\b|\bcard\b|\bcarte\b|\bform\b|formulaire|\bhero\b|\bheader\b|\bfooter\b|\bmenu\b|dropdown|tooltip|\bbadge\b|\bchart\b|graphique|accordion|carousel|\bslider\b|landing|dashboard|homepage|home page|\baccueil\b|\bpage\b|\bpages\b|\bécran\b|\becran\b|\bscreen\b|portfolio|maquette|mockup|wireframe|prototype|\blook\b|\bjoli\b|\bjolie\b|\bbeau\b|\bbelle\b|esth[eé]tique|aesthetic|\bvisuel\b|\bvisual\b|embellir|fignol|peaufin|polish|styliser|\bstyle\b|styling|stylesheet|\bskin\b|charte graphique|\bbrand\b|branding|\blogo\b|favicon|ic[oô]ne|\bicon\b|\bcss\b|tailwind|shadcn|couleur|\bcolor\b|palette|gradient|d[eé]grad[eé]|\bshadow\b|\bombre\b|spacing|espacement|\bmarge\b|\bpadding\b|\bmargin\b|\bradius\b|arrondi|\bhover\b|dark mode|light mode|\btheme\b|th[eè]me|typograph|\bfont\b|\bfonts\b|font pairing|\bpolice\b|animation|\bmotion\b|transition|micro-interaction|keyframe|glassmorph|neumorph|claymorph|skeuomorph|brutalis|bento|minimalis|responsive|figma'
|
||||
# substring false matches like perform/platform/information. Tightened
|
||||
# 2026-07-02: ultra-generic English tokens (page, form, menu, card, style,
|
||||
# look, screen, interface, color) fired on a large share of NON-UI prompts —
|
||||
# ~200 tokens of reminder each time (measured: 6 fires during a pure config
|
||||
# audit). Kept: unambiguous design vocabulary + FR aesthetic words; specific
|
||||
# compounds (stylesheet, styling, formulaire, écran) still match.
|
||||
pattern='design|redesign|refonte|refont|ui/ux|ux/ui|\bui\b|\bux\b|ui kit|design system|design-system|frontend|front-end|front end|composant|component|\bnavbar\b|\bsidebar\b|\bmodal\b|\bbouton\b|\bbutton\b|formulaire|\bhero\b|\bheader\b|\bfooter\b|dropdown|tooltip|\bbadge\b|\bchart\b|graphique|accordion|carousel|\bslider\b|landing|dashboard|homepage|home page|\baccueil\b|\bécran\b|\becran\b|portfolio|maquette|mockup|wireframe|prototype|\bjoli\b|\bjolie\b|\bbeau\b|\bbelle\b|esth[eé]tique|aesthetic|\bvisuel\b|\bvisual\b|embellir|fignol|peaufin|polish|styliser|styling|stylesheet|\bskin\b|charte graphique|\bbrand\b|branding|\blogo\b|favicon|ic[oô]ne|\bicon\b|\bcss\b|tailwind|shadcn|couleur|palette|gradient|d[eé]grad[eé]|\bombre\b|spacing|espacement|\bmarge\b|\bpadding\b|\bmargin\b|\bradius\b|arrondi|\bhover\b|dark mode|light mode|\btheme\b|th[eè]me|typograph|\bfont\b|\bfonts\b|font pairing|\bpolice\b|animation|\bmotion\b|transition|micro-interaction|keyframe|glassmorph|neumorph|claymorph|skeuomorph|brutalis|bento|minimalis|responsive|figma'
|
||||
|
||||
if printf '%s' "$lc" | grep -Eq "$pattern"; then
|
||||
cat <<'EOF'
|
||||
|
||||
+55
-29
@@ -7,8 +7,17 @@
|
||||
# which is the single source of truth (src/discover/registry.rs).
|
||||
# To add or change rewrite rules, edit the Rust registry — not this file.
|
||||
#
|
||||
# INTEGRITY PIN: the rtk binary verifies this file against
|
||||
# hooks/.rtk-hook.sha256 at execution time and refuses to run on mismatch.
|
||||
# ANY edit here must re-pin: (cd hooks && sha256sum rtk-rewrite.sh > .rtk-hook.sha256)
|
||||
#
|
||||
# Exit code protocol for `rtk rewrite`:
|
||||
# 0 + stdout Rewrite found, no deny/ask rule matched → auto-allow
|
||||
# 0 + stdout Rewrite found, no rtk deny/ask rule matched → rewrite. NO
|
||||
# permissionDecision is emitted (auto-allow dropped 2026-07-02:
|
||||
# it made rtk's registry a parallel permission authority that
|
||||
# bypassed settings.json deny/ask). The REWRITTEN command goes
|
||||
# through native evaluation; explicit `rtk <tool>` allow rules
|
||||
# in settings.json keep read-only forms frictionless.
|
||||
# 1 No RTK equivalent → pass through unchanged
|
||||
# 2 Deny rule matched → pass through (Claude Code native deny handles it)
|
||||
# 3 + stdout Ask rule matched → rewrite but let Claude Code prompt the user
|
||||
@@ -18,14 +27,27 @@ if ! command -v jq &>/dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v rtk &>/dev/null; then
|
||||
# PATH heal: hook/tool-shell PATH may lack the cargo bin dir (hand-managed
|
||||
# ~/.bashrc can lose the cargo line — LRN-036 class). Resolve the ABSOLUTE
|
||||
# binary path: the rewritten command executes in the tool shell, whose PATH
|
||||
# the hook cannot fix — a bare `rtk …` rewrite would exit 127 there.
|
||||
RTK_BIN="$(command -v rtk 2>/dev/null || true)"
|
||||
RTK_ON_PATH=1
|
||||
if [ -z "$RTK_BIN" ]; then
|
||||
RTK_ON_PATH=0
|
||||
for _d in "$HOME/.cargo/bin" "$HOME/.local/bin"; do
|
||||
if [ -x "$_d/rtk" ]; then RTK_BIN="$_d/rtk"; break; fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$RTK_BIN" ]; then
|
||||
echo "[rtk] WARNING: rtk is not installed or not in PATH. Hook cannot rewrite commands. Install: https://github.com/rtk-ai/rtk#installation" >&2
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Version guard: rtk rewrite was added in 0.23.0.
|
||||
# Older binaries: warn once and exit cleanly (no silent failure).
|
||||
RTK_VERSION=$(rtk --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
RTK_VERSION=$("$RTK_BIN" --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
|
||||
if [ -n "$RTK_VERSION" ]; then
|
||||
MAJOR=$(echo "$RTK_VERSION" | cut -d. -f1)
|
||||
MINOR=$(echo "$RTK_VERSION" | cut -d. -f2)
|
||||
@@ -44,13 +66,13 @@ if [ -z "$CMD" ]; then
|
||||
fi
|
||||
|
||||
# Delegate all rewrite + permission logic to the Rust binary.
|
||||
REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null)
|
||||
REWRITTEN=$("$RTK_BIN" rewrite "$CMD" 2>/dev/null)
|
||||
EXIT_CODE=$?
|
||||
|
||||
case $EXIT_CODE in
|
||||
0)
|
||||
# Rewrite found, no permission rules matched — safe to auto-allow.
|
||||
# If the output is identical, the command was already using RTK.
|
||||
# Rewrite found. If the output is identical, the command was
|
||||
# already using RTK — nothing to do.
|
||||
[ "$CMD" = "$REWRITTEN" ] && exit 0
|
||||
;;
|
||||
1)
|
||||
@@ -70,29 +92,33 @@ case $EXIT_CODE in
|
||||
;;
|
||||
esac
|
||||
|
||||
# When rtk is NOT on PATH, a bare `rtk …` rewrite exits 127 in the tool
|
||||
# shell (whose PATH the hook cannot fix). Substitute the absolute path at
|
||||
# the string head — the only position safe to rewrite. Compound commands
|
||||
# (`a && b`) can carry further bare rtk segments we canNOT substitute
|
||||
# safely (quoted text, e.g. commit messages, may contain the same
|
||||
# pattern): if any remain at a command position, pass through unrewritten
|
||||
# — lose the compression, never emit a command that 127s.
|
||||
if [ "$RTK_ON_PATH" -eq 0 ]; then
|
||||
case "$REWRITTEN" in
|
||||
rtk\ *) REWRITTEN="$RTK_BIN ${REWRITTEN#rtk }" ;;
|
||||
esac
|
||||
if printf '%s' "$REWRITTEN" | grep -Eq '(^|[;&|][[:space:]]*)rtk[[:space:]]'; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
ORIGINAL_INPUT=$(echo "$INPUT" | jq -c '.tool_input')
|
||||
UPDATED_INPUT=$(echo "$ORIGINAL_INPUT" | jq --arg cmd "$REWRITTEN" '.command = $cmd')
|
||||
|
||||
if [ "$EXIT_CODE" -eq 3 ]; then
|
||||
# Ask: rewrite the command, omit permissionDecision so Claude Code prompts.
|
||||
jq -n \
|
||||
--argjson updated "$UPDATED_INPUT" \
|
||||
'{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreToolUse",
|
||||
"updatedInput": $updated
|
||||
}
|
||||
}'
|
||||
else
|
||||
# Allow: rewrite the command and auto-allow.
|
||||
jq -n \
|
||||
--argjson updated "$UPDATED_INPUT" \
|
||||
'{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreToolUse",
|
||||
"permissionDecision": "allow",
|
||||
"permissionDecisionReason": "RTK auto-rewrite",
|
||||
"updatedInput": $updated
|
||||
}
|
||||
}'
|
||||
fi
|
||||
# Rewrite WITHOUT a permissionDecision (exit 0 and exit 3 alike): the
|
||||
# rewritten command goes through Claude Code's native allow/deny/ask
|
||||
# evaluation. Permission control lives in settings.json, not in rtk.
|
||||
jq -n \
|
||||
--argjson updated "$UPDATED_INPUT" \
|
||||
'{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "PreToolUse",
|
||||
"updatedInput": $updated
|
||||
}
|
||||
}'
|
||||
|
||||
+31
-12
@@ -49,10 +49,12 @@ TOGGLE_ACTIVE=()
|
||||
TOGGLE_INACTIVE=()
|
||||
|
||||
for plugin in gstack uiux_pro_max plugin_dev context7 graphifyy; do
|
||||
# Map function name to display name
|
||||
# Map function name to display name. graphifyy = the pipx PACKAGE name
|
||||
# (pypi:graphifyy); the CLI and skill are 'graphify' — display that.
|
||||
case "$plugin" in
|
||||
uiux_pro_max) display="ui-ux-pro-max" ;;
|
||||
plugin_dev) display="plugin-dev" ;;
|
||||
graphifyy) display="graphify" ;;
|
||||
*) display="$plugin" ;;
|
||||
esac
|
||||
|
||||
@@ -105,7 +107,7 @@ declare -A _plugin_costs=(
|
||||
[ui-ux-pro-max]=400
|
||||
[plugin-dev]=100
|
||||
[context7]=200
|
||||
[graphifyy]=300
|
||||
[graphify]=300
|
||||
)
|
||||
for _p in "${TOGGLE_ACTIVE[@]}"; do
|
||||
_cost="${_plugin_costs[$_p]:-0}"
|
||||
@@ -129,20 +131,37 @@ echo "┌─ Claude Code config ────────────────
|
||||
# the user sees the real picture instead of a misleading literal.
|
||||
ALWAYS_ON=()
|
||||
detect_rtk &>/dev/null && ALWAYS_ON+=("rtk")
|
||||
plugin_enabled "security-guidance@claude-code-plugins" && ALWAYS_ON+=("security-guidance")
|
||||
plugin_enabled "superpowers@superpowers-marketplace" && ALWAYS_ON+=("superpowers")
|
||||
# Derive the plugin list from settings.json:enabledPlugins (true entries)
|
||||
# instead of a hardcoded name pair — a hardcoded SET under-reports newly
|
||||
# enabled plugins (pr-review-toolkit was enabled yet invisible). LRN-005
|
||||
# class. Plugins owned by the toggle row below are excluded (dual display).
|
||||
_toggle_owned=" gstack ui-ux-pro-max plugin-dev context7 graphify "
|
||||
while IFS= read -r _pl; do
|
||||
case "$_toggle_owned" in
|
||||
*" $_pl "*) : ;;
|
||||
*) ALWAYS_ON+=("$_pl") ;;
|
||||
esac
|
||||
done < <(grep -oE '"[A-Za-z0-9_-]+@[A-Za-z0-9_-]+"[[:space:]]*:[[:space:]]*true' "$HOME/.claude/settings.json" 2>/dev/null \
|
||||
| sed -E 's/^"([^@]+)@.*$/\1/')
|
||||
unset _toggle_owned _pl
|
||||
ALWAYS_ON_STR="${ALWAYS_ON[*]:-none}"
|
||||
# Same 40-char-width split policy as the toggle row below — keeps the
|
||||
# right border aligned when 4 always-on plugins overflow the field.
|
||||
# right border aligned on overflow. Greedy width-fill (not a fixed 3-name
|
||||
# cut: 3 long names overflowed line 1 and left line 2 empty).
|
||||
if [ "${#ALWAYS_ON_STR}" -le 40 ]; then
|
||||
printf "│ ✅ ON : %-40s│\n" "$ALWAYS_ON_STR"
|
||||
else
|
||||
_ao_line1="${ALWAYS_ON[0]} ${ALWAYS_ON[1]} ${ALWAYS_ON[2]:-}"
|
||||
_ao_rest=("${ALWAYS_ON[@]:3}")
|
||||
_ao_line2="${_ao_rest[*]}"
|
||||
printf "│ ✅ ON : %-40s│\n" "$_ao_line1"
|
||||
printf "│ %-40s│\n" "$_ao_line2"
|
||||
unset _ao_line1 _ao_line2 _ao_rest
|
||||
_ao_l1=""; _ao_l2=""
|
||||
for _ao_e in "${ALWAYS_ON[@]}"; do
|
||||
if [ -z "$_ao_l2" ] && [ $(( ${#_ao_l1} + ${#_ao_e} + 1 )) -le 40 ]; then
|
||||
_ao_l1="${_ao_l1:+$_ao_l1 }$_ao_e"
|
||||
else
|
||||
_ao_l2="${_ao_l2:+$_ao_l2 }$_ao_e"
|
||||
fi
|
||||
done
|
||||
printf "│ ✅ ON : %-40s│\n" "$_ao_l1"
|
||||
printf "│ %-40s│\n" "$_ao_l2"
|
||||
unset _ao_l1 _ao_l2 _ao_e
|
||||
fi
|
||||
unset ALWAYS_ON ALWAYS_ON_STR
|
||||
# Plugin display — all plugins shown, split across 2 lines if >4
|
||||
@@ -182,7 +201,7 @@ printf "│ 📦 v%-45s│\n" "$CONFIG_VERSION"
|
||||
# Version check: compare local vs remote (non-blocking)
|
||||
_remote_ver=""
|
||||
if [ -n "$REPO_DIR" ] && [ -d "$REPO_DIR/.git" ]; then
|
||||
_remote_ver=$(cd "$REPO_DIR" 2>/dev/null && git fetch origin --quiet 2>/dev/null && git show origin/master:version.txt 2>/dev/null) || _remote_ver=""
|
||||
_remote_ver=$(cd "$REPO_DIR" 2>/dev/null && git fetch origin --quiet 2>/dev/null && git show origin/main:version.txt 2>/dev/null) || _remote_ver=""
|
||||
fi
|
||||
if [ -n "$_remote_ver" ] && [ "$_remote_ver" != "$CONFIG_VERSION" ]; then
|
||||
printf "│ 🔄 update available: v%-27s│\n" "$_remote_ver"
|
||||
|
||||
+65
-16
@@ -363,9 +363,10 @@ if [ -d "$GSTACK_DIR" ]; then
|
||||
gstack_bump_playwright_if_unsupported
|
||||
|
||||
info "Running GStack setup..."
|
||||
_gstack_setup_ok=0
|
||||
if [ -x "$GSTACK_DIR/setup" ]; then
|
||||
if (cd "$GSTACK_DIR" && ./setup); then
|
||||
: # setup succeeded
|
||||
_gstack_setup_ok=1
|
||||
else
|
||||
warn "GStack ./setup failed — check output above"
|
||||
fi
|
||||
@@ -381,9 +382,13 @@ if [ -d "$GSTACK_DIR" ]; then
|
||||
&& [ "$(bash "$REPO/lib/toggle-external.sh" status gstack 2>/dev/null)" = "enabled" ]; then
|
||||
info "Disabling gstack by default (no context cost until enabled)..."
|
||||
bash "$REPO/lib/toggle-external.sh" disable gstack >/dev/null
|
||||
ok "gstack installed, disabled — enable with: bash lib/toggle-external.sh enable gstack"
|
||||
fi
|
||||
# Success message gated on the real setup outcome — an unconditional ok
|
||||
# after a `|| warn` reads as success even when setup failed (LRN-071 class).
|
||||
if [ "$_gstack_setup_ok" -eq 1 ]; then
|
||||
ok "GStack ready (disabled by default — enable: bash lib/toggle-external.sh enable gstack)"
|
||||
else
|
||||
ok "GStack ready (submodule initialized, symlinks staged)"
|
||||
warn "GStack NOT ready — ./setup did not complete (see warnings above)"
|
||||
fi
|
||||
|
||||
# GStack shared infrastructure: bin/ (CLI tools) and browse/dist/ (compiled binary).
|
||||
@@ -526,7 +531,9 @@ enable_plugin "security-guidance" "claude-code-plugins"
|
||||
# (not in claude-code marketplace — it's a separate repo)
|
||||
install_plugin "example-skills" "anthropic-agent-skills"
|
||||
install_plugin "pr-review-toolkit" "claude-code-plugins"
|
||||
install_plugin "plugin-dev" "claude-code-plugins"
|
||||
# plugin-dev dropped 2026-07-02 (audit #14): installed 2026-06-23, never
|
||||
# enabled, pure disk weight — reinstall deliberately if plugin authoring
|
||||
# becomes a need: claude plugin install plugin-dev@claude-code-plugins
|
||||
|
||||
echo ""
|
||||
|
||||
@@ -573,11 +580,47 @@ else
|
||||
err "ctx7 install failed — run manually: npm install -g ctx7"
|
||||
fi
|
||||
fi
|
||||
# Suggest setup for Claude Code integration (optional — ctx7 also works standalone)
|
||||
# ctx7 auth — detect, then offer login ONLY in an interactive TTY. A non-interactive
|
||||
# run (CI / headless / re-run) must never open a browser or block on OAuth.
|
||||
if command -v ctx7 &>/dev/null; then
|
||||
info "Run 'ctx7 setup --claude' to configure Context7 for Claude Code"
|
||||
info "Or use ctx7 standalone: ctx7 docs /vercel/next.js \"middleware\""
|
||||
info "Free higher rate limits: ctx7 login (OAuth) or --api-key from context7.com/dashboard"
|
||||
# Deterministic offline oracle: ctx7's OAuth token lives here (XDG-aware).
|
||||
# Present => authenticated; absent => anonymous. No subprocess, no network, no browser.
|
||||
ctx7_creds="${XDG_CONFIG_HOME:-$HOME/.config}/context7/credentials.json"
|
||||
if [ -f "$ctx7_creds" ]; then
|
||||
ok "ctx7 authenticated (full rate limits)"
|
||||
else
|
||||
info "ctx7 works anonymously — docs + library already usable, no auth required."
|
||||
if [ -t 0 ] && [ -t 1 ]; then
|
||||
# Interactive terminal: offer to log in now (opens a browser).
|
||||
printf '%b' "${BLUE}→${NC} Authenticate ctx7 now for higher rate limits? [y/N] "
|
||||
read -r ctx7_ans || ctx7_ans=""
|
||||
if [[ "$ctx7_ans" =~ ^[Yy]([Ee][Ss])?$ ]]; then
|
||||
if ctx7 login; then
|
||||
ok "ctx7 authenticated (full rate limits)"
|
||||
else
|
||||
warn "ctx7 login did not finish — re-run 'ctx7 login' anytime"
|
||||
fi
|
||||
else
|
||||
info "Skipped — authenticate later with: ctx7 login"
|
||||
fi
|
||||
else
|
||||
# Non-interactive (CI / headless / re-run): never block — just guide.
|
||||
info "For higher rate limits, authenticate: ctx7 login (opens a browser)"
|
||||
info " headless: ctx7 login --no-browser (prints a URL to open yourself)"
|
||||
fi
|
||||
fi
|
||||
# CLI + Skills mode: install the find-docs skill into ~/.claude/skills when
|
||||
# absent (it is gitignored — ctx7 owns it, this regenerates it on a fresh
|
||||
# clone). Guarded on absence so a re-run never clobbers a customized config
|
||||
# (setup also (re)writes ~/.claude/rules/context7.md).
|
||||
if [ ! -f "$HOME/.claude/skills/find-docs/SKILL.md" ]; then
|
||||
if ctx7 setup --claude --cli -y </dev/null &>/dev/null; then
|
||||
ok "ctx7 CLI + Skills configured (find-docs skill installed)"
|
||||
else
|
||||
warn "ctx7 setup failed — run manually: ctx7 setup --claude --cli"
|
||||
fi
|
||||
fi
|
||||
info "Standalone usage: ctx7 docs /vercel/next.js \"middleware\""
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
@@ -596,11 +639,18 @@ else
|
||||
fi
|
||||
fi
|
||||
if command -v graphify &>/dev/null; then
|
||||
_graphify_ok=1
|
||||
info "Running graphify install (dependencies)..."
|
||||
graphify install 2>/dev/null || warn "graphify install failed — run manually"
|
||||
graphify install 2>/dev/null || { warn "graphify install failed — run manually"; _graphify_ok=0; }
|
||||
info "Configuring Claude Code integration..."
|
||||
graphify claude install 2>/dev/null || warn "graphify claude install failed — run manually"
|
||||
ok "Graphifyy configured for Claude Code"
|
||||
graphify claude install 2>/dev/null || { warn "graphify claude install failed — run manually"; _graphify_ok=0; }
|
||||
# Success message gated on the real outcome (LRN-071 class: an
|
||||
# unconditional ok after `|| warn` lies when a step failed).
|
||||
if [ "$_graphify_ok" -eq 1 ]; then
|
||||
ok "Graphify configured for Claude Code"
|
||||
else
|
||||
warn "Graphify NOT fully configured — re-run the failed step manually"
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
@@ -861,14 +911,13 @@ echo " ✅ security-guidance — PreToolUse security hook (0 tokens) [claud
|
||||
echo " ✅ rtk — token compression hook (0 tokens)"
|
||||
echo " ✅ superpowers — brainstorm/plan/implement/debug workflow"
|
||||
echo ""
|
||||
echo " TOGGLE (installed but start OFF — /plugin-check recommends when needed):"
|
||||
echo " TOGGLE (plugin state = settings.json enabledPlugins; skills/CLIs = profiles):"
|
||||
echo " 🔄 gstack — disabled by default (toggle: lib/toggle-external.sh enable gstack)"
|
||||
echo " 🔄 gsd v2 — standalone CLI 'gsd' (gsd-pi, not a Claude Code plugin)"
|
||||
echo " 🔄 plugin-dev — create plugins/skills (~100 tokens) [claude-code-plugins]"
|
||||
echo " 🔄 pr-review-toolkit — /pr-review-toolkit:review-pr (~300 tokens) [claude-code-plugins]"
|
||||
echo " 🔄 ui-ux-pro-max — user scope (~400 tokens)"
|
||||
echo " 🔄 pr-review-toolkit — /review-pr + 6 PR agents (~2.2k tokens when enabled) [claude-code-plugins]"
|
||||
echo " 🔄 ui-ux-pro-max — user scope (~780 tokens when enabled)"
|
||||
echo " 🔄 context7 CLI — ctx7 (npm global, standalone or MCP setup)"
|
||||
echo " 🔄 graphifyy — codebase knowledge graph (pipx, PreToolUse hook)"
|
||||
echo " 🔄 graphifyy (CLI: graphify) — codebase knowledge graph (pipx, PreToolUse hook)"
|
||||
echo " 🔄 emil-design-eng — UI polish, animations, component craft (curl → symlink)"
|
||||
echo " 🔄 frontend-design — distinctive frontend interfaces, anti-AI-slop (anthropic-agent-skills)"
|
||||
echo " 🔄 design-motion-principles — motion/animation design, 3-designer lens (kylezantos)"
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
# --- Always-on plugins ---
|
||||
|
||||
detect_rtk() {
|
||||
command -v rtk &>/dev/null
|
||||
command -v rtk &>/dev/null && return 0
|
||||
# PATH heal: hook/session PATH may lack the cargo bin dir (LRN-036 class)
|
||||
[ -x "$HOME/.cargo/bin/rtk" ] || [ -x "$HOME/.local/bin/rtk" ]
|
||||
}
|
||||
|
||||
detect_superpowers() {
|
||||
|
||||
@@ -156,6 +156,22 @@ if bash "$HERE/gitflow.sh" protected-base main; then ok "cli protected-bas
|
||||
if bash "$HERE/gitflow.sh" protected-base feature/x; then no "cli protected-base feature (rc0?)"; else ok "cli protected-base feature → rc1"; fi
|
||||
chk "cli base-for hotfix=main" '[ "$(bash "$HERE/gitflow.sh" base-for hotfix)" = main ]'
|
||||
|
||||
echo "T12 — finish arg-guard (named branch must equal current, else refuse)"
|
||||
newrepo finargs; echo a>a; hookon; gitflow_init >/dev/null 2>&1
|
||||
gitflow_start feature standon >/dev/null 2>&1; echo w>w.txt; git add w.txt; git commit -q -m w
|
||||
# mismatch: standing on feature/standon but asking to finish bugfix/other → refuse
|
||||
# shellcheck disable=SC2034 # mism_out/mism_rc are used in the deferred chk eval strings
|
||||
mism_out="$(gitflow_finish bugfix other 2>&1)"; mism_rc=$?
|
||||
chk "arg-mismatch → nonzero rc" "[ $mism_rc -ne 0 ]"
|
||||
chk "arg-mismatch → HEAD untouched" '[ "$(git symbolic-ref --short HEAD)" = feature/standon ]'
|
||||
chk "arg-mismatch → branch kept" 'git rev-parse --verify -q refs/heads/feature/standon >/dev/null'
|
||||
chk "arg-mismatch → develop NOT merged" '! git log develop --oneline | grep -q "Merge feature/standon into develop"'
|
||||
chk "arg-mismatch → message names both" 'printf "%s" "$mism_out" | grep -q "current branch" && printf "%s" "$mism_out" | grep -q "bugfix/other"'
|
||||
# match: naming the current branch explicitly finishes exactly like the no-arg path
|
||||
gitflow_finish feature standon >/dev/null 2>&1
|
||||
chk "arg-match → merged into develop" 'git log develop --oneline | grep -q "Merge feature/standon into develop"'
|
||||
chk "arg-match → branch deleted" '! git rev-parse --verify -q refs/heads/feature/standon >/dev/null'
|
||||
|
||||
echo
|
||||
echo "==== RESULT: $PASS passed, $FAIL failed ===="
|
||||
[ "$FAIL" -eq 0 ]
|
||||
|
||||
+16
-3
@@ -97,11 +97,24 @@ _gitflow_delete() { # <branch>
|
||||
git branch -q -d "$br" || { echo "gitflow: '$br' not fully merged — branch kept" >&2; return 5; }
|
||||
}
|
||||
|
||||
# gitflow_finish → directed merge of the CURRENT branch per its type, then delete.
|
||||
# WHEN to call this is the human gate (SKILL.md). This only performs the merge.
|
||||
# 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).
|
||||
#
|
||||
# The merge source is ALWAYS the checked-out branch (HEAD) — that is the contract.
|
||||
# The optional <type> <name> is a SAFETY ASSERTION, not a target selector: if you
|
||||
# name a branch it MUST equal the current one, else finish refuses loudly instead
|
||||
# of silently merging whatever you happen to be standing on. (Guards the audit UX
|
||||
# trap: `finish bugfix audit-bugs` run from feature/audit-tokens merged the wrong
|
||||
# branch — args were silently ignored. See BLK-015 / LRN-089.) No args = unchanged.
|
||||
gitflow_finish() {
|
||||
local br type
|
||||
local br type req_type="${1:-}" req_name="${2:-}"
|
||||
br="$(git symbolic-ref --short -q HEAD)" || { echo "gitflow_finish: detached HEAD" >&2; return 3; }
|
||||
if [ -n "$req_type" ] || [ -n "$req_name" ]; then
|
||||
[ "$req_type/$req_name" = "$br" ] || {
|
||||
echo "gitflow_finish: operates on the current branch '$br', but you asked '$req_type/$req_name' — checkout '$req_type/$req_name' first (or run finish with no args)." >&2
|
||||
return 2
|
||||
}
|
||||
fi
|
||||
type="$(gitflow_branch_type "$br")"
|
||||
case "$type" in
|
||||
feature|bugfix|chore)
|
||||
|
||||
@@ -34,8 +34,9 @@ guard
|
||||
learn
|
||||
retro
|
||||
|
||||
# Plugin: PR review toolkit (pre-merge audit)
|
||||
pr-review-toolkit plugin@claude-code-plugins
|
||||
# pr-review-toolkit removed (audit 2026-07-02 #12 — ~2.2k tokens, PR-only):
|
||||
# enable per PR session via `bash lib/profile.sh apply audit` or
|
||||
# claude plugin enable pr-review-toolkit@claude-code-plugins
|
||||
|
||||
# CLIs (advisory)
|
||||
ctx7 cli
|
||||
|
||||
@@ -79,7 +79,12 @@ emil-design-eng external
|
||||
frontend-design external
|
||||
design-motion-principles external
|
||||
ui-ux-pro-max plugin@ui-ux-pro-max-skill
|
||||
pr-review-toolkit plugin@claude-code-plugins
|
||||
# pr-review-toolkit REMOVED from full (audit 2026-07-02 #12): heaviest
|
||||
# single plugin cost (~2.2k tokens of agent descriptions/session), useful
|
||||
# only when reviewing PRs. Reactivate per PR session:
|
||||
# claude plugin enable pr-review-toolkit@claude-code-plugins
|
||||
# or profile-based: bash lib/profile.sh apply audit (audit.profile keeps it;
|
||||
# a later `set full` re-disables it — MANAGED_PLUGINS lifecycle).
|
||||
magic mcp
|
||||
|
||||
# === CLIs (advisory) =================================================
|
||||
|
||||
@@ -65,7 +65,10 @@ if has "$cand" "--help"; then ok "T5 surfaced --help candidate (BDR-001 ⇄ --he
|
||||
echo; echo "=== T6 live oracle smoke — oracles QUERY real git/fs (not a name) ==="
|
||||
if reconcile_oracle_merge_done "$REPO" "prune-memory"; then ok "T6a merge_done(prune-memory) via git log"; else no "T6a merge not found in git"; fi
|
||||
if reconcile_oracle_sha_exists "$REPO" "be1dcef"; then ok "T6b sha_exists(be1dcef) via cat-file"; else no "T6b sha missing"; fi
|
||||
dk="$MEM/../skills/darwin-skill"
|
||||
# $REPO here = lib/ (see line 12) → lib/../skills = the real skills/ dir.
|
||||
# Was "$MEM/../skills" = .claude/skills/ — the LRN-042 parasite dir, removed
|
||||
# 2026-06-30 by make plugin Step 8.5: green-for-wrong-reason (LRN-077 class).
|
||||
dk="$REPO/../skills/darwin-skill"
|
||||
if reconcile_oracle_path_present "$dk"; then ok "T6c path_present(darwin-skill) via fs"; else no "T6c path absent"; fi
|
||||
|
||||
echo; echo "================ $pass GREEN / $fail RED ================"
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
"gsd": {
|
||||
"source": "npm:gsd-pi",
|
||||
"version": "2.64.0",
|
||||
"note": "Check latest at https://www.npmjs.com/package/gsd-pi before updating. GSD v2 is a standalone CLI (Pi SDK), not a Claude Code plugin. Run 'gsd' in terminal, not '/gsd' in Claude Code."
|
||||
"note": "Check latest at https://www.npmjs.com/package/gsd-pi before updating. GSD v2 is a standalone CLI (Pi SDK), not a Claude Code plugin. Run 'gsd' in terminal, not '/gsd' in Claude Code. NOTE: update-all.sh honors this pin — 'make update' will NOT advance gsd past it; bump this version deliberately, then re-run."
|
||||
},
|
||||
"gstack": {
|
||||
"source": "https://github.com/garrytan/gstack.git",
|
||||
|
||||
+43
-4
@@ -46,6 +46,32 @@
|
||||
"Bash(tr *)",
|
||||
"Bash(cut *)",
|
||||
"Bash(diff *)",
|
||||
"Bash(rtk grep *)",
|
||||
"Bash(*/rtk grep *)",
|
||||
"Bash(rtk ls)",
|
||||
"Bash(rtk ls *)",
|
||||
"Bash(*/rtk ls)",
|
||||
"Bash(*/rtk ls *)",
|
||||
"Bash(rtk cat *)",
|
||||
"Bash(*/rtk cat *)",
|
||||
"Bash(rtk head *)",
|
||||
"Bash(*/rtk head *)",
|
||||
"Bash(rtk tail *)",
|
||||
"Bash(*/rtk tail *)",
|
||||
"Bash(rtk wc *)",
|
||||
"Bash(*/rtk wc *)",
|
||||
"Bash(rtk diff *)",
|
||||
"Bash(*/rtk diff *)",
|
||||
"Bash(rtk git status)",
|
||||
"Bash(*/rtk git status)",
|
||||
"Bash(rtk git log*)",
|
||||
"Bash(*/rtk git log*)",
|
||||
"Bash(rtk git diff*)",
|
||||
"Bash(*/rtk git diff*)",
|
||||
"Bash(rtk git show*)",
|
||||
"Bash(*/rtk git show*)",
|
||||
"Bash(rtk git branch*)",
|
||||
"Bash(*/rtk git branch*)",
|
||||
"Read(**/*.md)",
|
||||
"Read(**/*.txt)",
|
||||
"Read(**/*.json)",
|
||||
@@ -63,9 +89,13 @@
|
||||
"deny": [
|
||||
"Bash(rm -rf *)",
|
||||
"Bash(rm -rf /*)",
|
||||
"Bash(rm -r *)",
|
||||
"Bash(rm -fr *)",
|
||||
"Bash(rmdir *)",
|
||||
"Bash(git push --force*)",
|
||||
"Bash(git push --force)",
|
||||
"Bash(git push --force *)",
|
||||
"Bash(git push -f*)",
|
||||
"Bash(git push * +*)",
|
||||
"Bash(git reset --hard*)",
|
||||
"Bash(git clean -fd*)",
|
||||
"Bash(sudo rm*)",
|
||||
@@ -156,10 +186,20 @@
|
||||
"Bash(source /dev/stdin)",
|
||||
"Bash(mkfifo *)",
|
||||
"Bash(node -e *)",
|
||||
"Bash(python3 -c *)",
|
||||
"Bash(python -c *)",
|
||||
"Bash(xargs * .env*)",
|
||||
"Bash(tar * .env*)",
|
||||
"Bash(zip * .env*)",
|
||||
"Bash(base64 .env*)"
|
||||
"Bash(base64 .env*)",
|
||||
"Bash(rtk cat *.env*)",
|
||||
"Bash(*/rtk cat *.env*)",
|
||||
"Bash(rtk grep * .env*)",
|
||||
"Bash(*/rtk grep * .env*)",
|
||||
"Bash(rtk head *.env*)",
|
||||
"Bash(*/rtk head *.env*)",
|
||||
"Bash(rtk tail *.env*)",
|
||||
"Bash(*/rtk tail *.env*)"
|
||||
],
|
||||
"ask": [
|
||||
"Bash(git push *)",
|
||||
@@ -177,7 +217,6 @@
|
||||
"WebFetch",
|
||||
"Bash(xargs *)",
|
||||
"Bash(sed *)",
|
||||
"Bash(python3 -c *)",
|
||||
"Bash(git stash pop*)",
|
||||
"Bash(git stash drop*)",
|
||||
"Bash(git stash clear)"
|
||||
@@ -230,7 +269,7 @@
|
||||
"ui-ux-pro-max@ui-ux-pro-max-skill": true,
|
||||
"security-guidance@claude-code-plugins": true,
|
||||
"superpowers@superpowers-marketplace": true,
|
||||
"pr-review-toolkit@claude-code-plugins": true
|
||||
"pr-review-toolkit@claude-code-plugins": false
|
||||
},
|
||||
"extraKnownMarketplaces": {
|
||||
"claude-code-plugins": {
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
---
|
||||
name: audit-delta
|
||||
description: |
|
||||
Use when the user wants a recurring code audit scoped to everything that
|
||||
changed since the previous audit run (full codebase on first run), on one
|
||||
or more selectable axes: CLAUDE.md norm conformity, bugs/improvements,
|
||||
dead code, security. NOT for one obvious bug (/hotfix, /bugfix), one-shot
|
||||
full cleanup (/code-clean), full security posture (/cso), quality
|
||||
dashboard (/health), or branch/PR diff review (/review, /code-review).
|
||||
Triggers: "audit-delta", "audit since last run", "incremental audit",
|
||||
"audit incrémental", "audit les changements", "audit ce qui a changé
|
||||
depuis la dernière fois", "periodic audit", "audit périodique",
|
||||
"re-run the audit", "relance l'audit", "audit conformité + sécurité".
|
||||
Use when the user wants a recurring code audit scoped to changes since
|
||||
the previous run (full codebase on first run), on selectable axes:
|
||||
CLAUDE.md conformity, bugs, dead code, security. NOT one obvious bug
|
||||
(/hotfix, /bugfix), one-shot cleanup (/code-clean), security posture
|
||||
(/cso), dashboard (/health), branch diff (/review).
|
||||
Triggers: "audit-delta", "incremental audit", "audit incrémental",
|
||||
"audit ce qui a changé", "periodic audit", "relance l'audit".
|
||||
argument-hint: "[axes among: conformity errors deadcode security — blank = asked]"
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
---
|
||||
name: capitalize
|
||||
description: |
|
||||
Use when about to /clear or /compact, or when closing a session, and the
|
||||
conversation holds decisions, learnings, blockers, eval results, or
|
||||
finished/new TODO items not yet written to `.claude/memory/` or
|
||||
`.claude/tasks/TODO.md`. Plain invocation = pre-wipe flush; `--ritual` (or the
|
||||
word "close"/"ritual" in the request) = end-of-session reflection mode. NOT
|
||||
registry curation (that is /prune-memory).
|
||||
Triggers: "capitalize", "capitalise", "before clear", "before compact",
|
||||
"save before clear", "flush memory", "don't lose this", "what's not logged
|
||||
yet", "avant de clear", "avant compact", "sauvegarde avant clear",
|
||||
"capitalise ce qui manque", "close", "end session", "session close",
|
||||
"ferme la session", "checkpoint memory", "what did we learn", "retro rapide",
|
||||
"fin de journée".
|
||||
Use when about to /clear or /compact, or closing a session, with
|
||||
decisions, learnings, blockers, evals, or TODO changes not yet written
|
||||
to .claude/memory/ or .claude/tasks/TODO.md. Plain = pre-wipe flush;
|
||||
--ritual (or "close") = end-of-session reflection. NOT registry
|
||||
curation (that is /prune-memory).
|
||||
Triggers: "capitalize", "before clear/compact", "flush memory", "don't
|
||||
lose this", "avant de clear/compact", "capitalise ce qui manque",
|
||||
"close", "fin de journée", "checkpoint memory".
|
||||
argument-hint: "[--ritual] (scans conversation + git + TODO against .claude/memory/; --ritual adds the 3-question reflection)"
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
---
|
||||
name: client-handover
|
||||
description: |
|
||||
Use when finalizing a project for non-technical client delivery — needs
|
||||
final audits, deploy validation against live site, and a branded
|
||||
deliverable (Markdown + HTML + PDF). Multi-agent orchestrator: dispatches
|
||||
client-handover-writer which spawns parallel /seo + /harden subagents,
|
||||
then /web-validate, then writes the deliverable.
|
||||
Triggers: "client handover", "compte rendu client", "livraison client",
|
||||
"rapport client", "deliverable", "summary for client", "handover doc",
|
||||
"livrable", "ship and handover", "finaliser et livrer".
|
||||
Use when finalizing a project for non-technical client delivery —
|
||||
final audits, live-site validation, branded deliverable (MD + HTML +
|
||||
PDF). Orchestrator: client-handover-writer spawns /seo + /harden in
|
||||
parallel, then /web-validate, then writes the deliverable.
|
||||
Triggers: "client handover", "livraison client", "rapport client",
|
||||
"deliverable", "livrable", "finaliser et livrer".
|
||||
argument-hint: [optional: language fr|en, --include-deploy, --skip-deploy, --skip-seo, --skip-audits, --skip-fix-loop, --max-iterations N, --audit-max-age <duration>, --output <path>]
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
name: code-clean
|
||||
description: |
|
||||
Full codebase cleanup: dead code removal, style/norm enforcement, structural
|
||||
issues. Two-phase workflow: audit first (read-only report), then execute
|
||||
approved fixes only. Delegates refactoring to the refactorer agent.
|
||||
Trigger: "code-clean", "clean up the code", "remove dead code",
|
||||
"enforce code style", "cleanup", "nettoyage du code", "code hygiene".
|
||||
For targeted refactoring without audit → use /refactor instead.
|
||||
For bug fixes discovered during cleanup → logged to .claude/audits/BUGS-FOUND.md, not fixed here.
|
||||
Full codebase cleanup: dead code, style/norm enforcement, structural
|
||||
issues. Two-phase: read-only audit, then approved fixes only
|
||||
(refactorer agent).
|
||||
Triggers: "code-clean", "remove dead code", "cleanup", "nettoyage du
|
||||
code", "code hygiene".
|
||||
Targeted refactor without audit → /refactor. Bugs found → logged to
|
||||
.claude/audits/BUGS-FOUND.md, not fixed here.
|
||||
argument-hint: <file, directory, or blank for entire project>
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
@@ -2,13 +2,12 @@
|
||||
name: commit-change
|
||||
version: 1.0.0
|
||||
description: |
|
||||
Analyze all changes since the last commit (staged, unstaged, untracked files)
|
||||
and create well-structured commits grouped by logical unit. Use this skill
|
||||
whenever the user says "commit my changes", "smart commit", "auto commit",
|
||||
"commit everything", "analyse et commit", or any variation of wanting to
|
||||
commit their pending work intelligently. Also trigger when the user has
|
||||
been working on multiple things and wants to create clean, atomic commits
|
||||
from their messy working directory. Works in any git repository.
|
||||
Analyze all pending changes (staged, unstaged, untracked) and create
|
||||
atomic commits grouped by logical unit, retracing the work. Any git
|
||||
repository.
|
||||
Triggers: "commit my changes", "smart commit", "auto commit", "commit
|
||||
everything", "analyse et commit", or any variation of committing messy
|
||||
pending work intelligently.
|
||||
allowed-tools:
|
||||
- Bash
|
||||
- Read
|
||||
|
||||
+6
-8
@@ -1,14 +1,12 @@
|
||||
---
|
||||
name: doc
|
||||
description: |
|
||||
Use when documentation may be out of sync with code — added features
|
||||
missing from docs, removed features still documented, or README / INSTALL
|
||||
/ DEPLOY / CHANGELOG drift detected. Stack-aware audit, cross-references
|
||||
git history, patches approved items.
|
||||
Triggers: "doc", "sync docs", "audit docs", "update readme", "check
|
||||
documentation", "are docs up to date", "documentation drift", "stale docs",
|
||||
"new feature not documented", "removed feature still in docs",
|
||||
"create README", "should I have a DEPLOY doc".
|
||||
Use when documentation may be out of sync with code — features
|
||||
added/removed vs README / INSTALL / DEPLOY / CHANGELOG. Stack-aware
|
||||
audit, cross-references git history, patches approved items.
|
||||
Triggers: "doc", "sync docs", "update readme", "documentation drift",
|
||||
"stale docs", "docs à jour ?", "create README", "should I have a
|
||||
DEPLOY doc".
|
||||
argument-hint: [leave empty for full audit, or list specific files/docs to check]
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
+5
-8
@@ -2,14 +2,11 @@
|
||||
name: geo
|
||||
description: |
|
||||
Use when a web project needs AI-search visibility audit — ChatGPT,
|
||||
Perplexity, Claude, Gemini, AI Overviews, Copilot, Brave AI, DuckAssist,
|
||||
You.com, Apple Intelligence. Standalone GEO; dispatches the geo-analyzer
|
||||
agent.
|
||||
Triggers: "geo", "AI search", "ChatGPT visibility", "Perplexity
|
||||
optimisation", "llms.txt", "AI crawlers", "Google AI Overview",
|
||||
"entity SEO", "Wikidata", "generative engine optimization",
|
||||
"référencement IA", "optimisation IA".
|
||||
For combined SEO+GEO → /seo.
|
||||
Perplexity, Gemini, AI Overviews, Copilot… Standalone GEO; dispatches
|
||||
the geo-analyzer agent.
|
||||
Triggers: "geo", "AI search", "llms.txt", "AI crawlers", "entity SEO",
|
||||
"Wikidata", "generative engine optimization", "référencement IA".
|
||||
Combined SEO+GEO → /seo.
|
||||
argument-hint: optional keywords/scope, e.g. "SaaS B2B content GEO" or "audit llms.txt et entity SEO"
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
+7
-15
@@ -1,21 +1,13 @@
|
||||
---
|
||||
name: harden
|
||||
description: |
|
||||
Web hardening audit — transport (HTTPS/TLS, HTTP→HTTPS redirect, HSTS),
|
||||
security headers (CSP, X-Frame-Options, X-Content-Type-Options,
|
||||
Referrer-Policy, Permissions-Policy), cookie flags (Secure, HttpOnly,
|
||||
SameSite), canonical URLs, custom 404, and server config hardening
|
||||
(.htaccess, nginx.conf, netlify.toml, vercel.json, _headers, _redirects,
|
||||
wrangler.toml). Dispatches the seo-analyzer agent with a STRICT scope
|
||||
filter — no meta/OG/JSON-LD/sitemap/CWV/headings/alt/i18n noise.
|
||||
Produces .claude/audits/HARDEN.md.
|
||||
Trigger: "harden", "web hardening", "ssl audit", "https audit",
|
||||
"hsts", "csp", "security headers", "http to https", "redirect audit",
|
||||
"htaccess audit", "404 page", "canonical audit", "transport security",
|
||||
"durcissement web", "audit sécurité web", "entêtes sécurité".
|
||||
For full SEO audit (meta/OG/JSON-LD/sitemap/CWV) → use /seo.
|
||||
For AI search / llms.txt / AI crawlers → use /geo.
|
||||
For secrets / dependency CVEs / OWASP code-level → use /cso.
|
||||
Web hardening audit — HTTPS/TLS, HSTS, security headers (CSP,
|
||||
X-Frame-Options…), cookie flags, canonical, custom 404, server config
|
||||
(.htaccess, nginx, netlify, vercel…). Strict scope: no
|
||||
meta/OG/JSON-LD/sitemap noise. Report: .claude/audits/HARDEN.md.
|
||||
Triggers: "harden", "security headers", "csp", "hsts", "https/ssl
|
||||
audit", "redirect audit", "durcissement web", "entêtes sécurité".
|
||||
Meta/sitemap/CWV → /seo. llms.txt/AI → /geo. Secrets/CVE/OWASP → /cso.
|
||||
argument-hint: [URL] [--fix] [--local|--full] [--no-external]
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
+7
-10
@@ -1,16 +1,13 @@
|
||||
---
|
||||
name: seo
|
||||
description: |
|
||||
Use when a web project needs SEO + GEO audit or optimization — classical
|
||||
search (Google, Bing, DuckDuckGo) AND AI search (ChatGPT, Perplexity,
|
||||
Claude, Gemini, AI Overviews, Copilot). Parallel multi-agent orchestrator:
|
||||
dispatches seo-analyzer + geo-analyzer concurrently, merges envelopes into
|
||||
.claude/audits/SEO.md.
|
||||
Triggers: "seo", "referencement", "audit SEO", "meta tags",
|
||||
"structured data", "JSON-LD", "sitemap", "robots.txt", "Google ranking",
|
||||
"local SEO", "AI search", "GEO", "llms.txt", "ChatGPT visibility",
|
||||
"Perplexity", "Google AI Overview".
|
||||
For GEO only → /geo. For W3C/a11y → /web-validate. For bugs → /bugfix.
|
||||
Use when a web project needs SEO + GEO audit or optimization —
|
||||
classical search (Google, Bing) AND AI search (ChatGPT, Perplexity, AI
|
||||
Overviews). Parallel orchestrator: dispatches seo-analyzer +
|
||||
geo-analyzer concurrently, merges into .claude/audits/SEO.md.
|
||||
Triggers: "seo", "referencement", "meta tags", "JSON-LD", "sitemap",
|
||||
"robots.txt", "local SEO", "llms.txt", "ChatGPT visibility".
|
||||
GEO only → /geo. W3C/a11y → /web-validate. Bugs → /bugfix.
|
||||
argument-hint: optional keywords/scope, e.g. "local SEO plombier 91 94 77" or "SaaS B2B content strategy"
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
---
|
||||
name: web-validate
|
||||
description: |
|
||||
Use when a web project needs W3C HTML/CSS validity check or WCAG 2.1
|
||||
accessibility audit. Dispatches the validator-analyzer agent with a
|
||||
STRICT scope filter (no meta/OG/JSON-LD/CWV/security-header noise).
|
||||
Triggers: "validate", "validation", "w3c", "html validity",
|
||||
"css validity", "wcag", "accessibility", "a11y audit", "axe", "pa11y",
|
||||
"wave", "validator.w3.org", "nu validator", "accessibilité",
|
||||
"audit a11y", "audit wcag", "normes w3c", "conformité web".
|
||||
For CSP/HSTS/404 → /harden. For meta/sitemap → /seo. For AI engines → /geo.
|
||||
Use when a web project needs W3C HTML/CSS validity or WCAG 2.1
|
||||
accessibility audit. Dispatches the validator-analyzer agent, strict
|
||||
scope (no meta/security-header noise).
|
||||
Triggers: "validate", "w3c", "wcag", "a11y", "accessibility", "axe",
|
||||
"pa11y", "accessibilité", "conformité web".
|
||||
CSP/HSTS/404 → /harden. Meta/sitemap → /seo. AI engines → /geo.
|
||||
argument-hint: [URL] [--fix] [--local|--full] [--no-external]
|
||||
allowed-tools:
|
||||
- Read
|
||||
|
||||
@@ -227,6 +227,27 @@ else
|
||||
info "graphifyy not installed — skipping"
|
||||
fi
|
||||
|
||||
# ── 6.5. Update bun ──
|
||||
echo ""
|
||||
echo "── Updating bun..."
|
||||
if command -v bun &>/dev/null; then
|
||||
if bun upgrade >/dev/null 2>&1; then
|
||||
ok "bun $(bun --version 2>/dev/null || echo '?') (self-upgrade)"
|
||||
else
|
||||
warn "bun upgrade failed — try manually: bun upgrade"
|
||||
fi
|
||||
else
|
||||
info "bun not installed — skipping"
|
||||
fi
|
||||
# NOT updated here, deliberately (audit 2026-07-02):
|
||||
# - magic MCP: registered as `npx -y @21st-dev/magic@latest` — npx resolves
|
||||
# the latest release at every invocation, nothing to upgrade.
|
||||
# - graphify Claude integration (`graphify claude install`): rewrites curated
|
||||
# CLAUDE.md / .claude/settings.json (BDR-028 guard territory) — re-run
|
||||
# MANUALLY only if a graphify upgrade changes its hook format.
|
||||
# - gsd: pinned in plugins.lock.json — Step 4 reinstalls the PIN, it does not
|
||||
# advance it. Bump the lock deliberately, then re-run.
|
||||
|
||||
# ── 7. Update Emil Design Engineering skill ──
|
||||
echo ""
|
||||
echo "── Updating Emil Design Engineering..."
|
||||
|
||||
Reference in New Issue
Block a user