--- title: "project-bootstrap@1.7.0 — generic skill-dependencies check (Step 5.6)" type: concept updated: 2026-05-05 --- # project-bootstrap@1.7.0 — generic skill-dependencies check (Step 5.6) _2026-05-05._ ## Problem Step 5.6 in `project-bootstrap@1.6.0` detected exactly one missing fulfiller — the `superpowers@claude-plugins-official` plugin — and printed a recommendation if absent. The shape worked but doesn't scale. The canonical CLAUDE.md template grew from 5 lines (1.0.0) to 9 lines (1.6.0) — every release added a new trigger: | Release | Added trigger | Fulfiller | |---|---|---| | 1.1.0 | `we're on Windows` / Linux / macOS | `active-platform` (skill) | | 1.2.0 | `check across all projects` | `using-projects-meta` (skill) | | 1.4.0 | `pull remote before work` | `pulling-before-work` (skill) | | 1.5.0 | `follow project discipline` | `project-discipline` (skill) | | 1.6.0 | `delegate to interns when allowed` | `using-interns` (skill) | Each new trigger silently no-ops on hosts where the corresponding skill / plugin isn't installed. The Step 5.6 superpowers detector was the right idea, but mirroring it as `Step 5.7`, `Step 5.8`, … per missing-skill — five mirror sections to cover the gaps above, and one more per future trigger — is a copy-paste explosion. Worse: a deferred task `[bootstrap-recommend-projects-meta]` was already opened in 1.2.0's wake to mirror the `superpowers` detector for `using-projects-meta`, and the same gap is structurally inevitable for every line in the template. ## Decision Collapse Step 5.6 into a single **generic** "Skill dependencies check" that: 1. Reads the project's `CLAUDE.md` (just-written or pre-existing). 2. Walks every non-empty, non-comment line. 3. Looks each line up in a `trigger → fulfiller` map embedded in the SKILL. 4. Checks the corresponding detection path on disk: - `kind: skill` → `~/.claude/skills//SKILL.md` exists? - `kind: plugin` → key under `plugins.` in `~/.claude/plugins/installed_plugins.json`? 5. Prints **one** chat-only block listing every missing fulfiller with a copy-pasteable install command. The `superpowers`-only Step 5.6 from 1.6.0 is subsumed cleanly: `superpowers` becomes one row in the map, with `kind: plugin` so its install command is `/plugin install …` rather than `bash scripts/install.sh …`. `[bootstrap-recommend-projects-meta]` (the deferred mirror task) is closed by absorption — the generic step handles `using-projects-meta` along with everything else in the same commit. Bumps `project-bootstrap` 1.6.0 → 1.7.0 (MINOR — adds capability, doesn't break the existing detector since it's absorbed). ## Why generic over per-skill mirrors Per-skill mirror shape: ``` Step 5.6 — Recommend superpowers if missing Step 5.7 — Recommend setup-projects-meta if MCP missing Step 5.8 — Recommend project-discipline if missing Step 5.9 — Recommend pulling-before-work if missing … ``` Each section is ~30 lines of nearly-identical "read detection path → if absent print recommendation" prose. Adding a new canonical trigger means writing another mirror section. Five-skill template → five mirror sections; ten-skill template → ten. The detection logic is the same; only the path and install command differ. Generic shape replaces the prose mirrors with one ~10-row table. Adding a new canonical trigger means adding one row in the map (plus the line in `assets/CLAUDE.md.template`, in the same commit). The detection algorithm is invariant. ## Skill vs plugin distinction Two install pathways exist on a Claude Code host: - **Skills** live at `~/.claude/skills//`, installed via `bash scripts/install.sh ` (or via the `find-skills` skill). Detection: file existence. - **Plugins** are a higher-level Claude Code concept (slash commands, hooks, sub-agents, MCP servers); installed via `/plugin install @`. Detection: key lookup in `~/.claude/plugins/installed_plugins.json`. The map's `kind` column flags which pathway each fulfiller uses, so the recommendation block emits the correct install command. Currently only `superpowers` is `kind: plugin`; everything else is `kind: skill`. Future triggers may add more plugins. ## MCP-server-backed skills `using-context7`, `using-projects-meta`, `using-interns` each depend on an MCP server that's separately installed (`setup-context7`, `setup-projects-meta`, `setup-interns`). Step 5.6 only checks the `using-X` policy skill — not whether the MCP server is registered or running. Rationale: every `using-X` skill carries a "Prerequisites" pointer in its body that fires `setup-X` at first use if the MCP tools are missing. Bootstrap doesn't need to duplicate that detection — the skill itself self-bootstraps when invoked. Step 5.6 only ensures the `using-X` skill is present so the trigger isn't silently dead. ## Hard rule — never auto-install carries over The `superpowers` detector at 1.6.0 had a hard rule: "never auto-install". Reasons: - Slash commands (`/plugin install …`) aren't callable from inside a skill. - Silently mutating user-level skill / plugin state without consent is overreach. Both reasons generalize. The 1.7.0 generic check is recommendation-only — it prints to chat and never writes into project files or user-level config. The user can install some / all / none of the recommendations, or remove canonical lines from `CLAUDE.md` to lean the project's trigger set down. ## What about user-custom triggers? Step 5.6 ignores any line in the project's `CLAUDE.md` that doesn't match a trigger row in the map. If the user added a custom trigger like `use my-team-style-guide`, it's their responsibility — bootstrap's contract is "we own canonical triggers; non-canonical lines are your responsibility". The check is permissive on custom lines (silent skip), strict on canonical lines (recommend if missing). Removed canonical lines work symmetrically: if the user deleted `delegate to interns when allowed` on purpose, Step 5.6 reads from the actual file and never sees that line, so it never recommends `using-interns`. Correct behavior — the user opted out. ## Source-of-truth invariant The map embedded in SKILL.md and the trigger list in `assets/CLAUDE.md.template` must stay in sync. Adding a new canonical trigger requires editing both in the same commit. Mismatch = silent gap (template adds a trigger, map doesn't have its row, the recommendation never fires for it). A future hardening could lint the two against each other in CI; for now it's a discipline rule for whoever bumps the version. ## Composition with the rest of bootstrap Step 5 (idempotent merge) ensures the trigger lines are *present* in the project's `CLAUDE.md`. Step 5.6 (this) ensures the fulfillers are *installed* on the host. Together they close the loop: - 5 → trigger in the file. - 5.6 → fulfiller on disk. Either alone is partial. Together a fresh bootstrap on a fresh machine surfaces every install gap in one shot.