Commit Graph
208 Commits
Author SHA1 Message Date
bastien c859ae256f feat(effort): entry level on every skill next to its model pin (BDR-108)
- lib/effort-pins.txt (map) + lib/effort-pins.sh (idempotent re-apply)
  replace the hardcoded brainstorming/writing-plans loop; called after the
  last vendoring step of install-plugins.sh AND update-all.sh (the resync
  dropped the pins until the next make plugin)
- design stack high uniform (last loaded wins), superpowers, agent-skills,
  21st pack pinned from the map; skills-perso low, pdf-translate medium,
  site-motion high
- doctrine: design stack loads paired with the first Read; one level per
  stack (CLAUDE.global.md, lib/effort-shift.md)
- lib/effort-audit.py prints thinking coverage per scope (sub-agent records
  carry no thinking count on ~94 % of requests)
- census map-driven + fixture suite lib/tests/effort-pins.test.sh; docs
  README/USAGE/CHANGELOG; contract + TODO plan
2026-09-29 13:15:41 +02:00
bastien a5b3374fb2 fix(gitflow): push hook names itself in its failure message (post-merge said post-commit) 2026-09-29 13:05:31 +02:00
bastien 347073a0cc fix(gitflow): pre-commit gitleaks scan falls back to protect --staged on < 8.19
Ubuntu's gitleaks 8.16 package has no git subcommand, so the hook's
"unknown command" exit 1 blocked every commit as a leak. Probe
gitleaks git --help once, fall back to protect --staged; regenerate the
installed hooks. T16c simulates a missing binary with a /usr/bin symlink
farm minus gitleaks instead of a shorter PATH.
2026-09-28 21:40:58 +02:00
bastien 58c3a3e9b7 fix(effort): re-raise judgment dispatches, planning re-asserts, pairing caveat, dedupe audit script (final review I1-I3) 2026-09-28 20:48:27 +02:00
bastien a3b479e984 fix(effort): reflow effort-audit.py to 80 columns (R12) 2026-09-28 20:27:46 +02:00
bastien 98ef991958 docs(effort): BDR-107 id, CHANGELOG entry, spec corrected for the rulings (vendored pins, exclusions, pairing rule) 2026-09-28 20:20:05 +02:00
bastien 1e3339358c feat(effort): transcript audit script for the thinking/cost split 2026-09-28 20:14:00 +02:00
bastien dd9488964b feat(effort): re-assert the skill level after prose gates that end the turn 2026-09-28 20:04:11 +02:00
bastien 557e4cc317 feat(effort): max at the verify-secure caps and ship-feature 4b; STOP texts suggest /effort-max 2026-09-28 20:02:56 +02:00
bastien a117e7ed67 fix(effort): shifts are sent with the step's first tool call (harness pairing rule); challenge shifts under their heading; fence indentation 2026-09-28 19:55:47 +02:00
bastien 3c58160d0c feat(effort): wire phase shifts in the 13 orchestrators and the handover writer 2026-09-28 19:44:22 +02:00
bastien 4a450ea6bc feat(effort): five shifter skills, lib/effort-shift.md, model-gate second axis 2026-09-28 19:32:26 +02:00
bastien 3de9d4f85a fix(effort): find-docs is ctx7-generated and gitignored, no entry level (30 skills, not 31) 2026-09-28 19:23:43 +02:00
bastien bac235cb33 feat(effort): xhigh on the vendored brainstorming and writing-plans, re-applied at resync 2026-09-28 19:21:15 +02:00
bastien 94189adbc6 feat(effort): entry effort level on the 31 user-invoked skills (spec D3)
A/B /reconcile headless — BEFORE requests=18 output=12374 thinking=3135 effort={'high'} duration_ms=96518 / AFTER requests=15 output=9038 thinking=2248 effort={'low'} duration_ms=78410
2026-09-28 19:11:21 +02:00
bastien 9223fda99f feat(effort): pin effort on the 20 repo-authored agents (BDR-077 second axis) 2026-09-28 18:59:49 +02:00
bastien 45ae0d1217 feat(effort): session default high, env-var warning, live effort in statusline 2026-09-28 18:52:36 +02:00
bastien 5437638437 test(effort): census suite skeleton with flip-test and settings lock 2026-09-28 18:49:40 +02:00
bastien 0deb5594d5 fix(floor-guard): word-bound the bare Jasmine skip patterns
skip_kind matched SKIP_SUBSTRINGS as plain substrings, so 'xit(' hit
exit(, SystemExit( and process.exit(, and 'fit(' hit model.fit( and
profit(, flagging FLOOR SKIP on ordinary test-file lines (BLK-023). The
four bare identifiers (xit, fit, xdescribe, fdescribe) now match through
SKIP_IDENT_RE with an identifier-boundary lookbehind; the dotted and
decorator forms stay substrings. Flip-test fixtures cover the false
positive (RED before, GREEN after) and the three focus/skip calls.
2026-09-28 16:57:47 +02:00
bastien ddea411491 chore(config): superpowers citers by bare name, routing map, docs, settings
Every superpowers-prefixed skill call in ship-feature, init-project, tour,
deploy, audit-delta, plugin-advisor and lib/analyze-before-plan now names
the vendored skill directly. finishing-a-development-branch is described
as the upstream skill this config does not vendor (gitflow finish is the
integration path). CLAUDE.global.md Skill routing maps the four
non-vendored skills the vendored text still references. settings.json
loses the plugin key and its marketplace block; README, USAGE,
plugin-advisor and the profile skill describe superpowers as vendored
skills, always on, zero plugin cost. CHANGELOG entry with a known
residual.
2026-09-28 14:54:53 +02:00
bastien 18f8c898f8 feat(superpowers): vendor the 7 wired skills at v6.4.1, drop the plugin
plugins.lock.json gains a superpowers entry (obra/superpowers @ 5bf4e78,
path skills, per-skill file lists, always_on) that lib/vendor-skills.sh
fetches byte-for-byte: brainstorming, writing-plans,
subagent-driven-development, test-driven-development,
requesting-code-review, using-git-worktrees, writing-skills. install-plugins
STEP 8e vendors it, update-all refreshes it at the pin, link.sh links the
seven, .gitignore ignores them. The plugin is no longer installed or
protected: its 8 other skills duplicated personal flows and its
SessionStart injection cost ~900 tokens per start, clear and compact.
detect_superpowers is one file test on the linked skill; doctor and
session-start stop charging the injection. doctor-vendored gains an
always_on class (third lock column) so always-on externals are
link-checked instead of reported parked.
2026-09-28 14:54:52 +02:00
bastien bd3e525bb3 feat(design-gate): ask for 21st login and wait instead of skipping
The design gate checked the 21st CLI with command -v only, so an
installed-but-signed-out CLI read as READY and every 21st step failed
downstream. tool_active now probes 21st whoami through a three-state
function: signed in (TWENTYFIRST_TOKEN or API_KEY_21ST set, or 'Logged in
as'), signed out (exact 'Not logged in'), unknown (rc != 0, timeout,
unexpected output). Signed out is a new verdict, SIGN-IN REQUIRED, exit
12: design-gate.md tells the orchestrator to ask the user to run
! 21st login, end the turn, re-run the gate on their reply, and to skip
21st only on an explicit 'proceed without 21st', never silently. Unknown
surfaces as exit 11 with the whoami diagnostic and a CLI-runtime remedy,
so a node/PATH failure can never loop on a sign-in prompt. INCOMPLETE
still wins. Hermetic suite lib/tests/design-tool-gate.test.sh (stub CLI,
fixture repo through DESIGN_GATE_REPO_OVERRIDE) covers every state.
2026-09-28 12:51:55 +02:00
bastien 02b62f787e fix(gstack): one helper-link tree for every hardcoded path, honest doctor stats
gstack skills hardcode ~/.claude/skills/gstack/<path> for 83 shared assets
(bin, scripts/jargon-list.json, ETHOS.md, */sections, review/specialists,
make-pdf/dist, lib/diagram-render/dist, freeze/bin...) but only bin and
browse/dist were linked: make-pdf and diagram failed on every run, cso and
plan-*-review could not read their sections, the freeze hook exited 127.
lib/gstack-links.sh links every top-level entry except SKILL.md, skips
non-skill dirs holding a nested SKILL.md (browser-skills, openclaw,
node_modules), removes the global symlink gstack ./setup plants and refuses
a destination inside the submodule. link.sh, install-plugins.sh and
update-all.sh all call it (three hand-copied blocks gone).

doctor.sh counted 34 skills (find without -L) and zero chars for block
scalar descriptions; lib/doctor-skills.sh reuses the census parser and
counts through the symlinks. Plugin constants re-based on measured values;
install-plugins.sh notes why frontend-design@claude-plugins-official and
brightdata-plugin@synced stay off and describes security-guidance truthfully.
2026-09-28 11:48:45 +02:00
bastien f83f8f755b feat(profiles): prune the gstack catalog, add max, honor a removed denylist
Nine gstack skills leave every profile (ship is trunk-based on Gitea,
land-and-deploy auto-merges and deploys, setup-deploy, autoplan reads
paths that do not exist here, context-save has no restore, learn is an
unused parallel store, careful and guard hooks never fired, design-shotgun
needs an absent OpenAI key). lib/gstack-removed.sh is the single denylist;
profile.sh gstack on and toggle-external.sh enable gstack skip it.

full now carries everything every other profile carries (user rule), minus
the parked make-pdf, diagram and 21st-ai/ui-explore/ui-review, which live
in the new max profile together with pr-review-toolkit. The 21st trio also
leaves web, web-full and design (redundant with impeccable + ui-ux-pro-max).

lib/tests/profile-census.test.sh asserts the invariants live and on a
baseline fixture plus one mutant per invariant; gstack-removed.test.sh
covers both restore paths.
2026-09-28 11:48:44 +02:00
bastien 6394fa79fc feat(doctor): check the vendored external skills
lib/doctor-vendored.sh check_vendored_skills: every curl-pinned lock entry
has its files under skills-external/ (list, dict, single-path shapes),
every link.sh EXTERNAL_SKILLS name is symlinked into ~/.claude/skills when
the active profile lists it, parked names reported not failed, hints make
plugin / make link. Lock shape-validated (warn, never a traceback), profile
and item names allowlisted before becoming paths. Suite: 11 cases.
2026-09-28 04:11:16 +02:00
bastien 415b44ed25 fix(lib): vendor-skills validates lock fields, fullmatch guard
Two security-gate LOW notes closed on user ask: the SAFE guard uses
re.fullmatch so a trailing newline is rejected; commit (40 hex), source
(github.com owner/repo) and path (SAFE class, no traversal) are validated
before any URL is built, INVALID marker names the field. Suite 12 cases.
2026-09-28 02:35:52 +02:00
bastien ba14b5ea03 feat(skills): site-motion, site-level scroll and transition choreography
Personal skill distilling the MengTo motion pack invariants (LRN-141):
gates first (reduced motion renders final states, content visible without
JS, compositor-only, offscreen pause), one smooth-scroll engine with the
Lenis/ScrollTrigger sync, Astro ClientRouter lifecycle, numbered recipes
(reveal, scrub, sticky stack, video and image scrub, TreeWalker split,
progressive blur, marquee, WebGL budgets), upstream pitfalls, checklist.
Routed into the Build UI chain of CLAUDE.global.md and lib/design-gate.md.
2026-09-28 01:40:01 +02:00
bastien 2a1ad1797b feat(lib): vendor-skills helper, five MengTo scroll skills pinned
lib/vendor-skills.sh: vendor_pinned_skills <lock-key> [refresh], list or
dict lock shapes, lock read via python argv, traversal and charset guard
on lock values, VENDOR_BASE_URL honoured only as file:// (hermetic suite),
per-file tmp+mv, refresh skips a skill never installed. install-plugins.sh
Step 8e and update-all.sh 7.3 call it for agent-skills and mengto-skills.
Vendored at a965851: scroll-world-storytelling, build-threejs-scroll-worlds
(+5 references), scroll-scrubbed-visual-sequence, scroll-scrubbed-word-
reveal, scroll-progress-timeline; text files only. Registered in link.sh,
.gitignore, toggle-external, profile.sh and the design/web/web-full/full
profiles, which also list site-motion (personal). Suite: 8 cases.
2026-09-28 01:40:01 +02:00
bastien 6617889b77 feat(verifier): floor-guard waivers outside test files need a CLARIFICATIONS ack
Security-gate MEDIUM: a self-service floor-guard: allow <reason> neutralised
the detector in the same commit. User chose strict: the tool prints WAIVED,
the contract authorizes, the verifier counts the rest as gaps. BDR-102
amendment.
2026-09-27 21:20:36 +02:00
bastien 409db51af9 test(lib): skill-routing census, TF-IDF collisions across the live catalog
Top 10 description pairs, WARN >= 0.50, FAIL >= 0.75, fixture flip-test
with a positive control and a sensitivity re-run (2-doc corpora are
degenerate, LRN-172). Baseline 2026-09-27: 120 skills, max 0.52
(careful ~ guard). Adapted from agent-skills evals Tier 2.
2026-09-27 20:17:37 +02:00
bastien 2b25cb4704 feat(lib): floor-guard, diff-scoped detector of a weakened quality bar
SUPPRESS / SKIP / DELETED_TEST / ASSERT_DROP / STUB / THRESHOLD_DOWN over
git diff <base> (untracked files included), floor-guard: allow <reason>
waiver printed as WAIVED, rc 0/2/3. Mandatory verifier STEP 3, documented
under GATE 1 of verify-secure-loop.md. Suite: 6 kinds + WAIVED + CLEAN,
flip-tested. Adapted from agent-skills constraint-driven-development.
2026-09-27 20:17:36 +02:00
bastien d28c45ed19 feat(skills): vendor agent-skills trio at a pinned commit, emil precedent
observability-and-instrumentation, deprecation-and-migration,
ci-cd-and-automation from addyosmani/agent-skills 2686b620, curl'd into
skills-external/<name>/ by install-plugins.sh Step 8e (tmp+mv), refreshed
by update-all.sh 7.3, symlinked by link.sh, registered in toggle-external,
profile.sh and the full/backend/dev profiles. Pin read from the lock via
argv, never hardcoded. Case 2 of the 6-repo review, BDR-102.
2026-09-27 20:17:36 +02:00
bastien bbe1087bd8 fix(profiles): full lacked the web/doc gstack tools superpowers does not cover
`scrape`, `skillify` (Browser + dogfooding) and `diagram`, `make-pdf`
(Docs + translation) join the default profile, user go. The rest of the
BDR-017 exclusion list (ios-*, connect-chrome duplicate of
open-gstack-browser, gstack-internal tooling) stays out; enable it per
session with `profile apply` when needed.
2026-09-25 18:12:15 +02:00
bastien 0d035fcab6 feat(profile): default profile = full; reset applies it, current is label-driven
No profile selected (.active-profile absent, empty or legacy "none") now
means the `full` profile is in force: DEFAULT_PROFILE declared once in
lib/profile.sh, resolved by active_profile(); the statusline reads the
constant and shows `full` instead of `?`; `gstack off` trims to it instead
of erroring. `reset` goes to the default profile (= `set full`: enables its
list, parks any non-listed gstack or managed item). `current` names the
active label and scores that profile only, saying `default — not applied
yet` until a set/apply/reset wrote the cache; the "none" sentinel and the
cross-profile best-guess scan are gone (they keyed on the parked-gstack
count, which says nothing under BDR-030's gstack-off default). Hermetic
suite lib/tests/profile-default.test.sh (29 checks) seeds gstack as OFF like
a real tree. Citers updated: profile SKILL, Makefile help, plugin-advisor
PROFILE line + reset paragraph, toggle-external header.
2026-09-25 16:28:21 +02:00
bastien e1963284d2 chore(21st): drop magic MCP residue
The magic MCP wiring left with BDR-093; this removes the prose that still
described it: gitleaks allowlist note, Step 8.7 header, plugins.lock note,
profile.sh comments and the usage() NOTE that still claimed `set` toggles
"the magic MCP", the managed-set test header, README (one history sentence
kept; MCP-era risk paragraph and the retired bashrc wrapper claim dropped).
.env.example carries the same scrub in the working tree; staging it is
denied to the agent (`git add .env*`), the user stages it.
2026-09-25 16:06:20 +02:00
bastien 27f201d4aa feat(guardrails): refusal ends the attempt; doctrine-citers census; make test suite=
Root causes of the 2026-09-24 errors turned into mechanisms (BDR-100). hard_deny 'Routing around a guardrail': a refused command is never rerun through a wrapper, alias, heredoc, Makefile target, env file, other shell or other agent; the same clause in 14 agents and in the doctrine's sub-agent rule. make test suite=<file> runs one suite hermetically so the denied env-prefix form is never needed by hand. lib/tests/doctrine-citers.test.sh: every CLAUDE.md "Section" / § Label citation across skills, agents, lib, rules and hooks must resolve to a heading or bold label (flip-tested); its first run fixed rest-api-node.md. Doctrine 'After code changes' step 4: a changed rule, heading, label or threshold → grep every citer in the same commit.
2026-09-24 20:58:25 +02:00
bastien d82c06f572 refactor(doctrine): C2 coherence — 30 doctrine/skill tensions resolved, doctrine wins (BDR-099)
One ask policy; mandated executors exempt from the delegation rule; skill plan satisfies the planning rule; journal line exempt from the approval gate; chore = maintenance without new behaviour; small fix on develop = bugfix; BDR-068 written as the one auto-finish exception; deploy routes to /deploy. Skills and agents follow: hotfix types by base + skips the design gate on trivial; capitalize/close create missing registries; commit-change asks the branch type; doc/seo/web-validate/refactor branch through the aiguillage; tour reports BREAKING fixes as needs-decision and runs doc-syncer two-mode; client-handover applies audit bundles from its main loop behind one gate; init-project/onboard use the 200-file graphify signal and bootstrap memory; release-candidate gates the tag push only; push wording aligned with the BDR-095 hooks; stale pointers fixed (§ Language, .gsd/ROADMAP.md, handover script path, design-gate lists).
2026-09-24 20:25:40 +02:00
bastien 1b20beccda fix(gitflow): init on an existing repo under the machine-wide hooks lands the socle via a chore/gitflow-adopt merge (T2c) 2026-09-24 20:25:39 +02:00
bastien c81b1731af feat(graphify): threshold signal from 200 tracked code files, the banner informs and the user decides
lib/graphify-gate.sh counts tracked code files (graphify's AST extension set, vendored trees excluded) and, from 200 with no graphify-out/graph.json, prints one banner-sized line; session-start shows it with the /graphify hint. Nothing is built, installed or updated: the rule is the user's (BDR-097), grounded in the LRN-162 measurements (AST build 2.3 s, 0 tokens, a query 2 to 3k tokens). Doctrine section and plugin-advisor thresholds follow the same rule; graphify claude install stays rejected. Test: 11 checks. GRAPHIFY_MIN_CODE_FILES overrides the threshold.
2026-09-24 12:12:16 +02:00
bastien 68c9df354b feat(gitflow): remove the origin copy of a branch once its merge is verified
`gitflow_delete` now ends with `_gitflow_delete_remote`: after the local
copy is gone, the remote tip is read with `ls-remote --exit-code`, checked
against develop/main with the same ancestor test, and only then removed
with `push origin --delete`. Same contract as the pushes (BDR-095): best
effort, warn never fail. No origin, `GITFLOW_NO_PUSH=1` or
`gitflow.autopush false` skip it; an unreachable origin or a remote tip
holding commits the bases lack keeps the remote branch, loudly. A base is
never targeted, by construction and by an explicit guard.

The static deny on hand `git push --delete` stays: it matches the Bash
tool's command string, the lib is the sanctioned path. Prose (hard_deny,
environment), doctrine, gitflow SKILL (table, op, warning row),
SETTINGS.md and CHANGELOG updated. T24: 9 checks (finish removes the
copy, bases untouched, unmerged remote tip kept, never pushed silent,
unreachable origin loud, autopush opt-out). 161/163, the 2 failures are
the pre-existing T16a (gitleaks absent on this host).
2026-09-24 11:50:16 +02:00
bastien 32d8f981df feat(gitflow): delete a branch only after a verified merge, main/develop undeletable
Since BDR-095 `start` sets an auto-pushed upstream, so `git branch -d`
checked "merged into origin/<branch>" (always true, the post-commit hook
keeps it in sync) instead of "merged into develop". T22a proves it: an
unmerged feature with its upstream in sync is deleted by `-d` alone.

- `gitflow_delete` is the single delete path (finish + CLI `delete`):
  refuses main/develop (rc 6) and any branch that is not an ancestor of
  develop or main (rc 5, `gitflow_merged_into_base`, fail closed when
  neither base exists), then `-d` as a second layer. CLI `merged`, `hooks`.
- Fourth generated hook `reference-transaction`: in the `prepared` call,
  a deletion of refs/heads/main or refs/heads/develop exits 1, whatever
  issued it (branch -d/-D, update-ref -d, rename, script, sub-agent).
  `git config gitflow.protect false` opts a foreign clone out.
- `GITFLOW_HOOKS` is the one hook list: write/emit/reconcile, T19d and
  doctor.sh (`gitflow.sh hooks`) read it. `.githooks/` and `githooks/`
  regenerated with the fourth hook.
- settings.json: static deny on hand `git branch -d/--delete/-dr/-rd` and
  on renames of main/develop; hard_deny "Branch deletion by hand"; the
  Disarming entry covers all four hooks and `gitflow.*` config; the
  protected-branches environment line states the rule.
- Doctrine (CLAUDE.global.md gitflow section), gitflow SKILL (`delete`
  op, rc 5/6 rows, common mistake), guard-bash spec T8w flips to deny,
  SETTINGS.md, README, CHANGELOG.
- Tests: T22 (12) lib guard incl. the premise proof, T23 (11) hook;
  T19 covers the fourth hook. 152/154, the 2 failures are the
  pre-existing T16a (gitleaks absent on this host).
2026-09-24 11:35:01 +02:00
bastien f608d34c3e feat(gitflow): hooks in every repo, no per-project step
Global: `make link` generates githooks/ from lib/gitflow.sh and sets git's
global core.hooksPath to ~/.claude/githooks, so every repo on the machine
runs the pre-commit protection and the post-commit / post-merge push, even
one that never ran gitflow init. A repo's own local core.hooksPath still
wins, so hooks/session-start.sh calls `gitflow reconcile-hooks` once per
session and rewrites a .githooks/ that lags the lib (LRN-114 automated);
the pre-commit exemption now covers .githooks/** next to .claude/**.

Per-repo opt-outs for a foreign clone: `git config gitflow.protect false`
(branch model) and `git config gitflow.autopush false` (push). Both, and
the GIT_CONFIG_GLOBAL= / GIT_CONFIG= env bypass, are static deny rules.

`make test` and the two suites that commit on main export
GIT_CONFIG_GLOBAL=/dev/null so the machine's global hooks never fire in
throwaway repos. doctor gains "Git hooks" (global setting, githooks/ equal
to the emitters) and "Scratchpad" (warn when TMPDIR sits on a tmpfs with
usrquota: systemd caps each user at 80% of it, which killed two shells
today, BLK-021). Tests: T18h, T19d, T20 (reconcile), T21 (whitelist and
protect opt-out); this repo's own stale .githooks/ refreshed.
2026-09-22 16:34:27 +02:00
bastien 9da5d8d52c feat(guardrails): push every commit, static deny for destructive tools, brief carries no user authority
Layer C of the plan written after the 2026-09-21 wipe (BDR-095): a reviewer
sub-agent traced `lftp mirror --delete` against a local file:// tree, the
prose tiers named neither lftp nor a local trace, the brief had authorized
it, and four days of commits had never left the machine.

- gitflow: `start` pushes the branch with its upstream, merge targets are
  pushed after each merge, and `init`/`install-hook` write post-commit and
  post-merge hooks that push every commit as it lands (warn, never block;
  GITFLOW_NO_PUSH=1 for throwaway repos). T18 + T19 (installed == emitted).
- hooks/unpushed-guard.sh on SessionStart and Stop: branch ahead of its
  upstream, no upstream, or no origin. Non-blocking systemMessage.
- settings.json: static deny for transfer and mirror tools, rsync --delete,
  xargs rm, pipe-to-shell, chmod/chown -R, sudo/doas/pkexec, disk tools,
  chattr, docker volume drops/prune/--privileged/socket/-v /:, git history
  destruction, --no-verify and core.hooksPath; new hard_deny "destructive
  tool against a local path, brief carries no user authority"; soft_deny
  reworded + discarding uncommitted work; environment records the incident.
- CLAUDE.global.md "Destructive tools & data loss"; the four report-only
  agents trace by reading, never by running, whatever the brief says.
- lib/tests/guard-bash.test.sh: executable spec of the PreToolUse guard
  (214 cases). The hook itself is not shipped (BLK-022); the spec skips.
2026-09-22 07:43:12 +02:00
bastien cc2f246e65 fix(impeccable): global-scope install with agents, pin fallback, output-read failure check
make plugin never installed impeccable. The 3.2.0 pin had rotted upstream
(the CLI fetches its skill dist at install time; that release's zip is
gone), the --scope=project staging moved the skill dir alone and dropped
the 4 impeccable-* subagents, and /impeccable init was never announced.

Step 8d now installs at --scope=global straight through the
~/.claude/{skills,agents} symlinks into the repo (both paths gitignored),
guards on those symlinks existing, keeps a profile-parked copy parked,
falls back to @latest on a pin failure with a bump-the-lock warning, and
prints the per-project init hint. update-all.sh mirrors the shape.

Found while probing: with a copy already installed a rotted pin exits 0
("Could not check for skill updates ... left unchanged"), byte-identical
on disk to an up-to-date rerun, so imp_install reads the installer output
instead of trusting the exit code. Harness 4/4 in a sandbox HOME with the
real installer.

plugins.lock.json: impeccable 3.2.0 -> 4.1.0 (CLI only). link.sh drops
impeccable from EXTERNAL_SKILLS. lib/design-gate.md section 5: suggest-only
/impeccable init check when a frontend project has no PRODUCT.md.
2026-09-22 03:20:25 +00:00
bastien 7c05f75eab feat(21st): replace the magic MCP with the @21st-dev CLI + skill pack
Upstream supersedes `@21st-dev/magic` with `@21st-dev/cli` (bin `21st`):
same endpoint, `21st login` in place of an API key, no MCP process loaded
into every session.

- install-plugins.sh Step 8.7: `npm i -g @21st-dev/cli` (pinned in
  plugins.lock.json), staged `21st skills install`, TTY-only login offer,
  pack disabled by default. update-all.sh 7.4 refreshes both.
- The documented `21st install-skill` cannot be used: the installer refuses
  to follow a symlink on the target path and `~/.claude/skills` is one. The
  install runs under a throwaway HOME and the result moves into
  skills-external/21st-* (gitignored), symlinked on demand.
- toggle-external.sh manages `21st` as a pack (names globbed from
  skills-external/21st-*, parked under plain names). `magic` is gone.
- The 5 design skills join design/web/web-full/full and MANAGED_EXTERNALS;
  21st-registry and 21st-design-sync stay parked. MANAGED_MCPS is now empty
  and profile.sh's dead magic branches are removed.
- Design gate: GATE-BLOCK gains `21st` (required-manual, magic's old slot)
  and `21st-ui-build`; PATH repair extended to the npm global bin.
- settings.json: the 4 mcp__magic__* ask entries go; the outward-facing
  21st verbs land in autoMode.soft_deny, the tier that holds under auto
  mode (LRN-153).
- Docs: README, CLAUDE.global.md, design-gate.md, profile SKILL.md,
  .env.example, .gitleaks.toml, link.sh. BDR-093, LRN-158.

Tests: profile-set-managed 17/17, make test green except 2 pre-existing
gitflow FAILs (gitleaks binary absent on this host), shellcheck clean.
2026-09-22 02:53:31 +00:00
Bastien Chanot 17370d7e4c feat(executors): NEED-DECISION and BLOCKED carry a CLASS tag 2026-09-16 22:14:13 +02:00
Bastien Chanot 97591ca737 feat(hotfix): pass B at LOCATE, class-tagged BLOCKED relayed as a question 2026-09-16 22:13:32 +02:00
Bastien Chanot a2978b6f23 feat(contract): STEP 2 CLARIFY, mid-run channel, how-to-ask 2026-09-16 22:12:13 +02:00
Bastien Chanot 2cebecbb91 feat(gstack): share the Playwright bump, report the browser cache
Extract gstack_bump_playwright_if_unsupported from install-plugins.sh into
lib/gstack-playwright.sh and call it from update-all.sh too. A submodule
update no longer leaves the OS-support bump unapplied until the next
`make plugin` — that was BDR-029's open caveat.

The update helper never touches the submodule working tree: on failure it
prints git's own message and points at `make plugin`, and returns non-zero
so the existing `else warn` arm still handles it.

Add a read-only `Playwright browsers` section to doctor.sh: cache size,
which registered install requires each revision, and counts of unreferenced
directories and broken links. No pruning is written — Playwright's own
`install` already unions the required set across every registered install,
and all three installs here are live (rev 1228 for gstack + gsd-pi 1.61,
rev 1243 for gsd-pi 1.63).

Carries two latent-bug fixes from the moved code: the ostag capture exited
1 on every non-Ubuntu host and aborted the caller under inherited errexit,
and the bun calls had no timeout.
2026-09-15 14:57:31 +02:00
Bastien Chanot 543b0c811a feat(tour): multi-project parallel fan-out — one runner per repo
Two or more project paths dispatch one general-purpose runner per repo,
all in a single message, instead of processing repos one by one. The
runner inherits the session model — no pin, it carries tour's reflection
(fix decisions, convergence) — and every agent inside keeps its defined
tier (security-auditor sonnet, Phase B opus, doc-syncer sonnet). A dead
or mute runner becomes an explicit RUNNER FAILED summary row; the gated
capitalize offer stays in the main loop, never in a runner.

Bounded LRN-083 derogation recorded in BDR-084: the per-project fix loop
moves into its runner, but nothing a runner decides touches shared state
— independent repos, per-repo chore branches, branches left unmerged for
human review exactly as inline. Mechanics proven before building: nested
probe, 3 sub-agent windows all overlapping, 9.1s vs ~18s sequential.

Census §12: 6 locks, flip-tested. Single-project path unchanged.
2026-08-24 14:18:59 +02:00