# PLAN — superpowers-vendored (feat, ad-hoc dispatch) — r3 (after confirmation pass) - r3 closes the confirmation pass (correctness CONCERNS(1)): MAJOR 1 — the CLAUDE.global.md map keeps every skill identifier whole on one line (grep is line-based); MINOR 2 — `always_on` mechanism pinned: the python lock reader emits a third column, `_dv_check_link` gets a 5th param, headers updated, a helper extracted if `check_vendored_skills` would exceed 5 locals; MINOR 3 — stale "uninstall || true" edge case deleted; MINOR 4 — settings.json edit moves to the orchestrator, AFTER criterion 2 is green (a disabled plugin + a failed fetch must never coincide); MINOR 5 — profile.sh comments located by grep, doctor pass line worded on what is proven. - r2 closes: correctness BLOCKER 1 (the CLAUDE.global.md map never spells the colon form — criterion 3 greps it), MAJOR 2 (doctor-vendored gains an always-on class driven by a lock field `always_on`, so the 7 are link-checked instead of "parked"), MAJOR 3 + robustness MAJOR 1 (NO uninstall code in the installer — comment only, one-shot by the orchestrator after criterion 2 is green), MAJOR 4 + robustness MAJOR 3 (settings.json hand-edited: enabledPlugins key and extraKnownMarketplaces.superpowers-marketplace block removed, committed), MAJOR 5 + robustness MAJOR 2 + simplicity MAJOR 1 (detect_superpowers = one file test on the linked skill, no plugin fallback, no new global), simplicity MAJOR 2 (same: no installer uninstall), MINORs: session-start line deleted plainly, map trimmed to the four referenced skills, lock note kept to maintainer facts, summary line placement pinned, rollback step, mixed-version rollback note. - date: 2026-09-28 | contract: contracts/2026-09-28-superpowers-vendored-1357.md - branch: feature/superpowers-vendored - executors: 2 feater (sonnet-pinned), parallel, disjoint file sets ## Ground truth (verified 2026-09-28) - Plugin superpowers 6.4.1 installed at `~/.claude/plugins/cache/superpowers-marketplace/superpowers/6.4.1/` (gitCommitSha 5bf4e78011075bcfc0dc295f0724994cd123ee71 = upstream tag v6.4.1 on obra/superpowers; raw files served at `https://raw.githubusercontent.com/obra/superpowers//skills//`, brainstorming/SKILL.md md5 identical local vs raw). Enabled in settings.json (`superpowers@superpowers-marketplace: true`), PROTECTED in lib/profile.sh, installed + enabled by install-plugins.sh STEP 5 (marketplace add, install_plugin, enable_plugin), summary line "ALWAYS ON … superpowers". Its hooks.json SessionStart (startup|clear|compact) injects using-superpowers (~3.6 KB) every start. - The 7 skills to vendor and their files (upstream layout `skills//`): brainstorming: SKILL.md, spec-document-reviewer-prompt.md, visual-companion.md, scripts/frame-template.html, scripts/helper.js, scripts/server.cjs, scripts/start-server.sh, scripts/stop-server.sh writing-plans: SKILL.md, plan-document-reviewer-prompt.md subagent-driven-development: SKILL.md, implementer-prompt.md, re-review-prompt.md, task-reviewer-prompt.md, scripts/review-package, scripts/sdd-workspace, scripts/task-brief test-driven-development: SKILL.md, writing-good-tests.md requesting-code-review: SKILL.md, code-reviewer.md using-git-worktrees: SKILL.md writing-skills: SKILL.md, anthropic-best-practices.md, examples/CLAUDE_MD_TESTING.md, graphviz-conventions.dot, persuasion-principles.md, render-graphs.js, testing-skills-with-subagents.md Scripts are invoked upstream as `bash scripts/` (SDD lines 137, 252, 290…; brainstorming visual-companion.md) → no exec bit needed. - Internal cross-references that will dangle (byte-for-byte text): writing-plans → superpowers:subagent-driven-development, superpowers:executing-plans (dropped), superpowers:using-git-worktrees; SDD → superpowers:finishing-a-development-branch ×4 (dropped), superpowers:using-git-worktrees, superpowers:requesting-code-review, executing-plans ×2; TDD → superpowers:writing-skills; writing-skills → superpowers:test-driven-development ×4, superpowers:systematic-debugging (dropped), using-superpowers, verification-before-completion. - `lib/vendor-skills.sh` `vendor_pinned_skills [refresh]`: lock entry `{source, commit (40 hex), path, skills: {name: [files]}, managed_by}`; files must match `[A-Za-z0-9._/-]+`, no `..`; tmp+mv; skips existing files unless `refresh`. install-plugins.sh STEP 8e calls it for agent-skills and mengto-skills with `EXT_SKILL_NAMES` symlink check; update-all.sh 7.3 calls it with `refresh`. link.sh `EXTERNAL_SKILLS=(…)` symlinks `skills-external/` into `~/.claude/skills/`; .gitignore lists `skills/` (symlink) and `skills-external//` (vendored text) per external. lib/doctor-vendored.sh reads the lock + EXTERNAL_SKILLS generically. - lib/profile.sh: `PROTECTED_PLUGINS=("security-guidance@claude-code-plugins" "superpowers@superpowers-marketplace")`; MANAGED_EXTERNALS is the allowlist `set` parks — the 7 are NOT added (always on, like darwin-skill). - lib/detect-plugins.sh `detect_superpowers`: plugin cache glob then `claude plugin list`. Consumers: hooks/session-start.sh:122 (`+ 800` passive), doctor.sh:225-228 (pass/fail "Superpowers plugin detected / not detected — orchestrators will fail") and :423 (`+ 1500`). - `superpowers:` citers (personal): skills/ship-feature:103,117,176,237; skills/init-project:71,182,215,259; skills/tour:318; skills/deploy:515; skills/audit-delta:321; lib/analyze-before-plan.md:106; lib/capitalize-commit.md:20 (finishing-a-development-branch); agents/plugin-advisor.md:182. Prose mentions of finishing-a-development-branch: lib/capitalize-commit.md:68, lib/doc-commit.md:84, lib/analyze-before-plan.md:108, skills/gitflow:16,110. Docs: README.md:121 (component table), USAGE.md ×19 (plugin/cost narrative), agents/plugin-advisor.md ×19 (matrix, recommended sets, remedy :324), skills/profile/SKILL.md:59, install-plugins.sh:1210 summary. `docs/superpowers/` paths (CLAUDE.md, gitflow, onboard) stay: brainstorming and writing-plans still write there. - lib/tests: gitflow-test.sh mentions superpowers only through the purge path (unchanged). No suite asserts PROTECTED_PLUGINS content. ## Approach ### E1 — wiring (lock, installers, link, gitignore, profile, detect, doctor) Files: plugins.lock.json, install-plugins.sh, update-all.sh, link.sh, .gitignore, lib/profile.sh, lib/detect-plugins.sh, hooks/session-start.sh, doctor.sh, lib/doctor-vendored.sh, lib/tests/doctor-vendored.test.sh, lib/vendor-skills.sh (header comment line only). 1. plugins.lock.json: new entry `"superpowers"` after `"mengto-skills"`: source `https://github.com/obra/superpowers`, commit `5bf4e78011075bcfc0dc295f0724994cd123ee71`, path `skills`, `skills` = the dict above (exact file lists), managed_by `curl`, `"always_on": true`, note (maintainer facts only, history lives in CHANGELOG/BDR-106): "Seven superpowers skills vendored byte-for-byte at the v6.4.1 tag commit (obra/superpowers), always on (no profile lists them). Bump the commit deliberately. Scripts inside run as `bash scripts/`, no exec bit needed. Upstream cross-references to the plugin prefix and to the 8 non-vendored skills stay in the text; CLAUDE.global.md Skill routing maps them." 2. install-plugins.sh STEP 5: delete the three superpowers lines (marketplace add, install_plugin, enable_plugin) and replace with a 3-line comment "Superpowers plugin removed 2026-09-28 (tier 2 of the skill-catalog prune): its 7 wired skills are vendored in Step 8e (plugins.lock.json 'superpowers'); a still-cached plugin is uninstalled by hand once (claude plugin uninstall superpowers@superpowers-marketplace), never here". NO uninstall code in the installer (precedent: frontend-design, caveman). Update the `enable_plugin` comment (:490) to name only security-guidance. STEP 8e: heading/comment mention superpowers; `EXT_SKILL_NAMES` += the 7; `vendor_pinned_skills superpowers` after mengto. Summary: replace line ~1210 ("✅ superpowers — brainstorm/plan/implement/debug workflow", ALWAYS ON block) by "✅ superpowers skills — 7 vendored (brainstorming, writing-plans, subagent-driven-development, test-driven-development, requesting-code-review, using-git-worktrees, writing-skills), pinned v6.4.1, curl → symlink, no plugin, no session injection"; add one "at:" line right after the mengto "at:" line (~1234): "Superpowers skills at: ~/.claude/skills/{brainstorming,…}/ (symlink → skills-external)". 3. update-all.sh 7.3: `echo "── Updating superpowers skills (obra/superpowers)..."` + `vendor_pinned_skills superpowers refresh`; comment names it. 4. link.sh EXTERNAL_SKILLS += the 7 (keep the array multi-line ≤ 80 chars). 5. .gitignore: 7 `skills/` lines next to the other external symlinks (:65-68 block) and 7 `skills-external//` lines next to the mengto block (:203-207), each block with a one-line comment "superpowers, vendored (plugins.lock.json 'superpowers')". 6. lib/profile.sh: PROTECTED_PLUGINS keeps only security-guidance; every comment naming superpowers as an always-on plugin (`grep -n superpowers lib/profile.sh`, currently ~:22 and ~:65) reworded ("superpowers is vendored skills now, not a plugin"). 7. lib/detect-plugins.sh `detect_superpowers`: exactly `[ -f "$HOME/.claude/skills/brainstorming/SKILL.md" ]` (the linked vendored skill: proves vendored AND linked; no plugin cache glob, no `claude plugin list`, no new global, no fallback). Comment: "superpowers = 7 vendored skills since 2026-09-28; the plugin is gone". A negative control (empty HOME) must return 1. 7b. lib/doctor-vendored.sh: lock entries may carry `"always_on": true` (the `superpowers` entry does). Skills of such an entry are expected LINKED whatever the active profile says (today every EXTERNAL_SKILLS name absent from the profile is reported `parked`, link unchecked — the 7 are in no profile by design). Mechanism: `_dv_lock_expectations` (python) prints a THIRD column `name\tfile\t1` for skills of an `always_on` entry (awk `$1==n {print $2}` in `_dv_check_files` keeps working unchanged); `check_vendored_skills` reads the flag and passes it as a 5th parameter to `_dv_check_link`, which treats `1` as "expected linked whatever the profile says". If `check_vendored_skills` would exceed 5 locals, extract the per-name dispatch into a helper (≤ 25 logic lines each). Update the file header ("A name absent from the profile is reported parked" → "… unless its lock entry is always_on") and the test header. Message unchanged for the linked case, fail ": symlink missing/wrong — run: make link" when absent. Add a case `ALWAYS_ON_LINK_CHECKED` to lib/tests/doctor-vendored.test.sh (fixture entry with always_on true, name absent from the profile, link missing → fail line, never `parked`). Document the field in lib/vendor-skills.sh's lock-shape header comment (one line: ignored by the vendor helper, read by doctor-vendored). 8. hooks/session-start.sh: delete line 122 (`detect_superpowers … + 800`) outright — the banner's ALWAYS_ON list comes from detect_rtk + settings enabledPlugins (lines ~147-160), not from this call. doctor.sh :225-228: pass "superpowers: 7 skills vendored + linked (plugins.lock.json, v6.4.1)" / fail "superpowers skills not linked — run: make plugin && make link"; the pass line is worded on what `detect_superpowers` proves ("superpowers skills linked (brainstorming found); per-skill check under Vendored skills"); :423 delete the `+ 1500` line (comment: counted by the skill catalog stats). 9. settings.json: NOT an executor file any more — the orchestrator edits it after criterion 2 is green (see Orchestrator steps), so a disabled plugin never coincides with a failed fetch. ### E2 — citers, routing map, docs Files: skills/{ship-feature,init-project,tour,deploy,audit-delta,gitflow,profile}/SKILL.md, lib/{analyze-before-plan,capitalize-commit,doc-commit}.md, agents/plugin-advisor.md, CLAUDE.global.md, README.md, USAGE.md, CHANGELOG.md. 1. `superpowers:` → `` (bare) in ship-feature ×4, init-project ×4, tour:318, deploy:515, audit-delta:321, lib/analyze-before-plan.md:106, agents/plugin-advisor.md:182. Wording around them: "Invoke `brainstorming` (vendored superpowers skill)" on first mention per file, bare afterwards. 2. finishing-a-development-branch prose: lib/capitalize-commit.md:20 → "Orchestrators that integrate via `gitflow finish` (the upstream finishing-a-development-branch is not vendored)"; :68, lib/doc-commit.md:84, lib/analyze-before-plan.md:108, skills/gitflow:16,110 → say "upstream superpowers skill, not vendored here; `gitflow finish` is the only integration path" where they present it as available. 3. CLAUDE.global.md § Skill routing, after the "Before /clear or /compact" line, ≤ 80 chars per line, about 4 lines, and NEVER the literal "superpowers" followed by a colon (criterion 3 greps that string): "- superpowers skills are vendored, called by bare name; an upstream `superpowers` prefix means the bare skill. Not vendored: executing-plans → subagent-driven-development; finishing-a-development-branch → `gitflow finish` (human signal); systematic-debugging → bugfix; verification-before-completion → the verifier gates." Every skill identifier stays WHOLE on its line (criterion 7 greps `finishing-a-development-branch`, `executing-plans`, `systematic-debugging` line by line); wrap at spaces only. 4. README.md:121 row → "**Superpowers skills** | Vendored (7, always on) | brainstorming, writing-plans, subagent-driven development, TDD, code review request, git worktrees, writing-skills — pinned v6.4.1 in plugins.lock.json, no plugin, no session injection | obra/superpowers". README:208 unchanged. 5. USAGE.md: every line presenting superpowers as a plugin to keep ON/OFF or as ~800 t passive (184-185, 589, 650, 751, 864, 959-965, 971, 995, 1018) → "skills superpowers (vendorisés, toujours actifs, 0 t passif)" or the equivalent in the sentence's French; keep the narrative otherwise. 6. agents/plugin-advisor.md: rows 177-182 (compat matrix) → "superpowers skills (vendored)" wording, drop the plugin-dev overlap row's "plugin" framing; recommended-set table 190-198: replace "superpowers" by "(superpowers skills always on)" in the ON column and subtract ~800 t from each cost; :80, :146, :242, :254, :298 reword; :324 remedy → "Superpowers skills missing → `make plugin` (vendors them) then `make link`". 7. skills/profile/SKILL.md:59: "Always-on plugins (`security-guidance`) and the vendored superpowers skills are never toggled by a profile". 8. CHANGELOG `[Unreleased]`: Changed (superpowers plugin → 7 vendored skills, pinned, always on; `superpowers:` citers renamed), Removed (plugin, its 8 duplicate skills, the SessionStart injection), Known residual (upstream cross-references inside the vendored text; CLAUDE.global.md map). ## Orchestrator steps - Criterion 2 vendors + links live (network fetch of 30 files); only when every file is present and byte-identical (c2.py) does the next step run. - Then the orchestrator edits settings.json by hand: remove the `"superpowers@superpowers-marketplace": true` key from `enabledPlugins` and the whole `extraKnownMarketplaces."superpowers-marketplace"` block, nothing else; validate with `python3 -c 'import json;json.load(open("settings.json"))'`. - Then, one shot by hand: `claude plugin uninstall superpowers@superpowers-marketplace` and `claude plugin marketplace remove superpowers-marketplace`; re-check `git diff settings.json` afterwards (the CLI must not have re-added anything), then criterion 8. - Rollback if criterion 8 fails: `claude plugin marketplace add obra/superpowers-marketplace && claude plugin install superpowers@superpowers-marketplace`, `git checkout -- settings.json`, stop and report. - Verifier; security; commit; BDR-106 + journal. ## Edge cases - Mid-migration machine (plugin cached, skills not yet vendored): doctor fails "not vendored or linked — run make plugin && make link"; the user uninstalls the plugin by hand (CHANGELOG says so). No fallback that could print "vendored" for a plugin-only machine. - Mixed-version rollback (an older checkout re-installs the plugin while the 7 symlinks are still linked → duplicate descriptions): CHANGELOG note "after a rollback, delete skills/<7> symlinks or re-run the new make plugin". - The running session keeps the plugin's `superpowers` skills until restart; the bare names appear after `make link` + a new session. - Fresh clone: link.sh symlinks a non-existent skills-external dir only if present (existing `[ -d ]` guard). - skill-routing-census live run gains 7 descriptions: brainstorming's "You MUST use this before any creative work" vs personal descriptions — the suite's live FAIL threshold must not trip (check by running it). ## Tests - make test suite= vendor-skills, doctor-vendored (with the new ALWAYS_ON_LINK_CHECKED case), doctrine-citers, skill-routing-census, profile-default, profile-set-managed. - shellcheck on every touched shell file. ## Disposition (RELATED MEMORY) - honors BDR-102 / BDR-104 — vendor over plugin, shared helper, pinned commit, byte-for-byte text. - honors BDR-105 — tier 2 of the prune decision. - honors BDR-065 — docs/superpowers transient path unchanged. - honors LRN-178 — no new top-level `source`; detect-plugins reads a path. - honors BDR-077 — requesting-code-review's reviewer dispatch keeps the model-routing note in ship-feature/init-project.