adapt
Set up or upgrade a project's CLAUDE.md for the Superpowers + GStack workflow. Analyzes the project, picks the skills; scripts/adapt-claude-md.py does every write, losing nothing.
SKILL.mdskills/adapt/SKILL.md
GitHubAdapt to Superpowers + GStack
Invoke with: /superpowers-gstack:adapt
One procedure for every project. A project with no CLAUDE.md gets one; a project with a CLAUDE.md keeps everything it has and gains (or upgrades) the plugin's sections. There is no separate setup skill any more — adapt on an empty project is setup.
Division of labour. You decide what the project gets: its type and stack, which
skills are relevant, the domain sensitivity, the placeholder values. The script
scripts/adapt-claude-md.py does every write to CLAUDE.md: the snapshot, the header,
retired sections, skill renames, each marker-managed block with its growth check,
attribution sentinels, heading demotion and emitted= provenance, Model Routing, the
verify diff and the report. Never edit CLAUDE.md by hand in this skill and never paste
a block yourself — the script is deterministic, idempotent and fail-closed; a hand
edit is neither.
Begin every Bash call with the two bindings below — shell state does not survive
between calls, and an unset $SKILL_DIR resolves the script to a path python3 cannot
open:
SKILL_DIR='<the base directory the Skill tool printed when this skill loaded>'
SCRIPT="$SKILL_DIR/../../scripts/adapt-claude-md.py"
[ -f "$SCRIPT" ] || SCRIPT=$(ls ~/.claude/plugins/cache/*/superpowers-gstack/*/scripts/adapt-claude-md.py 2>/dev/null | sort -V | tail -1)
[ -f "$SCRIPT" ] || { echo "BLOCKED — adapt-claude-md.py not found; run /plugin update superpowers-gstack"; exit 2; }
Dependency check: verify both upstream frameworks are installed:
ls -d ~/.claude/plugins/cache/claude-plugins-official/superpowers/*/ 2>/dev/null | head -1
ls -d ~/.claude/skills/gstack/ 2>/dev/null
If either path is missing, STOP and tell the user:
This plugin is glue for two upstream frameworks. Install them first:
Missing: Superpowers —
/plugin marketplace add claude-plugins-officialthen/plugin install superpowersMissing: GStack —
git clone https://github.com/garrytan/gstack.git ~/.claude/skills/gstack && cd ~/.claude/skills/gstack && ./setupOnly mention the framework(s) that are actually missing. Restart Claude Code after installing, then run
/superpowers-gstack:adaptagain.
Directory check: the working directory must be the target project. If it looks like a different project (the superpowers-gstack repo itself, say), STOP:
You're currently in
[cwd]. This skill needs to run from your target project directory. Start a new Claude Code session:cd /path/to/your-project && claudeThen run
/superpowers-gstack:adaptagain.
Process
Follow the steps in order. Three STOP HERE gates ask the user something; end your
message at the question each time. An empty folder skips all three (Step 0): there
is nothing in it to protect, and every question the gates ask has an answer the stack
decides later.
Step 0: An empty folder gets the short path
Ask the script first, with no inputs:
SKILL_DIR='<the base directory the Skill tool printed>'
SCRIPT="$SKILL_DIR/../../scripts/adapt-claude-md.py"
python3 "$SCRIPT" --fresh-check
It prints one JSON line, fresh and fresh_reason, and merges nothing (a plain
--dry-run would refuse on a fresh folder that already pins a native track, since the
native blocks need their placeholders). The script, not you, decides what
fresh means: no CLAUDE.md, no package file (package.json, Package.swift,
Cargo.toml, pyproject.toml, go.mod, Gemfile, .claude-plugin/plugin.json,
*.xcodeproj, *.xcworkspace), and fewer than five files outside .git/, .gstack/,
.claude/ and docs/superpowers/. A folder with only a README.md and a .gitignore
is fresh; a folder with a lone package.json is not, because the stack can be read off
it, and Steps 1–7 fit it.
fresh is false → continue with Step 1. Quote fresh_reason in one line when the
folder looked empty to the user.
fresh is true → one command does what Steps 2–6 would otherwise ask for over
six stops:
python3 "$SCRIPT" --fresh --mkdirs
It refuses (exit 2, BLOCKED — not a fresh project) if the folder is not fresh after
all, so a wrong call on a living project can never overwrite anything. A fresh folder
that already pins a native track (.gstack/track = ios | macos | both) refuses with
UNRESOLVED PLACEHOLDER: resolve IOS_SIMULATOR and DEVELOPMENT_TEAM per
blocks/PLACEHOLDERS.md, add their --sets, and run it again — still no question for
the user. Otherwise it
writes .gstack/workflow = vibe and .gstack/explainer = local when they are
missing (an existing pin is kept) and stages them; writes CLAUDE.md with the header,
the routing from blocks/routing-default.md, every block, Model Routing at medium
sensitivity, Local state: none, and a ## Project section that holds only
Stack: not yet known under the marker <!-- gstack-project-pending -->; creates the
context skill (vibe) and docs/superpowers/; and prints its report with one extra line
at the top:
Assumed: web track, vibe workflow, local explainer, no local state, medium sensitivity, Installable not set — change any of them in .gstack/ or CLAUDE.md, or run /superpowers-gstack:adapt again after the first spec.
Relay that line and the report, git add the context skill the report names, and go
straight on — no "is this right?", no "shall I proceed?", no offer of a review (Step 6's
offer is a read-through of a file nobody has written in). With the vibe profile, invoke
/superpowers-gstack:vibe with what the user said they want to build; with classic,
/superpowers:brainstorming. The first stop of the session is then the first question
about the product, not about the setup.
Why these defaults and not questions: each is the answer the gates below mark
(recommended), and each costs one line to change — .gstack/workflow,
.gstack/explainer, the Local state: line. No Installable: line is written: an
empty folder has nothing to install, and /superpowers-gstack:work-state shows the
missing line as not defined until the fill-in asks (Step 4, item 8). The sensitivity is medium, not low,
because it is unknown until the stack is: medium routes coding to sonnet, which is
right for the common case, and the fill-in below corrects it; low could send DSP code
to haiku before anyone has seen that it is DSP. The stack, test command, deploy target
and the stack-dependent routing rows (/qa <url>, /cso, the Apple skills) are not
guessed at all — they are filled in once the first spec has decided them:
- Vibe:
/superpowers-gstack:vibeStep 2 writes## Projectfrom its intake and calls--project-section; nothing to do here. - Classic: the routing line Stack decided →
/superpowers-gstack:adaptbrings the user back here. Step 4 sees the marker and asks one confirmation instead of the Step 2 questionnaire.
Step 1: Analyze the project
Read what exists (skip what does not): CLAUDE.md; package files (package.json,
Package.swift, Cargo.toml, pyproject.toml, go.mod, Gemfile, plugin.json);
test configuration; CI (.github/workflows/, .gitlab-ci.yml); git state (branch,
remotes, recent branch names); the root layout; docs/; .gstack/track.
If there is no CLAUDE.md, or the stack cannot be read off the files, ask in one message: project type; test framework (or none yet); deploy target (or none); browser UI and its URL (or none); security concerns (auth, user data, payments, external APIs); for a native app, the platform (iOS / macOS / both). Then summarize what you found — concisely, what matters for the transition.
Step 2: Confirm the stack
Based on my analysis, this is a [type] using [stack]. Tests run with
[command]. [Deployed to X / not deployed]. [Has browser UI at X / No browser UI]. Track: [web / ios / macos / both].Is this correct? Anything to add?
STOP HERE. Do not add "next steps" or anything after the question.
Step 3: Evaluate skills and model routing
Read roster.md (sibling of this file) and pick, for this project, the relevant
Superpowers skills and the relevant GStack skills per phase. Leave out rows marked
User-started only: they stay the user's to invoke and stay out of the routing draft.
Read model-routing.md (sibling) for the per-skill base tiers, and infer the
project's domain sensitivity:
- real-time audio / DSP / signal processing, or any lock-free concurrency → very high (a plain SwiftUI CRUD app with none of these is medium)
- database migrations / ETL / data transforms, or security concerns from Step 1 → high
- web / mobile UI feature work → medium
- CLI tools / libraries / format plumbing → low
- ambiguous → ask one line: "How silently could a subtle bug here compound — very high / high / medium / low?"
Present the selection (Superpowers; GStack by phase; excluded, with a reason each), then the base tiers for the selected skills and the inferred sensitivity, and ask:
Does this look right? Any skills to add or remove, or a different sensitivity? (Say so if you want no Model Routing section at all.)
STOP HERE. Repeat until confirmed.
Step 4: Resolve the script's inputs
A pending ## Project first. If CLAUDE.md carries <!-- gstack-project-pending -->
on its ## Project heading, the project was set up by Step 0. Is the stack decided
yet? It is when a spec exists (docs/superpowers/specs/, docs/superpowers/vibe/) or
a package file does. If neither does (the session-start hook nudged /adapt after
a plugin upgrade, say), this is a plain upgrade: run Steps 5–6 as usual, without
--project-section; the script leaves the pending section exactly as it is, and the
marker waits for the spec. If the stack is decided, this run is the fill-in: the
pins exist (the script reads them), so items 4, 6 and 7 below are not asked again
(item 2, the macOS test executor, is asked now if the platform turned out to be macOS),
and Steps 2–3 collapse into one confirmation with the answer in it:
I read this as a [type] on [stack], tests via
[command], [deployed to X / not deployed], [browser UI at X / none], sensitivity [level] because [reason]. Installed means [item 8's recommendation]. Right?
(Item 8's question rides along in this one confirmation instead of a stop of its own;
leave the sentence out when CLAUDE.md already has an Installable: line.)
STOP HERE (this is the one question of a fill-in). Then write the section to
.gstack/adapt-project.md — ## Project with ### Tech Stack / Testing / QA URL / Deployment (omit what does not apply) and ### Routing for this stack holding the
rows the stack adds (/qa <url> when there is a browser UI, /cso before /review
when there is auth, user data, payments or external APIs, the Apple skills on a native
track), nothing else — and run:
python3 "$SCRIPT" --project-section .gstack/adapt-project.md \
--set 'DOMAIN_SENSITIVITY=<level>' [--set 'IOS_SIMULATOR=…' --set 'DEVELOPMENT_TEAM=…'] \
[--installable '<answer>']
The script replaces the pending section once, drops the marker (the section is the
project's from then on; without the marker the flag refuses) and rewrites Model Routing with the sensitivity. Delete .gstack/adapt-project.md afterwards; it was
the input, not a record. A native platform decided since Step 0: write
.gstack/track first (item 1) and resolve the native placeholders (item 3); the native
blocks come in on the same run. Relay the report and go to Step 7; Steps 5–6 ask about a
merge this run does not do.
Track.
.gstack/trackif present (ios|macos|both; anything else isBLOCKED — invalid .gstack/track, stop and say so); absent means web. If Step 2 established a native platform and the file is missing, write it:mkdir -p .gstack && printf '%s\n' "$TRACK" > .gstack/track.E2E executor pin — only when track is
macosorboth. If.gstack/e2e-executorexists the script reads and validates it; do not re-ask. If it does not exist, ask once withAskUserQuestion:Where should this project's committed macOS UI tests run? A VM rig gives isolation — a UI test that grabs the screen cannot fight you for focus, two runs cannot collide on one machine, and an unattended run does not need anyone logged in. It requires
vm-e2eonPATH; without it the tests still run, on this machine, with a warning.- On this machine (recommended) — no extra setup, and what every project does today.
- In the VM rig — needs the rig installed; a teammate without it gets a warning and a host run, not a failure.
Default to
hostif unclear, then write the pin and keep it committable:mkdir -p .gstack && printf '%s\n' "$ANSWER" > .gstack/e2e-executor # host or vm if git check-ignore -q .gstack/e2e-executor 2>/dev/null; then grep -q '^!\.gstack/e2e-executor$' .gitignore 2>/dev/null \ || echo '!.gstack/e2e-executor' >> .gitignore git add .gitignore && git add -f .gstack/e2e-executor else git add .gstack/e2e-executor fiDo not check whether
vm-e2eis installed before asking — the pin records a project decision, not this machine's capabilities. iOS-only and web projects get no file and no question.Placeholders — resolve every token the emitted blocks carry, per
blocks/PLACEHOLDERS.md:DOMAIN_SENSITIVITYfrom Step 3 (every track);IOS_SIMULATORandDEVELOPMENT_TEAMon native tracks (the resolution commands are in that file — run them, do not guess). Each becomes a--set TOKEN=value. The script refuses withUNRESOLVED PLACEHOLDERand writes nothing if one is missing; that is the guard, not an inconvenience.Workflow profile. Ask it before the routing draft (item 5), which follows the answer. If
.gstack/workflowexists the script reads and validates it; do not re-ask. If it does not exist, ask once withAskUserQuestion:How should this project work?
- Vibe (recommended) — one intake round, then the feature is finished autonomously and you review it once. Your one checkpoint on the way is the acceptance tests, which are then locked. Adds the
Vibe contractsection and a project context skill. - Classic — the skills' own approval gates (design, plan, execution method, landing menu), as before.
Write the pin and keep it committable:
mkdir -p .gstack && printf '%s\n' "$PROFILE" > .gstack/workflow # vibe or classic if git check-ignore -q .gstack/workflow 2>/dev/null; then grep -q '^!\.gstack/workflow$' .gitignore 2>/dev/null \ || echo '!.gstack/workflow' >> .gitignore git add .gitignore && git add -f .gstack/workflow else git add .gstack/workflow fiA run with nobody to answer writes no
.gstack/workflow: the script then uses classic and says so in its notes. Withvibethe script also creates.claude/skills/<project>-context/SKILL.mdfrom a template when no*-contextor*-kontekstskill exists, and never overwrites one.- Vibe (recommended) — one intake round, then the feature is finished autonomously and you review it once. Your one checkpoint on the way is the acceptance tests, which are then locked. Adds the
Skill routing draft — only when CLAUDE.md has no
## Skill routingheading. Write it to.gstack/adapt-routing.mdfrom this template, tight (row descriptions ≤ 15 words, decision-tree lines ≤ 10 words, no rationale prose), only the skills confirmed in Step 3, sections that do not apply omitted:## Skill routing This project uses Superpowers + GStack. Each owns a distinct phase. ### GStack — [phases] **Planning:** [selected Phase 1 skills, one line each] **Review & QA:** [selected Phase 3 skills] **Ship & Monitor:** [selected Phase 4 skills] ### Superpowers — Implementation - [selected skills] ### Routing Logic [project-specific decision tree, e.g. Ready to build → `/superpowers-gstack:vibe` with the vibe profile, `/superpowers:brainstorming` with classic; Bug during coding → /superpowers:systematic-debugging; Bug found in QA → /investigate; Code complete → /review [→ /qa <url>]; Security-sensitive → /cso before /review; Ready to ship → /ship; Trivial change → just do it] ### Rules - Never run GStack and Superpowers skills in the same phase - Never nest subagents from different frameworks - `/superpowers:systematic-debugging` for bugs found during implementation; `/investigate` only for bugs found in QA or production - Superpowers specs go in `docs/superpowers/`; GStack state lives in `~/.gstack/projects/` ### Session Management - `/clear` when transitioning between GStack and Superpowers phases; save architecture decisions to `docs/` first - Skip `/clear` for small projects (< 5 tasks, < 30 min) ## Project ### Tech Stack / Testing / QA URL / Deployment [from Step 2 — omit what does not apply]If
## Skill routingalready exists, the script leaves it alone (its marker-managed subsections are still upgraded), so write no draft. If the old section routes to skills that no longer exist, the script renamesmacos-/ios-native-review→apple-native-reviewandmacos-/ios-e2e-scaffold→e2e-scaffold, and dropsios-visual-explorerows itself.Local state. Files git ignores but the project needs (data, local configuration, keys) exist only in the primary checkout, and the
Worktrees and solo landingblock keeps work that needs them out of worktrees. If CLAUDE.md already has a line startingLocal state:outside the plugin's sections, the script keeps it; do not re-ask. Otherwise list candidates from the primary checkout (in a worktree the ignored files do not exist, and an empty list would wrongly suggest "none"), leaving out build output and caches (.build/,node_modules/,DerivedData/,.venv/,__pycache__/,.gstack/):PRIMARY=$(git worktree list --porcelain | sed -n '1s/^worktree //p') git -C "$PRIMARY" ls-files --others --ignored --exclude-standard --directoryThen ask once with
AskUserQuestion, the candidates in the question:Does this project keep files outside git that its work depends on — data, local settings, keys? They will stay in the main folder only, and work that needs them runs there after landing.
- Yes:
<candidates>(recommended when any were found) — edit the list under Other if it is wrong. - No — the project has none.
Pass the answer as
--local-state '<paths>'or--local-state none. The script writesLocal state: …under## <project> local state, a heading the project owns from then on, and never edits again: a wrong answer is corrected by editing that line by hand. A run with nobody to answer passes no flag and writes no line.- Yes:
Explainer page. After every spec and plan,
/superpowers-gstack:htmlify explainmakes a visual page that explains it. If.gstack/explainerexists the script validates it; do not re-ask. If it does not exist, ask once withAskUserQuestion:Where should the visual explainer page for each spec and plan go?
- Local file (recommended) — an HTML file next to the document, committed with it and opened in your browser.
- Artifact page — published as a private page on claude.ai, which you can share and comment on.
Write the pin and keep it committable:
mkdir -p .gstack && printf '%s\n' "$TARGET" > .gstack/explainer # local or artifact if git check-ignore -q .gstack/explainer 2>/dev/null; then grep -q '^!\.gstack/explainer$' .gitignore 2>/dev/null \ || echo '!.gstack/explainer' >> .gitignore git add .gitignore && git add -f .gstack/explainer else git add .gstack/explainer fiA run with nobody to answer writes no file, which means
local.Installable. What "installed" means for this project, so
/superpowers-gstack:work-statecan say whether the landed version is the one in use. If CLAUDE.md already has a line startingInstallable:outside the plugin's sections and code blocks, the script keeps it; do not re-ask. Otherwise pick the recommendation by these rules, in order:.claude-plugin/plugin.jsonexists →plugin- the track is
macosorboth, and a scheme'sSUPPORTED_PLATFORMScontainsmacosx(xcodebuild -showBuildSettings -scheme <Scheme> | grep SUPPORTED_PLATFORMSper scheme fromxcodebuild -list) →macos-app <Scheme>; with several such schemes, name the one that belongs in the Dock and list the others as options - otherwise →
none, orcommand <cmd>when the project has a read-only check of its own that exits 0 when the installed copy is current (an iOS app, a CLI onPATH)
Then ask once with
AskUserQuestion:What should count as "installed" once work lands? I'll check it after every landing and show it in the status line.
<recommendation>(recommended) — [one line on what it checks: the app in/Applicationsbuilt fromorigin/main; the plugin validates and its version has a CHANGELOG entry; the command exits 0; nothing to install]- [the other plausible shape] — [what it checks]
Pass the answer as
--installable '<answer>'(plugin,none,macos-app <Scheme>orcommand <cmd>; anything else is refused with exit 2 before any write). The script writesInstallable: …under## <project> install, a heading the project owns from then on, and never edits it again: a wrong answer is corrected by editing that line by hand. A run with nobody to answer passes no flag and writes no line, and the Step 0 short path does not ask at all.
Step 5: Dry run, then ask
SKILL_DIR='<the base directory the Skill tool printed>'
SCRIPT="$SKILL_DIR/../../scripts/adapt-claude-md.py"
python3 "$SCRIPT" --dry-run --mkdirs \
--set 'DOMAIN_SENSITIVITY=<value>' [--set 'IOS_SIMULATOR=<value>' --set 'DEVELOPMENT_TEAM=<value>'] \
[--routing-file .gstack/adapt-routing.md] [--no-model-routing] [--local-state '<answer>'] \
[--installable '<answer>']
Exit 2 is a refusal with the reason on stderr (BLOCKED, UNRESOLVED PLACEHOLDER,
UNREADABLE): fix the input it names and re-run; never work around it by editing the
file. Exit 0 prints the report — Changes made / Preserved / Removed (not plugin
prose) / Deferred (grown past its block, not upgraded) — and ends with one JSON line.
Present, in this order:
- The gap analysis: what already works, what the run will add or upgrade, anything in
the existing CLAUDE.md that contradicts the workflow ("never use subagents", "don't
use TDD"). With the vibe profile, also list every rule that contradicts the vibe
contract ("write a PRD before any code", "ask before each phase") and let the user
choose which one stands. Also note whether there is a remote and a branch workflow (
/reviewand/shipneed both; if onmainwith uncommitted work, warn and do not branch for the user). - The report's
Deferredentries, if any. Each is a plugin-managed section that has grown past its block — project knowledge is living inside it, and replacing it would destroy that. For each one, show theat_risklines from the JSON and offer two outcomes: move that content into a new unmarked section and upgrade (recommended — the script rescues the lines it cannot find in the block, plus the section's own subheadings, into## <project> — notes rescued from "<heading>", where no upgrade will ever touch them), or leave the section at its old version and skip its upgrade this run. - The report's inline notices — a section the script could not attribute to a past
emitter (preserved, current block inserted below it), a markerless
Code reuse disciplineorModel Routingthat is the project's own.
Then ask: "Shall I proceed with these changes?" — naming the move/leave choice for every deferred section.
STOP HERE. Do not continue until the user answers. A run with nobody to answer (a
--print session that pre-answered Steps 2–3, a subagent, an orchestrator) proceeds
with every deferred section left at its old version — the script's own default;
a stale section is recoverable, a deleted one is not.
Step 6: Apply and report
Run the same command without --dry-run, adding --rescue <marker> (the marker field
of the deferred entry, e.g. --rescue gstack-xcode-tools) for every section the user
chose to move. The script snapshots CLAUDE.md to .gstack/CLAUDE.md.pre-adapt (rotated,
never overwritten; excluded from git via .git/info/exclude) before its one write,
creates docs/superpowers/specs/ and plans/ with .gitkeep, and prints the final
report.
Relay the report to the user verbatim. Its three labels —
**Removed (not plugin prose):**, Nothing project-authored was removed. and
**Deferred (grown past its block, not upgraded):** — stay in English even when the
rest of your message is in the user's language; tooling greps them. The Removed block
lists every removed line the new block does not carry; it is over-inclusive by design
(a reworded plugin sentence can land there), so read it as candidates for a glance,
not as a verdict. The Snapshot line names the restore command; repeat it. When the report
says the script created .claude/skills/<name>/SKILL.md, run git add on that file (like the
pin), so a worktree cleanup does not lose it.
Whenever a marker-managed section was replaced, add:
Where project knowledge belongs. A heading carrying a
gstack-<name>-vNmarker is plugin-owned:/adaptreplaces the whole section on every upgrade. Pasting rescued content back into one guarantees a repeat at the next upgrade. Project findings — the measurement you took, the flag that turned out to work, the thing that cost you an hour — belong in your own H2 section with no marker./adaptleaves those alone, with one exception: the headings it manages are reserved even when unmarked, because an unmarked copy of one reads as an older emitted section. Prefix your own headings with this project's name and none of them can collide.
Then ask:
Would you like me to run a comprehensive review of the adaptation? It checks that the routing matches your stack and test setup, that nothing project-authored was lost (re-reading
diff .gstack/CLAUDE.md.pre-adapt CLAUDE.md), that existing conventions do not contradict the new rules, and thatdocs/superpowers/is in place. Recommended for projects with a complex existing setup.
STOP HERE. If the user says yes: re-read the new CLAUDE.md end to end; cross-check
the routing against the project (/qa without a browser UI, /cso without auth or
user data, are wrong); re-read the < side of the snapshot diff with fresh eyes for
project content wearing plugin-shaped wording; check for contradictions with existing
instructions; walk three or four common scenarios through the Routing Logic. Fix what
you find and re-verify.
Step 7: Suggest next steps
Next steps:
- Vibe profile? →
/superpowers-gstack:vibe <what to build>— and fill in the context skill as you learn the project- Working on a new feature? →
/superpowers-gstack:vibe(vibe profile) or/superpowers:brainstorming(classic)- Have code ready for review? →
/review- Want a product-framing session first? → type
/office-hoursyourself; it is never routed automaticallyTip: Run
/superpowers-gstack:adaptagain after major project changes (new deploy target, added test framework) and after every plugin upgrade — the session-start hook nudges when the CLAUDE.md version marker lags.
What this skill never changes: test configuration, CI pipelines, git hooks (unless they directly conflict), code-style or lint configuration, and any CLAUDE.md content outside the sections the script manages.