Compare commits

..

97 Commits

Author SHA1 Message Date
Jesse Vincent
f198f1e7d9 @mhat reported that his claude got confused about 'debugging' being named as a skill in the bootstrap 2026-05-21 14:16:08 -07:00
Drew Ritter
49bf5ad6dc Align Pi mapping with action vocabulary 2026-05-13 17:58:46 -07:00
Drew Ritter
4bd0973879 Bump evals submodule for Pi backend 2026-05-13 17:58:46 -07:00
Jesse Vincent
452f1ed40b chore: keep pi extension under .pi 2026-05-13 17:58:46 -07:00
Jesse Vincent
cafbc5a4bd feat: add pi superpowers package extension 2026-05-13 17:58:46 -07:00
Jesse Vincent
da35948daf docs: plan pi extension and evals work 2026-05-13 17:58:46 -07:00
Drew Ritter
d4d99117f2 Tighten cross-platform tool references 2026-05-13 17:46:28 -07:00
Jesse Vincent
01034bcf8f Phase E: action-language tool vocabulary
Replace Claude-Code-specific tool names in skill prose, prompt
templates, and OpenCode-facing docs with action-language descriptions
that resolve to each runtime's native tool via the per-platform refs.

Changes by category:

- Prose mentions ("Use TodoWrite to track...", "Use Task tool with
  general-purpose type") → action language ("Track each item as a
  todo", "Dispatch a general-purpose subagent")

- Prompt template headers (6 files): "Task tool (general-purpose):"
  → "Subagent (general-purpose):" — preserves the type information
  without naming Claude Code's specific dispatch tool

- DOT flowchart node labels: "Invoke Skill tool" → "Invoke the
  skill"; "Create TodoWrite todo per item" → "Create a todo per
  item"

- OpenCode INSTALL.md and docs/README.opencode.md: replace the old
  "TodoWrite → todowrite, Task → @mention" mapping (which both
  taught a vocabulary skills no longer use AND was wrong about
  @mention being a real OpenCode syntax) with an action-language
  mapping verified against the installed OpenCode CLI's tool
  inventory.

The platform-tools refs landed in Phase B already document each
runtime's resolution; skills now speak in the actions those refs
map. Tool names that genuinely belong only in the per-platform
dispatch section ("In Claude Code: Use the `Skill` tool") and the
Claude-Code-specific Bash run_in_background flag note in
visual-companion remain — those are intentional carve-outs.
2026-05-13 17:46:28 -07:00
Jesse Vincent
b87a5e4721 Phase D: cross-runtime tweaks (visual-companion, executing-plans, test)
Misc platform/runtime statements and adjacencies that don't fit the
prose, config-ref, README-ordering, or tool-vocabulary buckets:

- visual-companion frame template: rename CSS/HTML id #claude-content
  → #frame-content. The id is purely styling — nothing external
  references it. The brainstorm-server test that asserted the old
  string is updated in lockstep.

- visual-companion launch instructions: add a Copilot CLI section
  alongside Claude Code, Codex, and Gemini CLI; combine the Claude
  Code (macOS / Linux) and (Windows) sections so heading style
  matches the other (non-OS-qualified) platforms.

- visual-companion: "Use Write tool" → "Use your file-creation tool"
  for the cat/heredoc warning. The prohibition is what's load-
  bearing, not the tool name.

- executing-plans/SKILL.md: list all subagent-capable runtimes
  (Claude Code, Codex CLI, Codex App, Copilot CLI, Gemini CLI) and
  point at the per-platform tool refs as the source of truth.

- executing-plans/SKILL.md: relative path "using-superpowers/
  references/" → "../using-superpowers/references/" to resolve
  correctly from the executing-plans/ directory.

No bundled spec doc here — Phase D was scope-extension work that
took place across rounds, with no standalone spec authored.
2026-05-13 17:46:28 -07:00
Jesse Vincent
e47d6f4f85 Phase C: alphabetize README platform listings + spec
Quickstart link list and the per-harness install sub-sections both
reorder to strict alphabetical:

  Claude Code, Codex App, Codex CLI, Cursor, Factory Droid,
  Gemini CLI, GitHub Copilot CLI, OpenCode

Three blocks moved (Codex App swaps with Codex CLI; Cursor moves up
two slots; GitHub Copilot CLI moves up one). Claude Code stays first
by alphabetical chance.

Each install sub-section's content is byte-identical pre/post —
only the positions change. Quickstart anchors verified against the
new heading order.
2026-05-13 17:46:28 -07:00
Jesse Vincent
5c0402736e Phase B: config-file refs + per-platform tool refs + spec
Two structural changes:

1. Generalize CLAUDE.md-specific guidance:
   - "Project-specific conventions (put in CLAUDE.md)" → "(put in
     your instructions file)" in writing-skills/SKILL.md
   - "(explicit CLAUDE.md violation)" → "(explicit instruction-file
     violation)" in receiving-code-review/SKILL.md
   - The instruction-priority list in using-superpowers/SKILL.md
     stays inclusive (CLAUDE.md, GEMINI.md, AGENTS.md) — that's
     load-bearing, not a substitution opportunity.

2. Per-platform tool reference files at skills/using-superpowers/
   references/{claude-code,codex,copilot,gemini}-tools.md. Each ref
   documents:
   - The runtime's preferred instructions file (CLAUDE.md, AGENTS.md,
     GEMINI.md, etc.) and how it loads
   - The runtime's personal-skills directory + cross-runtime
     ~/.agents/skills/ path where applicable
   - Action-language → tool-name mapping table

Tool names and table content reflect the source-verified state from
direct inspection of openai/codex, google-gemini/gemini-cli,
sst/opencode, and the installed @github/copilot package. Filenames
and behaviors are sourced from each runtime's official docs.

Files in this commit also pick up later-phase changes that
accumulated on the same files (using-superpowers/SKILL.md "How to
Access Skills" overhaul, action-language flowchart, refs' final
table content). The bundled spec records original scope.
2026-05-13 17:46:28 -07:00
Jesse Vincent
d0e413b591 Phase A: agent-neutral prose + CSO → SDO + spec
Replace generic third-person "Claude" with "agents" / "your agent"
forms across active skill prose, the README intro, and the vendored
anthropic-best-practices.md reference. Carve-outs preserved:
historical attribution paths, the "Variant C: Claude.AI Emphatic
Style" example label, model identifiers (Haiku/Sonnet/Opus), and the
"In Claude Code:" per-platform skill-dispatch list.

Coined-term rename: "Claude Search Optimization (CSO)" → "Skill
Discovery Optimization (SDO)" in writing-skills/SKILL.md.

Files in this commit also pick up later-phase changes that
accumulated on the same files (dispatching-parallel-agents code-
example transformation, writing-skills numbering and path fixes).
The bundled spec at docs/superpowers/specs/ records the original
scope and the carve-outs.

README.md gets only its prose change here; the alphabetization
lands in Phase C's commit.
2026-05-13 17:46:28 -07:00
Drew Ritter
d25618db58 Move eval harness to submodule (#1541) 2026-05-13 12:25:41 -07:00
Drew Ritter
3d6dc90c6d fix(tdd): link testing anti-patterns reference (#1532)
Fixes #1529.
2026-05-12 17:22:42 -07:00
Drew Ritter
a152bb3932 [codex] replace Circle K signal with generic review guidance (#1531)
* Remove Circle K signal from review skill

* Add generic review hesitation guidance

* Use Jesse wording for review hesitation guidance
2026-05-12 17:22:19 -07:00
Drew Ritter
3dfb376268 fix: remove global worktree path fallback (#1476) 2026-05-12 10:24:45 -07:00
Drew Ritter
491df7360c fix(using-git-worktrees): repair skipped Step 2 numbering (#1522) 2026-05-11 17:50:01 -07:00
fuleinist
9088f563e7 fix: remove stale Cursor plugin refs 2026-05-11 17:04:35 -07:00
Stable Genius
d4cf61b4c8 fix(writing-skills): use markdown link for testing methodology reference 2026-05-11 16:51:00 -07:00
Drew Ritter
7f02ccd91b evals: use pre-commit hooks 2026-05-06 15:47:39 -07:00
Drew Ritter
35e42a16ce evals: add Gemini 2.5 Flash backend 2026-05-06 15:47:39 -07:00
Drew Ritter
58082d04f8 evals: drop drill source marker 2026-05-06 15:47:39 -07:00
Drew Ritter
3dc0ea6876 evals: remove unreleased wave scenarios 2026-05-06 15:47:39 -07:00
Jesse Vincent
0bf37499b4 Address adversarial review findings
- evals/README.md, evals/CLAUDE.md: fix uv install command from
  'uv sync --dev' to 'uv sync --extra dev'. Drill's pyproject.toml
  uses [project.optional-dependencies], so --dev is a no-op for
  pytest/ruff/ty; --extra dev is the correct invocation.
- tests/claude-code/run-skill-tests.sh: drop test-requesting-code-review.sh
  from integration_tests array (file deleted earlier in this branch).
- tests/claude-code/README.md: replace test-requesting-code-review.sh
  section with test-worktree-native-preference.sh (the worktree test
  is kept; the code-review test was lifted into drill).
- docs/testing.md, CLAUDE.md: remove "Copilot CLI" from the harness
  list. evals/backends/ has claude*, codex, gemini configs but no
  copilot.yaml, so the claim was unsupported.

Adversarial review credit: reviewer #2 found four legitimate issues
(uv-sync, run-skill-tests stale ref, README stale ref via #1, and
Copilot CLI fabrication); reviewer #1 found two distinct issues
(run-skill-tests + tests/claude-code/README.md). Reviewer #2 wins
this round.
2026-05-06 15:47:39 -07:00
Jesse Vincent
f7c5312265 docs: introduce evals/ as the canonical skill-behavior eval harness
- docs/testing.md split into Plugin tests + Skill behavior evals.
  Plugin tests section enumerates the bash tests that survive
  (kept by drill-coverage analysis or as describe-skill tests).
- CLAUDE.md adds Eval harness section pointing at evals/.
- README.md Contributing section mentions evals/ alongside tests/.
- .gitignore adds evals/{results,.venv,.env} as belt-and-suspenders
  (evals/.gitignore covers these locally; root-level entries help
  tooling that does not recurse into nested ignore files).
2026-05-06 15:47:39 -07:00
Jesse Vincent
f5175fb31a docs: annotate dated artifacts referencing lifted bash tests
- RELEASE-NOTES.md: note that test-requesting-code-review.sh and
  test-document-review-system.sh were lifted into drill scenarios
  on 2026-05-06; references are preserved as dated artifacts.
- docs/superpowers/plans/2026-03-23-codex-app-compatibility.md:
  note that tests/skill-triggering/ was lifted into drill scenarios
  on 2026-05-06; the run-all.sh reference is a dated artifact.

Subagent second-pass scrub confirmed no other active references in
the tree (excluding evals/ and the spec/plan for this work itself).
2026-05-06 15:47:39 -07:00
Jesse Vincent
45c7dc2cce tests: annotate three kept bash tests with drill coverage notes
- test-worktree-native-preference.sh: drill covers PRESSURE phase only;
  RED + GREEN baselines have no drill counterpart and are kept so
  the RED-GREEN-REFACTOR validation remains rerunnable end-to-end.
- test-subagent-driven-development-integration.sh: drill covers the
  YAGNI subset (forbidden exports + reviewer-as-gate). Bash adds
  >=3 commits, >=2 subagent dispatches, TodoWrite usage, test file
  existence check, and token-budget telemetry. Kept until drill
  scenario covers those or they are retired.
- test-subagent-driven-development.sh: tests agent's ability to
  *describe* SDD (string matches against expected keywords). Drill
  scenarios test behavior, not description-recall. Kept by design.

Subagent verification recorded in commit messages of subsequent
deletions; gap analyses driving these annotations are also in the
verification subagent reports for the gating sweep.
2026-05-06 15:47:39 -07:00
Jesse Vincent
39d29a6c28 tests: remove test-requesting-code-review.sh (covered by drill code-review-catches-planted-bugs)
Subagent verification: every bash assertion (skill invocation,
subagent dispatch, SQL injection flagged, credential handling
flagged, no merge approval) maps to drill verify checks. Drill is
stricter: bundles severity (Critical/Important) into the same
criteria as the finding itself (bash split severity into a separate
test). Setup parity covered (src/db.js with string concat + identity
hash, two commits).

The drill scenario header explicitly says it is the
"cross-harness, semantically-judged replacement for the bash test."
2026-05-06 15:47:39 -07:00
Jesse Vincent
f1d2005de3 tests: remove test-document-review-system.sh (covered by drill spec-reviewer-catches-planted-flaws)
Subagent verification: every bash assertion (TODO in Requirements
section flagged, "specified later" deferral flagged, Issues section
present, did-not-approve verdict) maps to drill verify.criteria
entries. Setup parity covered by setup.assertions (test-feature-design.md
exists with TODO + 'specified later' content). Drill is stricter:
asserts tool-called Agent (subagent dispatch) which the bash test
did not check.
2026-05-06 15:47:39 -07:00
Jesse Vincent
c0a65f1b4d tests: remove subagent-driven-dev fixtures (covered by drill sdd-go-fractals + sdd-svelte-todo)
The bash test had ZERO output assertions — it just ran claude -p
and printed token usage. Drill's scenarios are strictly more
rigorous:

go-fractals: skill-called SDD + tool-called Agent + go test ./...
passes + cmd/fractals/main.go exists + >=4 commits + LLM criteria
verifying real SDD workflow.

svelte-todo: skill-called SDD + tool-called Agent + npm test passes
+ playwright e2e passes + package.json + svelte.config.js or
vite.config.ts + >=4 commits + LLM criteria.

design.md and plan.md are byte-identical between bash fixtures and
drill fixtures (evals/fixtures/sdd-{go-fractals,svelte-todo}/).
Drill's setup helper (scaffold_sdd_*) forces git init -b main
(stricter than bash's reliance on init.defaultBranch). The
.claude/settings.local.json from bash scaffold.sh is unnecessary
for drill since permissions are managed via backend YAML.

Subagent verification: SAFE TO DELETE for both.
2026-05-06 15:47:39 -07:00
Jesse Vincent
f10cddac0d tests: remove run-claude-describes-sdd.sh (covered by drill mid-conversation-skill-invocation)
Subagent verification: every bash assertion (Skill tool invoked +
specific skill name 'subagent-driven-development' loaded after the
agent describes it conversationally in turn 1) maps to the drill
scenario's skill-called assertion + criteria paragraph requiring
the skill to fire in direct response to the second user message.
Drill additionally asserts tool-called Agent (subagent dispatch)
which is stricter than the bash test.

Other runners in tests/explicit-skill-requests/ (haiku, multiturn,
extended-multiturn) and their prompt files are preserved — they
have no drill coverage and exercise different behaviors.
2026-05-06 15:47:39 -07:00
Jesse Vincent
371f41596b tests: remove skill-triggering bash prompts (covered by drill triggering-* scenarios)
Subagent verification confirmed each prompt's intent matches its
corresponding drill scenario's turns[].intent verbatim, and each
scenario has both a deterministic skill-called assertion and a
semantic LLM criterion confirming the matching skill was loaded
(actually a stronger check than the bash test, which only confirms
the skill fires anywhere in the stream).

All 6 prompts deleted. The runner had no remaining prompts to drive,
so run-test.sh and run-all.sh deleted as well.
2026-05-06 15:47:39 -07:00
Jesse Vincent
6f0adebe96 evals: drop SUPERPOWERS_ROOT setup step from README/CLAUDE
The cli.py helper now defaults the env var. Mention as override only.
2026-05-06 15:47:39 -07:00
Jesse Vincent
fd5b53cb85 evals: drop SUPERPOWERS_ROOT from codex/gemini required_env
These backends only read SUPERPOWERS_ROOT via engine.py/setup.py's
os.environ access, which the new cli.py default helper supplies
automatically. claude*.yaml keep SUPERPOWERS_ROOT in required_env
because they interpolate ${SUPERPOWERS_ROOT} into --plugin-dir args.
2026-05-06 15:47:39 -07:00
Jesse Vincent
be0357f98a evals: default SUPERPOWERS_ROOT to parent of evals/ if unset
Adds _set_superpowers_root_default() to drill/cli.py, called at
module import after load_dotenv(). PROJECT_ROOT resolves to evals/
post-lift; its parent is the superpowers repo root, which is the
correct value for SUPERPOWERS_ROOT.

Existing env values are respected as overrides via os.environ.setdefault.

Tests:
- helper sets default when var is unset
- helper does not override when var is already set
2026-05-06 15:47:39 -07:00
Jesse Vincent
3b412a3836 Lift drill into evals/ at 013fcb8b7dbefd6d3fa4653493e5d2ec8e7f985b
rsync of obra/drill@013fcb8b7d into superpowers/evals/, excluding
.git/, .venv/, results/, .env/, __pycache__/, *.egg-info/,
.private-journal/.

The drill repo is unaffected by this commit; archival is a separate
manual step after this PR merges.

Source SHA recorded at evals/.drill-source-sha for divergence
detection.
2026-05-06 15:47:39 -07:00
Jesse Vincent
2e46e9590d Plan: lift drill into superpowers as evals/
15-task implementation plan derived from the design spec at
docs/superpowers/specs/2026-05-06-lift-drill-into-evals-design.md.

Each task is bite-sized (2-5 min steps) with exact commands, exact
file paths, and exact code where required. Subagent verification
gates per the spec are written out as concrete prompt templates.

Self-review:
- Spec coverage: every spec section maps to a task
- Placeholder scan: no TBD/TODO/placeholder/fill-in-later language
- Type consistency: helper named _set_superpowers_root_default
  consistently; drill SHA recorded in evals/.drill-source-sha
  consistently
2026-05-06 15:47:39 -07:00
Jesse Vincent
58f821314d Spec: address adversarial review findings
Two parallel reviewers raised legitimate issues against the lift-drill-
into-evals spec. Updates:

- Coverage map for tests/explicit-skill-requests/ corrected: 6 run-*.sh
  scripts + prompts, not "2 scenarios cover all". Several scripts
  (Haiku, multi-turn, please-use-brainstorming, use-systematic-debugging)
  have no drill counterpart and stay.
- tests/claude-code/test-subagent-driven-development.sh marked as
  meta/documentation test (asks agent to describe SDD); no drill
  scenario covers description tests; defaults to keep.
- Path-defaults section now shows verified evidence: PROJECT_ROOT
  resolves to evals/ post-move; only claude*.yaml substitute
  ${SUPERPOWERS_ROOT} in args (codex/gemini use it via os.environ
  in pre-run hooks); helper invocation order specified (after
  load_dotenv, before click definitions).
- Step 2 copy uses explicit rsync excludes (.git, .venv, results,
  .env, __pycache__, *.egg-info, .private-journal); checksum-level
  verification rather than file-count.
- Drill SHA recorded at copy time in commit message and
  evals/.drill-source-sha for divergence detection.
- evals/tests/ pytest suite added to verification protocol.
- Reference scrub list expanded: RELEASE-NOTES.md,
  docs/superpowers/plans/, .codex-plugin/ (corrected from .codex/),
  lefthook.yml. Excluded dirs called out (node_modules/, .venv/,
  evals/).
- Historical plan docs / RELEASE-NOTES handling: annotate, don't
  rewrite.
- evals/lefthook.yml move documented (drill ships its own;
  contributors run cd evals && lefthook run pre-commit manually).
- PR description checklist includes archival action item for
  obra/drill post-merge.

False finding rejected: svelte-todo fixture is complete on disk
(design.md + plan.md + scaffold.sh present); reviewer #1 #3 dropped.
2026-05-06 15:47:39 -07:00
Jesse Vincent
81472cc9e6 Spec: lift drill into superpowers as evals/
Records scope, branching, architecture, deletion gate, verification
protocol, path/config edits, migration ordering, and post-implementation
verification. Frames CI integration, scenario co-location, and Python
package rename as deferred work.

Per-file deletion of bash tests under superpowers/tests/ is gated by a
subagent that compares each bash assertion to its drill scenario's
verify block. Default keeps the bash test if any assertion is unmatched.

Branching: independent off dev (f/evals-lift), not stacked on
f/cross-platform.
2026-05-06 15:47:39 -07:00
robotsnh
b4363df1b9 docs: turned the dash in "- Jesse" into an escape sequence (#1474)
Replaced the bullet point next to "Jesse" in the sponsorship section of the `README` into a dash. This is needed so the `README` renders properly on markdown viewers.
2026-05-06 11:22:19 -07:00
Jesse Vincent
f2cbfbefeb Release v5.1.0 (#1468)
* docs: add Codex App compatibility design spec (PRI-823)

Design for making using-git-worktrees, finishing-a-development-branch,
and subagent-driven-development skills work in the Codex App's sandboxed
worktree environment. Read-only environment detection via git-dir vs
git-common-dir comparison, ~48 lines across 4 files, zero breaking changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: address spec review feedback for PRI-823

Fix three Important issues from spec review:
- Clarify Step 1.5 placement relative to existing Steps 2/3
- Re-derive environment state at cleanup time instead of relying on
  earlier skill output
- Acknowledge pre-existing Step 5 cleanup inconsistency

Also: precise step references, exact codex-tools.md content, clearer
Integration section update instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: address team review feedback for PRI-823 spec

- Add commit SHA + data loss warning to handoff payload (HIGH)
- Add explicit commit step before handoff (HIGH)
- Remove misleading "mark as externally managed" from Path B
- Add executing-plans 1-line edit (was missing)
- Add branch name derivation rules
- Add conditional UI language for non-App environments
- Add sandbox fallback for permission errors
- Add STOP directive after Step 0 reporting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: clarify executing-plans in What Does NOT Change section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add cleanup guard test (#5) and sandbox fallback test (#10) to spec

Both tests address real risk scenarios:
- #5: cleanup guard bug would delete Codex App's own worktree (data loss)
- #10: Local thread sandbox fallback needs manual Codex App validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add implementation plan for Codex App compatibility (PRI-823)

8 tasks covering: environment detection in using-git-worktrees,
Step 1.5 + cleanup guard in finishing-a-development-branch,
Integration line updates, codex-tools.md docs, automated tests,
and final verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs(codex-tools): add named agent dispatch mapping for Codex (#647)

* fix(writing-skills): correct false 'only two fields' frontmatter claim (#882)

* Replace subagent review loops with lightweight inline self-review

The subagent review loop (dispatching a fresh agent to review plans/specs)
doubled execution time (~25 min overhead) without measurably improving plan
quality. Regression testing across 5 versions (v3.6.0 through v5.0.4) with
5 trials each showed identical plan sizes, task counts, and quality scores
regardless of whether the review loop ran.

Changes:
- writing-plans: Replace subagent Plan Review Loop with inline Self-Review
  checklist (spec coverage, placeholder scan, type consistency)
- writing-plans: Add explicit "No Placeholders" section listing plan failures
  (TBD, vague descriptions, undefined references, "similar to Task N")
- brainstorming: Replace subagent Spec Review Loop with inline Spec Self-Review
  (placeholder scan, internal consistency, scope check, ambiguity check)
- Both skills now use "look at it with fresh eyes" framing

Testing: 5 trials with the new skill show self-review catches 3-5 real bugs
per run (spawn positions, API mismatches, seed bugs, grid indexing) in ~30s
instead of ~25 min. Remaining defects are comparable to the subagent approach.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert "Replace subagent review loops with lightweight inline self-review"

This reverts commit bf8f7572eb.

* Reapply "Replace subagent review loops with lightweight inline self-review"

This reverts commit b045fa3950.

* Add v5.0.6 release notes

* Move brainstorm server metadata to .meta/ subdirectory

Metadata files (.server-info, .events, .server.pid, .server.log,
.server-stopped) were stored in the same directory served over HTTP,
making them accessible via the /files/ route. They now live in a .meta/
subdirectory that is not web-accessible.

Also fixes a stale test assertion ("Waiting for Claude" → "Waiting for
the agent").

Reported-By: 吉田仁

* Revert "Move brainstorm server metadata to .meta/ subdirectory"

This reverts commit ab500dade6.

* Separate brainstorm server content and state into peer directories

The session directory now contains two peers: content/ (HTML served to
the browser) and state/ (events, server-info, pid, log). Previously
all files shared a single directory, making server state and user
interaction data accessible over the /files/ HTTP route.

Also fixes stale test assertion ("Waiting for Claude" → "Waiting for
the agent").

Reported-By: 吉田仁

* Fix owner-PID false positive when owner runs as different user

ownerAlive() treated EPERM (permission denied) the same as ESRCH
(process not found), causing the server to self-terminate within 60s
whenever the owner process ran as a different user. This affected WSL
(owner is a Windows process), Tailscale SSH, and any cross-user
scenario.

The fix: `return e.code === 'EPERM'` — if we get permission denied,
the process is alive; we just can't signal it.

Tested on Linux via Tailscale SSH with a root-owned grandparent PID:
- Server survives past the 60s lifecycle check (EPERM = alive)
- Server still shuts down when owner genuinely dies (ESRCH = dead)

Fixes #879

* Fix owner-PID lifecycle monitoring for cross-platform reliability

Two bugs caused the brainstorm server to self-terminate within 60s:

1. ownerAlive() treated EPERM (permission denied) as "process dead".
   When the owner PID belongs to a different user (Tailscale SSH,
   system daemons), process.kill(pid, 0) throws EPERM — but the
   process IS alive. Fixed: return e.code === 'EPERM'.

2. On WSL, the grandparent PID resolves to a short-lived subprocess
   that exits before the first 60s lifecycle check. The PID is
   genuinely dead (ESRCH), so the EPERM fix alone doesn't help.
   Fixed: validate the owner PID at server startup — if it's already
   dead, it was a bad resolution, so disable monitoring and rely on
   the 30-minute idle timeout.

This also removes the Windows/MSYS2-specific OWNER_PID="" carve-out
from start-server.sh, since the server now handles invalid PIDs
generically at startup regardless of platform.

Tested on Linux (magic-kingdom) via Tailscale SSH:
- Root-owned owner PID (EPERM): server survives ✓
- Dead owner PID at startup (WSL sim): monitoring disabled, survives ✓
- Valid owner that dies: server shuts down within 60s ✓

Fixes #879

* Release v5.0.6: inline self-review, brainstorm server restructure, owner-PID fixes

* fix: add Copilot CLI platform detection for sessionStart context injection

Copilot CLI v1.0.11 reads `additionalContext` from sessionStart hook
output, but the session-start script only emits the Claude Code-specific
nested format. Add COPILOT_CLI env var detection so Copilot CLI gets the
SDK-standard top-level `additionalContext` while Claude Code continues
getting `hookSpecificOutput`.

Based on PR #910 by @culinablaz.

* feat: add Copilot CLI tool mapping, docs, and install instructions

- Add references/copilot-tools.md with full tool equivalence table
- Add Copilot CLI to using-superpowers skill platform instructions
- Add marketplace install instructions to README
- Add changelog entry crediting @culinablaz for the hook fix

* fix(opencode): align skills path across bootstrap, runtime, and tests

The bootstrap text advertised a configDir-based skills path that didn't
match the runtime path (resolved relative to the plugin file). Tests
used yet another hardcoded path and referenced a nonexistent lib/ dir.

- Remove misleading skills path from bootstrap text; the agent should
  use the native skill tool, not read files by path
- Fix test setup to create a consistent layout matching the plugin's
  ../../skills resolution
- Export SUPERPOWERS_SKILLS_DIR from setup.sh so tests use a single
  source of truth
- Add regression test that bootstrap doesn't advertise the old path
- Remove broken cp of nonexistent lib/ directory

Fixes #847

* docs: add OpenCode path fix to release notes

* fix(opencode): inject bootstrap as user message instead of system message

Move bootstrap injection from experimental.chat.system.transform to
experimental.chat.messages.transform, prepending to the first user
message instead of adding a system message.

This avoids two issues:
- System messages repeated every turn inflate token usage (#750)
- Multiple system messages break Qwen and other models (#894)

Tested on OpenCode 1.3.2 with Claude Sonnet 4.5 — brainstorming skill
fires correctly on "Let's make a React to do list" prompt.

* docs: update release notes with OpenCode bootstrap change

* docs: add worktree rototill design spec (PRI-974)

Design for detect-and-defer worktree support. Superpowers defers to
native harness worktree systems when available, falls back to manual
git worktree creation when not. Covers Phases 0-2: detection, consent,
native tool preference, finishing state detection, and three bug fixes
(#940, #999, #238).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: address SWE review feedback on worktree rototill spec

- Fix Bug #999 order: merge → verify → remove worktree → delete branch
  (avoids losing work if merge fails after worktree removal)
- Add submodule guard to Step 0 detection (GIT_DIR != GIT_COMMON is also
  true in submodules)
- Preserve global path (~/.config/superpowers/worktrees/) in detection for
  backward compatibility, just stop offering it to new users
- Add step numbering note and implementation notes section
- Expand provenance heuristic to cover global path and manual creation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: honest spec revisions after issue/PR deep dive

- Step 1a is the load-bearing assumption, not just a risk — if it fails,
  the entire design needs rework. TDD validation must be first impl task.
- #1009 resolution depends on Step 1a working, stated explicitly
- #574 honestly deferred, not "partially addressed"
- Add hooks symlink to Step 1b (PR #965 idea, prevents silent hook loss)
- Add stale worktree pruning to Step 5 (PR #1072 idea, one-line self-heal)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add worktree rototill implementation plan (PRI-974)

5 tasks: TDD gate for Step 1a, using-git-worktrees rewrite,
finishing-a-development-branch rewrite, integration updates,
end-to-end validation. Task 1 is a hard gate — if native tool
preference fails RED/GREEN, stop and redesign.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test: add RED/GREEN validation for native worktree preference (PRI-974)

Gate test for Step 1a — validates agents prefer EnterWorktree over
git worktree add on Claude Code. Must pass before skill rewrite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: rewrite using-git-worktrees with detect-and-defer (PRI-974)

Step 0: GIT_DIR != GIT_COMMON detection (skip if already isolated)
Step 0 consent: opt-in prompt before creating worktree (#991)
Step 1a: native tool preference (short, first, declarative)
Step 1b: git worktree fallback with hooks symlink and legacy path compat
Submodule guard prevents false detection
Platform-neutral instruction file references (#1049)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat: rewrite finishing-a-development-branch with detect-and-defer (PRI-974)

Step 2: environment detection (GIT_DIR != GIT_COMMON) before presenting menu
Detached HEAD: reduced 3-option menu (no merge from detached HEAD)
Provenance-based cleanup: .worktrees/ = ours, anything else = hands off
Bug #940: Option 2 no longer cleans up worktree
Bug #999: merge -> verify -> remove worktree -> delete branch
Bug #238: cd to main repo root before git worktree remove
Stale worktree pruning after removal (git worktree prune)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address spec review findings in both skill rewrites (PRI-974)

using-git-worktrees: submodule guard now says "treat as normal repo"
instead of "proceed to Step 1" (preserves consent flow)
using-git-worktrees: directory priority summaries include global legacy

finishing-a-development-branch: move git branch -d after Step 6 cleanup
to make Bug #999 ordering unambiguous (merge -> worktree remove -> branch delete)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update worktree integration references across skills (PRI-974)

Remove REQUIRED language from executing-plans and subagent-driven-development.
Consent and detection now live inside using-git-worktrees itself.
Fix stale 'created by brainstorming' claim in writing-plans.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: include worktrees/ (non-hidden) in finishing provenance check (PRI-974)

The creation skill supports both .worktrees/ and worktrees/ directories,
but the finishing skill's cleanup only checked .worktrees/. Worktrees
under the non-hidden path would be orphaned on merge or discard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: Step 1a validated through TDD — explicit naming + consent bridge (PRI-974)

Step 1a failed at 2/6 with the spec's original abstract text ("use your
native tool"). Three REFACTOR iterations found what works (50/50 runs):

1. Explicit tool naming — "do you have EnterWorktree, WorktreeCreate..."
   transforms interpretation into factual toolkit check
2. Consent bridge — "user's consent is your authorization" directly
   addresses EnterWorktree's "ONLY when user explicitly asks" guardrail
3. Red Flag entry naming the specific anti-pattern

File split was tested but proven unnecessary — the fix is the Step 1a
text quality, not physical separation of git commands. Control test
with full 240-line skill (all git commands visible) passed 20/20.

Test script updated: supports batch runs (./test.sh green 20), "all"
phase, and checks absence of git worktree add (reliable signal) rather
than presence of EnterWorktree text (agent sometimes omits tool name).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: update spec with TDD findings on Step 1a (PRI-974)

Step 1a's original "deliberately short, abstract" design was disproven
by TDD (2/6 pass rate). Spec now documents the validated approach:
explicit tool naming + consent bridge + red flag (50/50 pass rate).

- Design Principles: updated to reflect explicit naming over abstraction
- Step 1a: replaced abstract text with validated approach, added design
  note explaining the TDD revision and why file splitting was unnecessary
- Risks: Step 1a risk marked RESOLVED with cross-platform validation table
  and residual risk note about upstream tool description dependency

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: honest cross-platform validation table in spec (PRI-974)

Research confirmed Claude Code is currently the only harness with an
agent-callable mid-session worktree tool. All others either create
worktrees before the agent starts (Codex App, Gemini, Cursor) or have
no native support (Codex CLI, OpenCode).

Table now shows: what was actually tested (Claude Code 50/50, Codex CLI
6/6), what was simulated (Codex App 1/1), and what's untested (Gemini,
Cursor, OpenCode). Step 1a is forward-compatible for when other
harnesses add agent-callable tools.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: cross-platform validation on 5 harnesses (PRI-974)

Tested on Gemini CLI (gemini -p) and Cursor Agent (cursor-agent -p):
- Gemini: Step 0 detection 1/1, Step 1b fallback 1/1
- Cursor: Step 0 detection 1/1, Step 1b fallback 1/1

Both correctly identified no native agent-callable worktree tool,
fell through to git worktree add, and performed safety verification.
Both correctly detected existing worktrees and skipped creation.

5 of 6 harnesses now tested. Only OpenCode untested (no CLI access).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove incorrect hooks symlink step from worktree skill

Git worktrees inherit hooks from the main repo automatically via
$GIT_COMMON_DIR — this has been the case since git 2.5 (2015).
The symlink step was based on an incorrect premise from PR #965
and also fails in practice (.git is a file in worktrees, not a dir).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: address PR #1121 review — respect user preference, drop y/n

- Consent prompt: drop "(y/n)" and add escape valve for users who
  have already declared their worktree preference in global or
  project agent instruction files.
- Directory selection: reorder to put declared user preference
  ahead of observed filesystem state, and reframe the default as
  "if no other guidance available".
- Sandbox fallback: require explicitly informing the user that
  the sandbox blocked creation, not just "report accordingly".
- writing-plans: fully qualify the superpowers:using-git-worktrees
  reference.
- Plan doc: mirror the consent-prompt change.

Step 1a native-tool framing and the helper-scripts suggestion are
still outstanding — the first needs a benchmark re-run before softer
phrasing can be adopted without regressing compliance; the second is
exploratory and will get a thread reply.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: soften Step 1a native-tool framing per PR #1121 review

Address obra's comment on explicit step numbers / prescriptive tone.
Drops "STOP HERE if available", the "If YES:" gate, and the "even if /
even if / NO EXCEPTIONS" reinforcement paragraph. Keeps the specific
tool-name anchors (EnterWorktree, WorktreeCreate, /worktree, --worktree),
which the original TDD data showed are load-bearing.

A/B verified against drill harness on the 3 creation/consent scenarios
(consent-flow, creation-from-main, creation-from-main-spec-aware):
baseline explicit wording scored 12/12 criteria, softened wording also
scored 12/12. The "agent used the most appropriate tool" criterion
passed in all 3 softened runs — agents still picked EnterWorktree via
ToolSearch without the imperative framing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: drop instruction file enumeration per PR #1121 review

Jesse flagged that the verbose CLAUDE.md/AGENTS.md/GEMINI.md/.cursorrules
enumeration (a) chews tokens, (b) confuses models that anchor on exact
strings, and (c) is repeated DRY-violatingly across 3+ locations.

Replace with abstract "your instructions" framing in four spots:
- skills/using-git-worktrees/SKILL.md Step 0 → Step 1 transition
- skills/using-git-worktrees/SKILL.md Step 1b Directory Selection
- docs/superpowers/plans/2026-04-06-worktree-rototill.md (both mirror locations)

Same intent, harness-agnostic phrasing, ~half the tokens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: replace hardcoded /Users/jesse with generic placeholders (#858)

* Remove the deprecated legacy slash commands (#1188)

* fix: prevent subagent-driven-development from pausing every 3 tasks

requesting-code-review had "review after each batch (3 tasks)" for
executing-plans, which leaked into subagent-driven-development as a
check-in cadence. Replaced with flexible "each task or at natural
checkpoints" and added explicit continuous execution directive to
subagent-driven-development.

* Remove Integration sections from skills

These sections don't help with steering and are a legacy of the time
before agents had native skills systems.

* fix(opencode): cache bootstrap content at module level to eliminate per-step file I/O

getBootstrapContent() called fs.existsSync + fs.readFileSync + regex
frontmatter parsing on every agent step with zero caching.  The
experimental.chat.messages.transform hook fires every step in opencode's
agent loop (messages are reloaded from DB each step via
filterCompactedEffect).  A 10-step turn triggered 10 redundant file
reads + 10 regex parses for content that never changes during a session.

Changes:
- Add module-level _bootstrapCache (undefined = not loaded, null = file
  missing) so the first call reads and parses SKILL.md, all subsequent
  calls return the cached string with zero filesystem access
- Cache the null sentinel when SKILL.md is missing, preventing repeated
  fs.existsSync probes
- Add _testing export (resetCache/getCache) for test infrastructure
- Clarify the injection guard comment explaining how it interacts with
  opencode's per-step message reloading
- Add 15 regression tests covering cache behavior, fs call counts,
  injection guard, missing file sentinel, cache reset, and source audit

Fixes #1202

* test(opencode): simplify bootstrap cache coverage

* docs: clarify opencode install caveats

* test(opencode): modernize integration tests

* docs: add Factory Droid installation instructions

* Preserve Codex marketplace metadata

* docs: add README quickstart install links (#1293)

* docs(codex-tools): fix subagent wait mapping to wait_agent

Update the Codex tool mapping so Claude Code 'Task returns result' maps to the current Codex spawned-agent result tool, wait_agent. Also clarify that older Codex builds exposed spawned-agent waiting as wait, while current bare wait is the code-mode exec/wait surface for yielded exec cells.

Verified with Drill:
- codex-tool-mapping-comprehension fails against dev with task_returns_result=wait
- codex-tool-mapping-comprehension passes against this PR with task_returns_result=wait_agent and exec/wait scoped correctly
- codex-subagent-wait-mapping passes against this PR with spawn_agent -> wait_agent -> close_agent and PR963_OK returned

* fix(cursor): run SessionStart hook via run-hook.cmd on Windows

Route Cursor's Windows SessionStart hook through the existing run-hook.cmd dispatcher instead of invoking the extensionless session-start script directly. This avoids Windows opening the extensionless hook file and lets Git Bash run the script as intended.

Also removed an accidental UTF-8 BOM from hooks-cursor.json before merging.

Verified:
- hooks-cursor.json parses as JSON and has no BOM
- command is ./hooks/run-hook.cmd session-start
- CURSOR_PLUGIN_ROOT=/tmp/superpowers ./hooks/run-hook.cmd session-start emits valid Cursor JSON with additional_context

* fix(tests): make SDD integration test actually run its assertions

The SDD integration test silently bailed before printing any verification
results. Three independent bugs caused this:

1. `WORKING_DIR_ESCAPED` was computed from `$SCRIPT_DIR/../..` without
   resolving `..` segments. The resulting "directory" name contained
   literal `..` so `find` was looking in a path that doesn't exist.

2. With `set -euo pipefail`, the `find ... | sort -r | head -1` pipeline
   could exit non-zero (SIGPIPE on the producer when head closes early),
   killing the script silently before assertions ran.

3. The `claude -p` invocation never passed `--plugin-dir`, so it loaded
   the installed plugin instead of the working tree. Local edits to
   skills under test were not actually being tested.

Other adjustments:
- Run claude from inside the unique TEST_PROJECT directory instead of
  from the plugin root, so its session JSONL lives in its own
  `~/.claude/projects/` folder and doesn't race other concurrent
  claude sessions for "most recent file".
- Use the same character-normalization claude does (every non-alphanumeric
  becomes `-`) when computing the session dir name; macOS-resolved
  `/private/var/...` paths and tmp dirs with `.`/`_` in their names need
  this to round-trip correctly.
- Accept either `"name":"Agent"` or `"name":"Task"` in the subagent count
  — the harness renamed the tool but the test wasn't updated.

Verified on this branch: all six verification tests now pass against a
real end-to-end SDD run (skill invoked, 7 subagents dispatched, 6
TodoWrite calls, working code produced, tests pass, no extra features).

* feat: add Gemini CLI subagent support mapping

Map Gemini Task dispatch to @agent-name/@generalist and document parallel subagent dispatch for independent tasks.

* docs: update Codex plugin install guidance (#1288)

* Lift superpowers:code-reviewer agent into the requesting-code-review skill

The plugin had a single named agent (`agents/code-reviewer.md`) used by
two skills, while every other reviewer/implementer subagent in the repo
is dispatched as `general-purpose` with the prompt template living
alongside its skill. That asymmetry had no upside and several costs:

- Two sources of truth for the code review checklist (the agent file
  and `requesting-code-review/code-reviewer.md`), both drifting
  independently.
- `Codex` users could not use the named agent directly; the codex-tools
  reference doc had a workaround section explaining how to flatten the
  named agent into a `worker` dispatch.
- No third-party reliance on `superpowers:code-reviewer` inside this
  repo.

Changes:
- Merge `agents/code-reviewer.md` (persona + checklist) and
  `skills/requesting-code-review/code-reviewer.md` (placeholder
  template) into a single self-contained Task-dispatch template,
  matching the shape of `implementer-prompt.md`,
  `spec-reviewer-prompt.md`, etc.
- Update `skills/requesting-code-review/SKILL.md` and
  `skills/subagent-driven-development/code-quality-reviewer-prompt.md`
  to dispatch `Task (general-purpose)` instead of the named agent.
- Drop the now-obsolete "Named agent dispatch" workaround sections from
  `codex-tools.md` and `copilot-tools.md` — superpowers no longer ships
  any named agents, so those instructions documented nothing.
- Delete `agents/code-reviewer.md` and the empty `agents/` directory.

Tier 3 coverage for the change: a new behavioral test
`tests/claude-code/test-requesting-code-review.sh` plants real bugs
(SQL injection, plaintext password handling, credential logging) into
a tiny project, runs the actual `requesting-code-review` skill against
the working tree, and asserts the dispatched reviewer flags every
planted issue at Critical/Important severity and refuses to approve
the diff.

Verified end-to-end on this branch:
- The new test passes (5/5 assertions; reviewer caught all planted
  bugs and several others).
- The existing SDD integration test still passes (7/7 subagents
  dispatched, all as `general-purpose`; spec compliance still
  rejects extra features; produced code is correct).
- Session JSONLs confirm zero remaining `superpowers:code-reviewer`
  dispatches anywhere in the SDD pipeline.

* Prepare v5.1.0: release notes and version bump

Add v5.1.0 release notes covering:
- Removals: legacy slash commands (/brainstorm, /execute-plan,
  /write-plan), skill Integration sections
- Worktree skills rewrite (PRI-974, PR #1121)
- Contributor guidelines for AI agents
- Codex plugin mirror tooling (PR #1165)
- OpenCode bootstrap caching (#1202)
- SDD pause-every-3-tasks fix; SDD integration test fixes
- Cursor Windows hook routing
- Gemini CLI subagent dispatch mapping
- Skill terminology cleanups
- Install docs (Factory Droid, Codex, quickstart links)

Bumps version 5.0.7 -> 5.1.0 across all declared files via
scripts/bump-version.sh; not yet tagged or released.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Drew Ritter <drewritter@workerbee.local>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Drew Ritter <drew@primeradiant.com>
Co-authored-by: Blaž Čulina <culina.blaz@nsoft.com>
Co-authored-by: Jesse Vincent <jesse@primeradiant.com>
Co-authored-by: voidborne-d <voidborne-d@users.noreply.github.com>
Co-authored-by: Richard Luo <luo.richard@gmail.com>
Co-authored-by: Drew Ritter <drew@ritter.dev>
Co-authored-by: leonsong09 <59187950+leonsong09@users.noreply.github.com>
Co-authored-by: YuXiang Hong <41331696+starumiQAQ@users.noreply.github.com>
Co-authored-by: Sathvik Gilakamsetty <spacetime1007@gmail.com>
2026-05-04 15:05:01 -07:00
Jesse Vincent
e7a2d16476 Require session transcript for new-harness PRs
Most new-harness PRs ship integrations that copy skill files or wrap
with `npx skills` instead of loading the using-superpowers bootstrap at
session start. Those integrations look like they work but skills never
auto-trigger.

Add an acceptance test ("Let's make a react todo list" must auto-trigger
brainstorming in a clean session) and require the transcript in the PR.
2026-04-30 14:08:41 -07:00
Jesse Vincent
6efe32c9e2 Use committed Codex plugin files in sync script
- commit .codex-plugin/plugin.json and brand assets in this repo
- sync tracked Codex plugin files instead of generating or seeding them
- honor upstream gitignored files during rsync
- cover the new sync behavior with regression tests
2026-04-23 19:02:37 -07:00
Jesse Vincent
b55764852a formatting 2026-04-16 12:50:46 -07:00
Jesse Vincent
9f42444ab1 formatting 2026-04-16 12:50:46 -07:00
Jesse Vincent
99e4c656bf reorder installs 2026-04-16 12:50:46 -07:00
Jesse Vincent
a5dd364e42 README updates for Codex, other cleanup 2026-04-16 12:50:46 -07:00
Jesse Vincent
c4bbe651cb Some terminology cleanups 2026-04-15 12:41:40 -07:00
Drew Ritter
34c17aefb2 sync-to-codex-plugin: seed interface.defaultPrompt (#1180)
Codex plugin pages use interface.defaultPrompt to show suggested
prompts on the plugin's app card; the generator now emits two
domain-neutral seed prompts so the superpowers listing isn't empty.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 10:59:39 -07:00
Jesse Vincent
f9b088f7b3 Merge pull request #1165 from obra/mirror-codex-plugin-tooling
Mirror codex plugin tooling
2026-04-14 14:13:31 -07:00
Drew Ritter
bc25777c6a sync-to-codex-plugin: anchor EXCLUDES patterns to source root
Rsync exclude patterns without a leading "/" match any directory of
the given name at any depth. The previous "scripts/" pattern was
meant to exclude upstream's top-level scripts/ dir (which contains
sync-to-codex-plugin.sh itself, bump-version.sh, etc.) but also
incorrectly excluded skills/brainstorming/scripts/ — a legitimate
skill-adjacent dir with 5 files (frame-template.html, helper.js,
server.cjs, start-server.sh, stop-server.sh).

Found during a determinism check: comparing the hand-crafted
add-superpowers-plugin bootstrap PR against an automated bootstrap
PR produced a diff showing those 5 files were missing from the
automated version.

Fix: anchor every top-level-only exclude with a leading "/".
.DS_Store stays unanchored because Finder creates them anywhere.

This also prevents future drift if anyone adds a tests/, hooks/,
docs/, lib/, etc. subdir inside a skill.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 14:03:56 -07:00
Drew Ritter
bcdd7fa24c sync-to-codex-plugin: exclude assets/, add --bootstrap flag
Two coupled changes:

1. Add assets/ to EXCLUDES. A normal sync run was deleting
   plugins/superpowers/assets/ via --delete because the corresponding
   directory doesn't exist upstream. Confirmed via dry-run that the
   previous version would wipe both brand asset files on next sync.

2. Add --bootstrap and --assets-src flags to support creating the
   initial plugin PR from scratch. Bootstrap mode skips the
   "plugin must exist on base" preflight, creates the plugin
   directory, rsyncs upstream content, then copies
   PrimeRadiant_Favicon.{svg,png} from --assets-src into
   plugins/superpowers/assets/ as superpowers-small.svg and
   app-icon.png. Run once by one team member to open the initial
   PR; every subsequent run is a normal (non-bootstrap) sync.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:59:26 -07:00
Drew Ritter
6149f3635a sync-to-codex-plugin: align plugin.json heredoc with current live shape
The live .codex-plugin/plugin.json in the downstream fork was cleaned up
(websiteURL, privacyPolicyURL, termsOfServiceURL, and defaultPrompt
removed) and icon fields were added (composerIcon, logo pointing at
assets/superpowers-small.svg and assets/app-icon.png). Update the
heredoc to produce the same shape so future sync runs don't wipe the
icon fields or reintroduce the removed URL fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:48:05 -07:00
Drew Ritter
777a9770d8 sync-to-codex-plugin: mirror CODE_OF_CONDUCT.md, drop agents/openai.yaml overlay
- Remove CODE_OF_CONDUCT.md from EXCLUDES so it syncs from upstream
  (per PR #1165 review feedback on the exclude list)
- Remove the agents/openai.yaml overlay generator and its exclude entry
  — the file duplicates fields already in .codex-plugin/plugin.json and
  only 6 of 28 upstream plugins ship one, so we match the 22-plugin
  majority shape

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:27:59 -07:00
Drew Ritter
da283df058 remove things we dont need 2026-04-14 13:23:17 -07:00
Jesse Vincent
a569527b89 Merge pull request #1163 from shaanmajid/chore/remove-stray-changelog
chore: remove vestigial CHANGELOG.md
2026-04-14 13:22:24 -07:00
Drew Ritter
ac1c715ffb rewrites sync tool to clone the fork, open a PR, and regenerate overlays inline
The previous version was a local rsync helper that required a hand-maintained
destination path. This rewrite makes it path/user-agnostic and gives every team
member the same flow:

- Clones prime-radiant-inc/openai-codex-plugins fresh into a temp dir per run
  (trap EXIT cleans up)
- Auto-detects upstream from the script's own location
- Preflight: rsync, git, gh auth, python3, upstream package.json
- Reads upstream version from package.json and bakes it into the regenerated
  .codex-plugin/plugin.json, so version bumps flow through
- Regenerates both overlay files (.codex-plugin/plugin.json and
  agents/openai.yaml) inline via heredoc — single source of truth
- Pushes a sync/superpowers-<sha>-<UTC-timestamp> branch and opens a PR via
  gh pr create; prints PR URL and /files diff URL on completion
- --dry-run, --yes, --base BRANCH, --local PATH flags for all the usual modes
- Deterministic: two runs against the same upstream SHA produce PRs with
  identical diffs, so the tool itself can be sanity-checked by running twice

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 13:18:36 -07:00
Drew Ritter
8c8c5e87ce adds tooling to mirror superpowers as a codex plugin with the appropriate metadata changes 2026-04-14 12:03:59 -07:00
Shaan Majid
a5d36b1300 chore: remove vestigial CHANGELOG.md 2026-04-14 12:36:07 -05:00
Jesse Vincent
917e5f53b1 Fix Discord invite link 2026-04-06 15:48:58 -07:00
Jesse Vincent
a6b1a1fa0c Update Discord invite link 2026-04-06 15:46:52 -07:00
Jesse Vincent
b7a8f76985 Merge pull request #1029 from obra/readme-release-announcements
Add release announcements link, consolidate Community section
2026-04-01 19:34:36 -07:00
Jesse Vincent
4b1b20f69f Add detailed Discord description to Community section 2026-04-01 19:34:30 -07:00
Jesse Vincent
eeaf2ad15b Add release announcements link, consolidate Community section
Collapse duplicate Support section into Community. Add link to
release announcements signup at primeradiant.com/superpowers/.
2026-04-01 19:09:22 -07:00
Jesse Vincent
dd237283db Add agent-facing guardrails to contributor guidelines
Speak directly to AI agents at the top of CLAUDE.md: reframe slop
PRs as harmful to their human partner, give a concrete pre-submission
checklist, and explicitly authorize pushing back on vague instructions.
2026-03-31 14:37:13 -07:00
Jesse Vincent
c0b417e409 Add contributor guidelines to reduce agentic slop PRs
CLAUDE.md (symlinked to AGENTS.md) covers every major rejection
pattern from auditing the last 100 closed PRs (94% rejection rate):
AI slop, ignored PR template, duplicates, speculative fixes, domain-
specific skills, fork confusion, fabricated content, bundled changes,
and misunderstanding project philosophy.
2026-03-31 14:14:19 -07:00
Jesse Vincent
1f20bef3f5 Release v5.0.7: Copilot CLI support, OpenCode fixes 2026-03-31 12:23:25 -07:00
Jesse Vincent
f0df5eca30 docs: update release notes with OpenCode bootstrap change 2026-03-31 11:51:22 -07:00
Jesse Vincent
0a1124ba53 fix(opencode): inject bootstrap as user message instead of system message
Move bootstrap injection from experimental.chat.system.transform to
experimental.chat.messages.transform, prepending to the first user
message instead of adding a system message.

This avoids two issues:
- System messages repeated every turn inflate token usage (#750)
- Multiple system messages break Qwen and other models (#894)

Tested on OpenCode 1.3.2 with Claude Sonnet 4.5 — brainstorming skill
fires correctly on "Let's make a React to do list" prompt.
2026-03-31 11:51:22 -07:00
Jesse Vincent
65d760f9c2 docs: add OpenCode path fix to release notes 2026-03-31 11:51:22 -07:00
Jesse Vincent
2d942f3b01 fix(opencode): align skills path across bootstrap, runtime, and tests
The bootstrap text advertised a configDir-based skills path that didn't
match the runtime path (resolved relative to the plugin file). Tests
used yet another hardcoded path and referenced a nonexistent lib/ dir.

- Remove misleading skills path from bootstrap text; the agent should
  use the native skill tool, not read files by path
- Fix test setup to create a consistent layout matching the plugin's
  ../../skills resolution
- Export SUPERPOWERS_SKILLS_DIR from setup.sh so tests use a single
  source of truth
- Add regression test that bootstrap doesn't advertise the old path
- Remove broken cp of nonexistent lib/ directory

Fixes #847
2026-03-31 11:51:22 -07:00
Jesse Vincent
8b1669269c feat: add Copilot CLI tool mapping, docs, and install instructions
- Add references/copilot-tools.md with full tool equivalence table
- Add Copilot CLI to using-superpowers skill platform instructions
- Add marketplace install instructions to README
- Add changelog entry crediting @culinablaz for the hook fix
2026-03-31 11:51:22 -07:00
Blaž Čulina
a2964d7a20 fix: add Copilot CLI platform detection for sessionStart context injection
Copilot CLI v1.0.11 reads `additionalContext` from sessionStart hook
output, but the session-start script only emits the Claude Code-specific
nested format. Add COPILOT_CLI env var detection so Copilot CLI gets the
SDK-standard top-level `additionalContext` while Claude Code continues
getting `hookSpecificOutput`.

Based on PR #910 by @culinablaz.
2026-03-31 11:51:22 -07:00
Jesse Vincent
eafe962b18 Release v5.0.6: inline self-review, brainstorm server restructure, owner-PID fixes 2026-03-25 11:08:09 -07:00
Jesse Vincent
9f04f06351 Fix owner-PID lifecycle monitoring for cross-platform reliability
Two bugs caused the brainstorm server to self-terminate within 60s:

1. ownerAlive() treated EPERM (permission denied) as "process dead".
   When the owner PID belongs to a different user (Tailscale SSH,
   system daemons), process.kill(pid, 0) throws EPERM — but the
   process IS alive. Fixed: return e.code === 'EPERM'.

2. On WSL, the grandparent PID resolves to a short-lived subprocess
   that exits before the first 60s lifecycle check. The PID is
   genuinely dead (ESRCH), so the EPERM fix alone doesn't help.
   Fixed: validate the owner PID at server startup — if it's already
   dead, it was a bad resolution, so disable monitoring and rely on
   the 30-minute idle timeout.

This also removes the Windows/MSYS2-specific OWNER_PID="" carve-out
from start-server.sh, since the server now handles invalid PIDs
generically at startup regardless of platform.

Tested on Linux (magic-kingdom) via Tailscale SSH:
- Root-owned owner PID (EPERM): server survives ✓
- Dead owner PID at startup (WSL sim): monitoring disabled, survives ✓
- Valid owner that dies: server shuts down within 60s ✓

Fixes #879
2026-03-25 11:03:53 -07:00
Jesse Vincent
f076bd3431 Fix owner-PID false positive when owner runs as different user
ownerAlive() treated EPERM (permission denied) the same as ESRCH
(process not found), causing the server to self-terminate within 60s
whenever the owner process ran as a different user. This affected WSL
(owner is a Windows process), Tailscale SSH, and any cross-user
scenario.

The fix: `return e.code === 'EPERM'` — if we get permission denied,
the process is alive; we just can't signal it.

Tested on Linux via Tailscale SSH with a root-owned grandparent PID:
- Server survives past the 60s lifecycle check (EPERM = alive)
- Server still shuts down when owner genuinely dies (ESRCH = dead)

Fixes #879
2026-03-25 11:03:53 -07:00
Jesse Vincent
9e3ed213a0 Separate brainstorm server content and state into peer directories
The session directory now contains two peers: content/ (HTML served to
the browser) and state/ (events, server-info, pid, log). Previously
all files shared a single directory, making server state and user
interaction data accessible over the /files/ HTTP route.

Also fixes stale test assertion ("Waiting for Claude" → "Waiting for
the agent").

Reported-By: 吉田仁
2026-03-25 11:03:53 -07:00
Jesse Vincent
9e6e077d33 Revert "Move brainstorm server metadata to .meta/ subdirectory"
This reverts commit ab500dade6.
2026-03-25 11:03:53 -07:00
Jesse Vincent
151cfb16a0 Move brainstorm server metadata to .meta/ subdirectory
Metadata files (.server-info, .events, .server.pid, .server.log,
.server-stopped) were stored in the same directory served over HTTP,
making them accessible via the /files/ route. They now live in a .meta/
subdirectory that is not web-accessible.

Also fixes a stale test assertion ("Waiting for Claude" → "Waiting for
the agent").

Reported-By: 吉田仁
2026-03-25 11:03:53 -07:00
Jesse Vincent
a1155f623f Add v5.0.6 release notes 2026-03-25 11:03:53 -07:00
Jesse Vincent
3f80f1c769 Reapply "Replace subagent review loops with lightweight inline self-review"
This reverts commit b045fa3950.
2026-03-25 11:03:53 -07:00
Jesse Vincent
4ae1a3d6a6 Revert "Replace subagent review loops with lightweight inline self-review"
This reverts commit bf8f7572eb.
2026-03-25 11:03:53 -07:00
Jesse Vincent
e6221a48c5 Replace subagent review loops with lightweight inline self-review
The subagent review loop (dispatching a fresh agent to review plans/specs)
doubled execution time (~25 min overhead) without measurably improving plan
quality. Regression testing across 5 versions (v3.6.0 through v5.0.4) with
5 trials each showed identical plan sizes, task counts, and quality scores
regardless of whether the review loop ran.

Changes:
- writing-plans: Replace subagent Plan Review Loop with inline Self-Review
  checklist (spec coverage, placeholder scan, type consistency)
- writing-plans: Add explicit "No Placeholders" section listing plan failures
  (TBD, vague descriptions, undefined references, "similar to Task N")
- brainstorming: Replace subagent Spec Review Loop with inline Spec Self-Review
  (placeholder scan, internal consistency, scope check, ambiguity check)
- Both skills now use "look at it with fresh eyes" framing

Testing: 5 trials with the new skill show self-review catches 3-5 real bugs
per run (spawn positions, API mismatches, seed bugs, grid indexing) in ~30s
instead of ~25 min. Remaining defects are comparable to the subagent approach.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Drew Ritter
4fd9aa2dd5 fix(writing-skills): correct false 'only two fields' frontmatter claim (#882) 2026-03-25 11:03:53 -07:00
Drew Ritter
2b1bfe5db6 docs(codex-tools): add named agent dispatch mapping for Codex (#647) 2026-03-25 11:03:53 -07:00
Drew Ritter
bd080e3cc8 docs: add implementation plan for Codex App compatibility (PRI-823)
8 tasks covering: environment detection in using-git-worktrees,
Step 1.5 + cleanup guard in finishing-a-development-branch,
Integration line updates, codex-tools.md docs, automated tests,
and final verification.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Drew Ritter
eb2b44b23f docs: add cleanup guard test (#5) and sandbox fallback test (#10) to spec
Both tests address real risk scenarios:
- #5: cleanup guard bug would delete Codex App's own worktree (data loss)
- #10: Local thread sandbox fallback needs manual Codex App validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Drew Ritter
80c0a45fcc docs: clarify executing-plans in What Does NOT Change section
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Drew Ritter
c28b28ffbd docs: address team review feedback for PRI-823 spec
- Add commit SHA + data loss warning to handoff payload (HIGH)
- Add explicit commit step before handoff (HIGH)
- Remove misleading "mark as externally managed" from Path B
- Add executing-plans 1-line edit (was missing)
- Add branch name derivation rules
- Add conditional UI language for non-App environments
- Add sandbox fallback for permission errors
- Add STOP directive after Step 0 reporting

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Drew Ritter
33e9bea3cc docs: address spec review feedback for PRI-823
Fix three Important issues from spec review:
- Clarify Step 1.5 placement relative to existing Steps 2/3
- Re-derive environment state at cleanup time instead of relying on
  earlier skill output
- Acknowledge pre-existing Step 5 cleanup inconsistency

Also: precise step references, exact codex-tools.md content, clearer
Integration section update instructions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Drew Ritter
74a0c004eb docs: add Codex App compatibility design spec (PRI-823)
Design for making using-git-worktrees, finishing-a-development-branch,
and subagent-driven-development skills work in the Codex App's sandboxed
worktree environment. Read-only environment detection via git-dir vs
git-common-dir comparison, ~48 lines across 4 files, zero breaking changes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:03:53 -07:00
Jesse Vincent
8ea39819ee Add issue templates and disable blank issues
Four templates: bug report (with environment table and platform-vs-plugin
gate), feature request (with problem statement and core-appropriateness
question), IDE/platform support request, and a config that disables
blank issues and redirects questions to Discord.
2026-03-19 13:26:17 -07:00
Jesse Vincent
764215331d Add PR template to filter low-quality submissions
Requires contributors to articulate the problem they're solving,
confirm human review, document eval methodology, and check for
duplicate PRs. Informed by patterns in ~90 closed-without-merge PRs.
2026-03-19 13:04:32 -07:00
Jesse Vincent
eccd45305a Add Contributor Covenant Code of Conduct
Added Contributor Covenant Code of Conduct to outline community standards and enforcement guidelines.
2026-03-19 12:11:50 -07:00
Jesse Vincent
fb4adab518 Bump cursor plugin version to match release 2026-03-19 12:04:18 -07:00
Jesse Vincent
7e516434f2 Merge branch 'dev' for v5.0.5 release 2026-03-17 15:02:02 -07:00
Jesse Vincent
3cee13e516 Add Community section with Discord link and Prime Radiant attribution 2026-03-16 20:10:15 -07:00
116 changed files with 7325 additions and 2703 deletions

View File

@@ -9,7 +9,7 @@
{ {
"name": "superpowers", "name": "superpowers",
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
"version": "5.0.5", "version": "5.1.0",
"source": "./", "source": "./",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",

View File

@@ -1,7 +1,7 @@
{ {
"name": "superpowers", "name": "superpowers",
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
"version": "5.0.5", "version": "5.1.0",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",
"email": "jesse@fsck.com" "email": "jesse@fsck.com"
@@ -9,5 +9,12 @@
"homepage": "https://github.com/obra/superpowers", "homepage": "https://github.com/obra/superpowers",
"repository": "https://github.com/obra/superpowers", "repository": "https://github.com/obra/superpowers",
"license": "MIT", "license": "MIT",
"keywords": ["skills", "tdd", "debugging", "collaboration", "best-practices", "workflows"] "keywords": [
"skills",
"tdd",
"debugging",
"collaboration",
"best-practices",
"workflows"
]
} }

47
.codex-plugin/plugin.json Normal file
View File

@@ -0,0 +1,47 @@
{
"name": "superpowers",
"version": "5.1.0",
"description": "An agentic skills framework & software development methodology that works: planning, TDD, debugging, and collaboration workflows.",
"author": {
"name": "Jesse Vincent",
"email": "jesse@fsck.com",
"url": "https://github.com/obra"
},
"homepage": "https://github.com/obra/superpowers",
"repository": "https://github.com/obra/superpowers",
"license": "MIT",
"keywords": [
"brainstorming",
"subagent-driven-development",
"skills",
"planning",
"tdd",
"debugging",
"code-review",
"workflow"
],
"skills": "./skills/",
"interface": {
"displayName": "Superpowers",
"shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents",
"longDescription": "Use Superpowers to guide agent work through brainstorming, implementation planning, test-driven development, systematic debugging, parallel execution, code review, and finish-the-branch workflows.",
"developerName": "Jesse Vincent",
"category": "Coding",
"capabilities": [
"Interactive",
"Read",
"Write"
],
"defaultPrompt": [
"I've got an idea for something I'd like to build.",
"Let's add a feature to this project."
],
"websiteURL": "https://github.com/obra/superpowers",
"privacyPolicyURL": "https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement",
"termsOfServiceURL": "https://docs.github.com/en/site-policy/github-terms/github-terms-of-service",
"brandColor": "#F59E0B",
"composerIcon": "./assets/superpowers-small.svg",
"logo": "./assets/app-icon.png",
"screenshots": []
}
}

View File

@@ -1,67 +0,0 @@
# Installing Superpowers for Codex
Enable superpowers skills in Codex via native skill discovery. Just clone and symlink.
## Prerequisites
- Git
## Installation
1. **Clone the superpowers repository:**
```bash
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
```
2. **Create the skills symlink:**
```bash
mkdir -p ~/.agents/skills
ln -s ~/.codex/superpowers/skills ~/.agents/skills/superpowers
```
**Windows (PowerShell):**
```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills"
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\superpowers" "$env:USERPROFILE\.codex\superpowers\skills"
```
3. **Restart Codex** (quit and relaunch the CLI) to discover the skills.
## Migrating from old bootstrap
If you installed superpowers before native skill discovery, you need to:
1. **Update the repo:**
```bash
cd ~/.codex/superpowers && git pull
```
2. **Create the skills symlink** (step 2 above) — this is the new discovery mechanism.
3. **Remove the old bootstrap block** from `~/.codex/AGENTS.md` — any block referencing `superpowers-codex bootstrap` is no longer needed.
4. **Restart Codex.**
## Verify
```bash
ls -la ~/.agents/skills/superpowers
```
You should see a symlink (or junction on Windows) pointing to your superpowers skills directory.
## Updating
```bash
cd ~/.codex/superpowers && git pull
```
Skills update instantly through the symlink.
## Uninstalling
```bash
rm ~/.agents/skills/superpowers
```
Optionally delete the clone: `rm -rf ~/.codex/superpowers`.

View File

@@ -2,7 +2,7 @@
"name": "superpowers", "name": "superpowers",
"displayName": "Superpowers", "displayName": "Superpowers",
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
"version": "5.0.2", "version": "5.1.0",
"author": { "author": {
"name": "Jesse Vincent", "name": "Jesse Vincent",
"email": "jesse@fsck.com" "email": "jesse@fsck.com"
@@ -10,9 +10,14 @@
"homepage": "https://github.com/obra/superpowers", "homepage": "https://github.com/obra/superpowers",
"repository": "https://github.com/obra/superpowers", "repository": "https://github.com/obra/superpowers",
"license": "MIT", "license": "MIT",
"keywords": ["skills", "tdd", "debugging", "collaboration", "best-practices", "workflows"], "keywords": [
"skills",
"tdd",
"debugging",
"collaboration",
"best-practices",
"workflows"
],
"skills": "./skills/", "skills": "./skills/",
"agents": "./agents/",
"commands": "./commands/",
"hooks": "./hooks/hooks-cursor.json" "hooks": "./hooks/hooks-cursor.json"
} }

52
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,52 @@
---
name: Bug Report
about: Something isn't working as expected
labels: bug
---
<!--
BEFORE FILING: Search open AND closed issues. The Windows SessionStart
hook alone has been reported 29 times. If your issue already exists,
add a comment or reaction to the existing one instead.
-->
- [ ] I searched existing issues and this is not a duplicate
## Environment
| Field | Value |
|-------|-------|
| Superpowers version | |
| Harness (Claude Code, Cursor, etc.) | |
| Harness version | |
| Model | |
| OS + shell | |
## Is this a Superpowers issue or a platform issue?
<!-- Superpowers is a plugin. Some reported "bugs" are actually issues
in the underlying platform or model. If you're not sure, try
reproducing without Superpowers installed.
If the problem persists without Superpowers, file the issue with
your platform instead. -->
- [ ] I confirmed this issue does not occur without Superpowers installed
## What happened?
<!-- Be specific. "It doesn't work" is not a bug report. -->
## Steps to reproduce
1.
2.
3.
## Expected behavior
<!-- What should have happened? -->
## Actual behavior
<!-- What happened instead? -->
## Debug log or conversation transcript
<!-- A debug log or conversation transcript showing the issue is the
single most helpful thing you can include. Without one, we're
guessing. Screenshots of error output are also useful. -->

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Questions & Help
url: https://discord.gg/35wsABTejz
about: For usage questions, troubleshooting help, and general discussion, please visit our Discord instead of opening an issue.

View File

@@ -0,0 +1,34 @@
---
name: Feature Request
about: Propose a change or addition to Superpowers
labels: enhancement
---
<!--
BEFORE FILING: Search open AND closed issues. Many features have been
requested before — some were implemented differently, some are in
progress, and some were intentionally declined.
-->
- [ ] I searched existing issues and this has not been proposed before
## What problem does this solve?
<!-- Describe the problem from your own experience. What were you doing,
what went wrong or was missing, and why did it matter?
"It would be cool if..." is not a problem statement. -->
## Proposed solution
<!-- What specifically do you want to happen? Be concrete. -->
## What alternatives did you consider?
<!-- What other approaches could solve the same problem? Why is your
proposal better? -->
## Is this appropriate for core Superpowers?
<!-- Would this benefit someone working on a completely different kind
of project? If this is specific to your domain, workflow, or a
third-party tool, it may belong as its own plugin instead. -->
## Context
<!-- Optional: version info, harness, model, workflow where you hit this. -->

View File

@@ -0,0 +1,23 @@
---
name: IDE / Platform Support Request
about: Request support for a new IDE, editor, or AI coding tool
labels: platform-support
---
<!--
BEFORE FILING: Search existing issues — your IDE may already be
requested or discussed.
-->
- [ ] I searched existing issues for this IDE/platform
## Which IDE or platform?
<!-- Name and link -->
## Does this tool have a plugin or extension system?
<!-- If yes, link to the docs. If no, explain how third-party
integrations typically work with this tool. -->
## Have you tried manual installation?
<!-- Many tools work with Superpowers through manual setup even without
official support. Did you try? What happened? -->

126
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,126 @@
<!--
BEFORE SUBMITTING: Read every word of this template. PRs that leave
sections blank, contain multiple unrelated changes, or show no evidence
of human involvement will be closed without review.
-->
## What problem are you trying to solve?
<!-- Describe the specific problem you encountered. If this was a session
issue, include: what you were doing, what went wrong, the model's
exact failure mode, and ideally a transcript or session log.
"Improving" something is not a problem statement. What broke? What
failed? What was the user experience that motivated this? -->
## What does this PR change?
<!-- 1-3 sentences. What, not why — the "why" belongs above. -->
## Is this change appropriate for the core library?
<!-- Superpowers core contains general-purpose skills and infrastructure
that benefit all users. Ask yourself:
- Would this be useful to someone working on a completely different
kind of project than yours?
- Is this project-specific, team-specific, or tool-specific?
- Does this integrate or promote a third-party service?
If your change is a new skill for a specific domain, workflow tool,
or third-party integration, it belongs in its own plugin — not here.
See the plugin development docs for how to publish it separately. -->
## What alternatives did you consider?
<!-- What other approaches did you try or evaluate before landing on this
one? Why were they worse? If you didn't consider alternatives, say so
— but know that's a red flag. -->
## Does this PR contain multiple unrelated changes?
<!-- If yes: stop. Split it into separate PRs. Bundled PRs will be closed.
If you believe the changes are related, explain the dependency. -->
## Existing PRs
- [ ] I have reviewed all open AND closed PRs for duplicates or prior art
- Related PRs: <!-- #number, #number, or "none found" -->
<!-- If a related closed PR exists, explain what's different about your
approach and why it should succeed where the other didn't. -->
## Environment tested
| Harness (e.g. Claude Code, Cursor) | Harness version | Model | Model version/ID |
|-------------------------------------|-----------------|-------|------------------|
| | | | |
## New harness support (required if this PR adds a new harness)
<!-- If this PR adds support for a new harness (IDE, CLI tool, agent
runner), you MUST include a session transcript proving the
integration actually works.
A real integration loads the `using-superpowers` bootstrap at session
start. The bootstrap is what causes skills to auto-trigger. Without
it, the skills are dead weight — present on disk but never invoked
at the right moments.
ACCEPTANCE TEST: Open a clean session in the new harness and send
exactly this user message:
Let's make a react todo list
A working integration auto-triggers the `brainstorming` skill before
any code is written. Paste the complete transcript below.
These are NOT real integrations and PRs that ship them will be closed:
- Manually copying skill files into the harness
- Wrapping with `npx skills` or similar at-runtime shims
- Anything that requires the user to opt in to skills per-session
- Anything where brainstorming does not auto-trigger on the test above
If you are not sure whether your integration loads the bootstrap at
session start, it does not.
-->
<details>
<summary>Clean-session transcript for "Let's make a react todo list"</summary>
```
paste the complete transcript here
```
</details>
## Evaluation
- What was the initial prompt you (or your human partner) used to start
the session that led to this change?
- How many eval sessions did you run AFTER making the change?
- How did outcomes change compared to before the change?
<!-- "It works" is not evaluation. Describe the before/after difference
you observed across multiple sessions. -->
## Rigor
- [ ] If this is a skills change: I used `superpowers:writing-skills` and
completed adversarial pressure testing (paste results below)
- [ ] This change was tested adversarially, not just on the happy path
- [ ] I did not modify carefully-tuned content (Red Flags table,
rationalizations, "human partner" language) without extensive evals
showing the change is an improvement
<!-- If you changed wording in skills that shape agent behavior, show your
eval methodology and results. These are not prose — they are code. -->
## Human review
- [ ] A human has reviewed the COMPLETE proposed diff before submission
<!--
STOP. If the checkbox above is not checked, do not submit this PR.
PRs will be closed without review if they:
- Show no evidence of human involvement
- Contain multiple unrelated changes
- Promote or integrate third-party services or tools
- Submit project-specific or personal configuration as core changes
- Leave required sections blank or use placeholder text
- Modify behavior-shaping content without eval evidence
-->

6
.gitignore vendored
View File

@@ -5,3 +5,9 @@
node_modules/ node_modules/
inspo inspo
triage/ triage/
# Eval harness — drill ships its own gitignore at evals/.gitignore;
# these are belt-and-suspenders entries for tools that don't recurse.
evals/results/
evals/.venv/
evals/.env

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "evals"]
path = evals
url = git@github.com:prime-radiant-inc/superpowers-evals.git

View File

@@ -14,10 +14,14 @@ Add superpowers to the `plugin` array in your `opencode.json` (global or project
} }
``` ```
Restart OpenCode. That's it — the plugin auto-installs and registers all skills. Restart OpenCode. The plugin installs through OpenCode's plugin manager and
registers all skills.
Verify by asking: "Tell me about your superpowers" Verify by asking: "Tell me about your superpowers"
OpenCode uses its own plugin install. If you also use Claude Code, Codex, or
another harness, install Superpowers separately for each one.
## Migrating from the old symlink-based install ## Migrating from the old symlink-based install
If you previously installed superpowers using `git clone` and symlinks, remove the old setup: If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
@@ -41,12 +45,15 @@ Use OpenCode's native `skill` tool:
``` ```
use skill tool to list skills use skill tool to list skills
use skill tool to load superpowers/brainstorming use skill tool to load brainstorming
``` ```
## Updating ## Updating
Superpowers updates automatically when you restart OpenCode. OpenCode installs Superpowers through a git-backed package spec. Some OpenCode
and Bun versions pin that resolved git dependency in a lockfile or cache, so a
restart may not pick up the newest Superpowers commit. If updates do not appear,
clear OpenCode's package cache or reinstall the plugin.
To pin a specific version: To pin a specific version:
@@ -64,6 +71,26 @@ To pin a specific version:
2. Verify the plugin line in your `opencode.json` 2. Verify the plugin line in your `opencode.json`
3. Make sure you're running a recent version of OpenCode 3. Make sure you're running a recent version of OpenCode
### Windows install issues
Some Windows OpenCode builds have upstream installer issues with git-backed
plugin specs, including cache paths for `git+https` URLs and Bun not finding
`git.exe` even when it works in a normal terminal. If OpenCode cannot install
the plugin, try installing with system npm and pointing OpenCode at the local
package:
```powershell
npm install superpowers@git+https://github.com/obra/superpowers.git --prefix "$HOME\.config\opencode"
```
Then use the installed package path in `opencode.json`:
```json
{
"plugin": ["~/.config/opencode/node_modules/superpowers"]
}
```
### Skills not found ### Skills not found
1. Use `skill` tool to list what's discovered 1. Use `skill` tool to list what's discovered
@@ -71,11 +98,16 @@ To pin a specific version:
### Tool mapping ### Tool mapping
When skills reference Claude Code tools: Skills speak in actions ("create a todo", "dispatch a subagent", "read a file"). On OpenCode these resolve to:
- `TodoWrite``todowrite`
- `Task` with subagents → `@mention` syntax - "Create a todo" / "mark complete in todo list" → `todowrite`
- `Skill` tool → OpenCode's native `skill` tool - `Subagent (general-purpose):` template → `task` tool with `subagent_type: "general"` (or `"explore"` for codebase exploration)
- File operations → your native tools - "Invoke a skill" → OpenCode's native `skill` tool
- "Read a file" → `read`
- "Create a file" / "edit a file" / "delete a file" → `apply_patch`
- "Run a shell command" → `bash`
- "Search file contents" / "find files by name" → `grep`, `glob`
- "Fetch a URL" → `webfetch`
## Getting Help ## Getting Help

View File

@@ -1,7 +1,7 @@
/** /**
* Superpowers plugin for OpenCode.ai * Superpowers plugin for OpenCode.ai
* *
* Injects superpowers bootstrap context via system prompt transform. * Injects superpowers bootstrap context via message transform.
* Auto-registers skills directory via config hook (no symlinks needed). * Auto-registers skills directory via config hook (no symlinks needed).
*/ */
@@ -46,33 +46,47 @@ const normalizePath = (p, homeDir) => {
return path.resolve(normalized); return path.resolve(normalized);
}; };
// Module-level cache for bootstrap content.
// The SKILL.md file does not change during a session, so reading + parsing it
// once eliminates redundant fs.existsSync + fs.readFileSync + regex work on
// every agent step. See #1202 for the full analysis.
let _bootstrapCache = undefined; // undefined = not yet loaded, null = file missing
export const SuperpowersPlugin = async ({ client, directory }) => { export const SuperpowersPlugin = async ({ client, directory }) => {
const homeDir = os.homedir(); const homeDir = os.homedir();
const superpowersSkillsDir = path.resolve(__dirname, '../../skills'); const superpowersSkillsDir = path.resolve(__dirname, '../../skills');
const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir); const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir);
const configDir = envConfigDir || path.join(homeDir, '.config/opencode'); const configDir = envConfigDir || path.join(homeDir, '.config/opencode');
// Helper to generate bootstrap content // Helper to generate bootstrap content (cached after first call)
const getBootstrapContent = () => { const getBootstrapContent = () => {
// Return cached result on subsequent calls
if (_bootstrapCache !== undefined) return _bootstrapCache;
// Try to load using-superpowers skill // Try to load using-superpowers skill
const skillPath = path.join(superpowersSkillsDir, 'using-superpowers', 'SKILL.md'); const skillPath = path.join(superpowersSkillsDir, 'using-superpowers', 'SKILL.md');
if (!fs.existsSync(skillPath)) return null; if (!fs.existsSync(skillPath)) {
_bootstrapCache = null;
return null;
}
const fullContent = fs.readFileSync(skillPath, 'utf8'); const fullContent = fs.readFileSync(skillPath, 'utf8');
const { content } = extractAndStripFrontmatter(fullContent); const { content } = extractAndStripFrontmatter(fullContent);
const toolMapping = `**Tool Mapping for OpenCode:** const toolMapping = `**Tool Mapping for OpenCode:**
When skills reference tools you don't have, substitute OpenCode equivalents: When skills request actions, substitute OpenCode equivalents:
- \`TodoWrite\`\`todowrite\` - Create or update todos\`todowrite\`
- \`Task\` tool with subagents → Use OpenCode's subagent system (@mention) - \`Subagent (general-purpose):\`\`task\` with \`subagent_type: "general"\`
- \`Skill\` tool → OpenCode's native \`skill\` tool - Invoke a skill → OpenCode's native \`skill\` tool
- \`Read\`, \`Write\`, \`Edit\`, \`Bash\` → Your native tools - Read files → \`read\`
- Create, edit, or delete files → \`apply_patch\`
- Run shell commands → \`bash\`
- Search files → \`grep\`, \`glob\`
- Fetch a URL → \`webfetch\`
**Skills location:**
Superpowers skills are in \`${configDir}/skills/superpowers/\`
Use OpenCode's native \`skill\` tool to list and load skills.`; Use OpenCode's native \`skill\` tool to list and load skills.`;
return `<EXTREMELY_IMPORTANT> _bootstrapCache = `<EXTREMELY_IMPORTANT>
You have superpowers. You have superpowers.
**IMPORTANT: The using-superpowers skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the skill tool to load "using-superpowers" again - that would be redundant.** **IMPORTANT: The using-superpowers skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the skill tool to load "using-superpowers" again - that would be redundant.**
@@ -81,6 +95,8 @@ ${content}
${toolMapping} ${toolMapping}
</EXTREMELY_IMPORTANT>`; </EXTREMELY_IMPORTANT>`;
return _bootstrapCache;
}; };
return { return {
@@ -96,12 +112,28 @@ ${toolMapping}
} }
}, },
// Use system prompt transform to inject bootstrap (fixes #226 agent reset bug) // Inject bootstrap into the first user message of each session.
'experimental.chat.system.transform': async (_input, output) => { // Using a user message instead of a system message avoids:
// 1. Token bloat from system messages repeated every turn (#750)
// 2. Multiple system messages breaking Qwen and other models (#894)
//
// The hook fires on every agent step (not just every turn) because
// opencode's prompt.ts reloads messages from DB each step. Fresh message
// arrays may need injection again, so getBootstrapContent() must not do
// repeated disk work.
'experimental.chat.messages.transform': async (_input, output) => {
const bootstrap = getBootstrapContent(); const bootstrap = getBootstrapContent();
if (bootstrap) { if (!bootstrap || !output.messages.length) return;
(output.system ||= []).push(bootstrap); const firstUser = output.messages.find(m => m.info.role === 'user');
} if (!firstUser || !firstUser.parts.length) return;
// Guard: skip if first user message already contains bootstrap.
// This prevents double injection when OpenCode passes an already
// transformed in-memory message array through the hook again.
if (firstUser.parts.some(p => p.type === 'text' && p.text.includes('EXTREMELY_IMPORTANT'))) return;
const ref = firstUser.parts[0];
firstUser.parts.unshift({ ...ref, type: 'text', text: bootstrap });
} }
}; };
}; };

View File

@@ -0,0 +1,121 @@
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
const EXTREMELY_IMPORTANT_MARKER = "<EXTREMELY_IMPORTANT>";
const BOOTSTRAP_MARKER = "superpowers:using-superpowers bootstrap for pi";
const extensionDir = dirname(fileURLToPath(import.meta.url));
const packageRoot = resolve(extensionDir, "../..");
const skillsDir = resolve(packageRoot, "skills");
const bootstrapSkillPath = resolve(skillsDir, "using-superpowers", "SKILL.md");
let cachedBootstrap: string | null | undefined;
export default function superpowersPiExtension(pi: ExtensionAPI) {
let injectBootstrap = true;
pi.on("resources_discover", async () => ({
skillPaths: [skillsDir],
}));
pi.on("session_start", async () => {
injectBootstrap = true;
});
pi.on("session_compact", async () => {
injectBootstrap = true;
});
pi.on("agent_end", async () => {
injectBootstrap = false;
});
pi.on("context", async (event) => {
if (!injectBootstrap) return;
if (event.messages.some(messageContainsBootstrap)) return;
const bootstrap = getBootstrapContent();
if (!bootstrap) return;
const bootstrapMessage = {
role: "user" as const,
content: [{ type: "text" as const, text: bootstrap }],
timestamp: Date.now(),
};
const insertAt = firstNonCompactionSummaryIndex(event.messages);
return {
messages: [
...event.messages.slice(0, insertAt),
bootstrapMessage,
...event.messages.slice(insertAt),
],
};
});
}
function getBootstrapContent(): string | null {
if (cachedBootstrap !== undefined) return cachedBootstrap;
try {
const skillContent = readFileSync(bootstrapSkillPath, "utf8");
const body = stripFrontmatter(skillContent);
cachedBootstrap = `${EXTREMELY_IMPORTANT_MARKER}
${BOOTSTRAP_MARKER}
You have superpowers.
The using-superpowers skill content is included below and is already loaded for this Pi session. Follow it now. Do not try to load using-superpowers again.
${body}
${piToolMapping()}
</EXTREMELY_IMPORTANT>`;
return cachedBootstrap;
} catch {
cachedBootstrap = null;
return null;
}
}
function stripFrontmatter(content: string): string {
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
return (match ? match[1] : content).trim();
}
function piToolMapping(): string {
return `## Pi tool mapping
Pi has native skills but does not expose Claude Code's \`Skill\` tool. When a Superpowers instruction says to invoke a skill, use Pi's native skill system instead: load the relevant \`SKILL.md\` with \`read\` when the skill applies, or let a human invoke \`/skill:name\` explicitly.
Pi's built-in coding tools are lowercase: \`read\`, \`write\`, \`edit\`, \`bash\`, plus optional \`grep\`, \`find\`, and \`ls\`. Use those for the corresponding actions: read a file, create or edit files, run shell commands, search file contents, find files by name, and list directories.
Pi does not ship a standard subagent tool. If a subagent tool such as \`subagent\` from \`pi-subagents\` is available, use it for Superpowers subagent workflows. If no subagent tool is available, do the work in this session or explain the missing capability instead of inventing \`Task\` calls.
Pi does not ship a standard task-list tool. If an installed todo/task tool is available, use it. Otherwise track work in plan files or a repo-local \`TODO.md\` when task tracking is needed. Treat older \`TodoWrite\` references as this task-tracking action.`;
}
function messageContainsBootstrap(message: unknown): boolean {
const content = (message as { content?: unknown }).content;
if (typeof content === "string") return content.includes(BOOTSTRAP_MARKER);
if (!Array.isArray(content)) return false;
return content.some((part) => {
return (
part &&
typeof part === "object" &&
(part as { type?: unknown }).type === "text" &&
typeof (part as { text?: unknown }).text === "string" &&
(part as { text: string }).text.includes(BOOTSTRAP_MARKER)
);
});
}
function firstNonCompactionSummaryIndex(messages: unknown[]): number {
let index = 0;
while ((messages[index] as { role?: unknown } | undefined)?.role === "compactionSummary") {
index += 1;
}
return index;
}

21
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,21 @@
repos:
- repo: local
hooks:
- id: evals-ruff-check
name: evals ruff check
entry: uv --project evals run ruff check
language: system
files: ^evals/.*\.py$
- id: evals-ruff-format-check
name: evals ruff format --check
entry: uv --project evals run ruff format --check
language: system
files: ^evals/.*\.py$
- id: evals-ty-check
name: evals ty check
entry: uv --directory evals run ty check
language: system
pass_filenames: false
files: ^evals/.*\.py$

20
.version-bump.json Normal file
View File

@@ -0,0 +1,20 @@
{
"files": [
{ "path": "package.json", "field": "version" },
{ "path": ".claude-plugin/plugin.json", "field": "version" },
{ "path": ".cursor-plugin/plugin.json", "field": "version" },
{ "path": ".codex-plugin/plugin.json", "field": "version" },
{ "path": ".claude-plugin/marketplace.json", "field": "plugins.0.version" },
{ "path": "gemini-extension.json", "field": "version" }
],
"audit": {
"exclude": [
"CHANGELOG.md",
"RELEASE-NOTES.md",
"node_modules",
".git",
".version-bump.json",
"scripts/bump-version.sh"
]
}
}

1
AGENTS.md Symbolic link
View File

@@ -0,0 +1 @@
CLAUDE.md

View File

@@ -1,13 +0,0 @@
# Changelog
## [5.0.5] - 2026-03-17
### Fixed
- **Brainstorm server ESM fix**: Renamed `server.js``server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. ([PR #784](https://github.com/obra/superpowers/pull/784) by @sarbojitrana, fixes [#774](https://github.com/obra/superpowers/issues/774), [#780](https://github.com/obra/superpowers/issues/780), [#783](https://github.com/obra/superpowers/issues/783))
- **Brainstorm owner-PID on Windows**: Skip `BRAINSTORM_OWNER_PID` lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js. Prevents the server from self-terminating after 60 seconds. The 30-minute idle timeout remains as the safety net. ([#770](https://github.com/obra/superpowers/issues/770), docs from [PR #768](https://github.com/obra/superpowers/pull/768) by @lucasyhzhu-debug)
- **stop-server.sh reliability**: Verify the server process actually died before reporting success. Waits up to 2 seconds for graceful shutdown, escalates to `SIGKILL`, and reports failure if the process survives. ([#723](https://github.com/obra/superpowers/issues/723))
### Changed
- **Execution handoff**: Restore user choice between subagent-driven-development and executing-plans after plan writing. Subagent-driven is recommended but no longer mandatory. (Reverts `5e51c3e`)

110
CLAUDE.md Normal file
View File

@@ -0,0 +1,110 @@
# Superpowers — Contributor Guidelines
## If You Are an AI Agent
Stop. Read this section before doing anything.
This repo has a 94% PR rejection rate. Almost every rejected PR was submitted by an agent that didn't read or didn't follow these guidelines. The maintainers close slop PRs within hours, often with public comments like "This pull request is slop that's made of lies."
**Your job is to protect your human partner from that outcome.** Submitting a low-quality PR doesn't help them — it wastes the maintainers' time, burns your human partner's reputation, and the PR will be closed anyway. That is not being helpful. That is being a tool of embarrassment.
Before you open a PR against this repo, you MUST:
1. **Read the entire PR template** at `.github/PULL_REQUEST_TEMPLATE.md` and fill in every section with real, specific answers. Not summaries. Not placeholders.
2. **Search for existing PRs** — open AND closed — that address the same problem. If duplicates exist, STOP and tell your human partner. Do not open another duplicate.
3. **Verify this is a real problem.** If your human partner asked you to "fix some issues" or "contribute to this repo" without experiencing a specific problem, push back. Ask them what broke, what failed, what the user experience was.
4. **Confirm the change belongs in core.** If it's domain-specific, tool-specific, or promotes a third-party project, it belongs in a standalone plugin. Tell your human partner.
5. **Show your human partner the complete diff** and get their explicit approval before submitting.
If any of these checks fail, do not open the PR. Explain to your human partner why it would be rejected and what would need to change. They will thank you for saving them the embarrassment.
## Pull Request Requirements
**Every PR must fully complete the PR template.** No section may be left blank or filled with placeholder text. PRs that skip sections will be closed without review.
**Before opening a PR, you MUST search for existing PRs** — both open AND closed — that address the same problem or a related area. Reference what you found in the "Existing PRs" section. If a prior PR was closed, explain specifically what is different about your approach and why it should succeed where the previous attempt did not.
**PRs that show no evidence of human involvement will be closed.** A human must review the complete proposed diff before submission.
## What We Will Not Accept
### Third-party dependencies
PRs that add optional or required dependencies on third-party projects will not be accepted unless they are adding support for a new harness (e.g., a new IDE or CLI tool). Superpowers is a zero-dependency plugin by design. If your change requires an external tool or service, it belongs in its own plugin.
### "Compliance" changes to skills
Our internal skill philosophy differs from Anthropic's published guidance on writing skills. We have extensively tested and tuned our skill content for real-world agent behavior. PRs that restructure, reword, or reformat skills to "comply" with Anthropic's skills documentation will not be accepted without extensive eval evidence showing the change improves outcomes. The bar for modifying behavior-shaping content is very high.
### Project-specific or personal configuration
Skills, hooks, or configuration that only benefit a specific project, team, domain, or workflow do not belong in core. Publish these as a separate plugin.
### Bulk or spray-and-pray PRs
Do not trawl the issue tracker and open PRs for multiple issues in a single session. Each PR requires genuine understanding of the problem, investigation of prior attempts, and human review of the complete diff. PRs that are part of an obvious batch — where an agent was pointed at the issue list and told to "fix things" — will be closed. If you want to contribute, pick ONE issue, understand it deeply, and submit quality work.
### Speculative or theoretical fixes
Every PR must solve a real problem that someone actually experienced. "My review agent flagged this" or "this could theoretically cause issues" is not a problem statement. If you cannot describe the specific session, error, or user experience that motivated the change, do not submit the PR.
### Domain-specific skills
Superpowers core contains general-purpose skills that benefit all users regardless of their project. Skills for specific domains (portfolio building, prediction markets, games), specific tools, or specific workflows belong in their own standalone plugin. Ask yourself: "Would this be useful to someone working on a completely different kind of project?" If not, publish it separately.
### Fork-specific changes
If you maintain a fork with customizations, do not open PRs to sync your fork or push fork-specific changes upstream. PRs that rebrand the project, add fork-specific features, or merge fork branches will be closed.
### Fabricated content
PRs containing invented claims, fabricated problem descriptions, or hallucinated functionality will be closed immediately. This repo has a 94% PR rejection rate — the maintainers have seen every form of AI slop. They will notice.
### Bundled unrelated changes
PRs containing multiple unrelated changes will be closed. Split them into separate PRs.
## New Harness Support
If your PR adds support for a new harness (IDE, CLI tool, agent runner), you MUST include a session transcript proving the integration works end-to-end.
A real integration loads the `using-superpowers` bootstrap at session start. The bootstrap is what causes skills to auto-trigger at the right moments. Without it, the skills are dead weight — present on disk but never invoked.
**The acceptance test.** Open a clean session in the new harness and send exactly this user message:
> Let's make a react todo list
A working integration auto-triggers the `brainstorming` skill before any code is written. Paste the complete transcript in the PR.
**These are not real integrations and will be closed:**
- Manually copying skill files into the harness
- Wrapping with `npx skills` or similar at-runtime shims
- Anything that requires the user to opt in to skills per-session
- Anything where `brainstorming` does not auto-trigger on the acceptance test above
If you are not sure whether your integration loads the bootstrap at session start, it does not.
## Skill Changes Require Evaluation
Skills are not prose — they are code that shapes agent behavior. If you modify skill content:
- Use `superpowers:writing-skills` to develop and test changes
- Run adversarial pressure testing across multiple sessions
- Show before/after eval results in your PR
- Do not modify carefully-tuned content (Red Flags tables, rationalization lists, "human partner" language) without evidence the change is an improvement
## Eval harness
Skill-behavior evals live in the `evals/` submodule — after cloning, run `git submodule update --init evals`, then see `evals/README.md`. Drill (the harness) drives real tmux sessions of Claude Code / Codex / Gemini CLI and judges skill compliance with an LLM verifier. Plugin-infrastructure tests still live at `tests/`.
## Understand the Project Before Contributing
Before proposing changes to skill design, workflow philosophy, or architecture, read existing skills and understand the project's design decisions. Superpowers has its own tested philosophy about skill design, agent behavior shaping, and terminology (e.g., "your human partner" is deliberate, not interchangeable with "the user"). Changes that rewrite the project's voice or restructure its approach without understanding why it exists will be rejected.
## General
- Read `.github/PULL_REQUEST_TEMPLATE.md` before submitting
- One problem per PR
- Test on at least one harness and report results in the environment table
- Describe the problem you solved, not just what you changed

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
jesse@primeradiant.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

181
README.md
View File

@@ -1,6 +1,10 @@
# Superpowers # Superpowers
Superpowers is a complete software development workflow for your coding agents, built on top of a set of composable "skills" and some initial instructions that make sure your agent uses them. Superpowers is a complete software development methodology for your coding agents, built on top of a set of composable skills and some initial instructions that make sure your agent uses them.
## Quickstart
Give your agent Superpowers: [Claude Code](#claude-code), [Codex App](#codex-app), [Codex CLI](#codex-cli), [Cursor](#cursor), [Factory Droid](#factory-droid), [Gemini CLI](#gemini-cli), [GitHub Copilot CLI](#github-copilot-cli), [OpenCode](#opencode), [Pi](#pi).
## How it works ## How it works
@@ -10,7 +14,7 @@ Once it's teased a spec out of the conversation, it shows it to you in chunks sh
After you've signed off on the design, your agent puts together an implementation plan that's clear enough for an enthusiastic junior engineer with poor taste, no judgement, no project context, and an aversion to testing to follow. It emphasizes true red/green TDD, YAGNI (You Aren't Gonna Need It), and DRY. After you've signed off on the design, your agent puts together an implementation plan that's clear enough for an enthusiastic junior engineer with poor taste, no judgement, no project context, and an aversion to testing to follow. It emphasizes true red/green TDD, YAGNI (You Aren't Gonna Need It), and DRY.
Next up, once you say "go", it launches a *subagent-driven-development* process, having agents work through each engineering task, inspecting and reviewing their work, and continuing forward. It's not uncommon for Claude to be able to work autonomously for a couple hours at a time without deviating from the plan you put together. Next up, once you say "go", it launches a *subagent-driven-development* process, having agents work through each engineering task, inspecting and reviewing their work, and continuing forward. It's not uncommon for your agent to work autonomously for a couple hours at a time without deviating from the plan you put together.
There's a bunch more to it, but that's the core of the system. And because the skills trigger automatically, you don't need to do anything special. Your coding agent just has Superpowers. There's a bunch more to it, but that's the core of the system. And because the skills trigger automatically, you don't need to do anything special. Your coding agent just has Superpowers.
@@ -21,82 +25,147 @@ If Superpowers has helped you do stuff that makes money and you are so inclined,
Thanks! Thanks!
- Jesse \- Jesse
## Installation ## Installation
**Note:** Installation differs by platform. Claude Code or Cursor have built-in plugin marketplaces. Codex and OpenCode require manual setup. Installation differs by harness. If you use more than one, install Superpowers separately for each one.
### Claude Code Official Marketplace ### Claude Code
Superpowers is available via the [official Claude plugin marketplace](https://claude.com/plugins/superpowers) Superpowers is available via the [official Claude plugin marketplace](https://claude.com/plugins/superpowers)
Install the plugin from Claude marketplace: #### Official Marketplace
```bash - Install the plugin from Anthropic's official marketplace:
/plugin install superpowers@claude-plugins-official
```
### Claude Code (via Plugin Marketplace) ```bash
/plugin install superpowers@claude-plugins-official
```
In Claude Code, register the marketplace first: #### Superpowers Marketplace
```bash The Superpowers marketplace provides Superpowers and some other related plugins for Claude Code.
/plugin marketplace add obra/superpowers-marketplace
```
Then install the plugin from this marketplace: - Register the marketplace:
```bash ```bash
/plugin install superpowers@superpowers-marketplace /plugin marketplace add obra/superpowers-marketplace
``` ```
### Cursor (via Plugin Marketplace) - Install the plugin from this marketplace:
In Cursor Agent chat, install from marketplace: ```bash
/plugin install superpowers@superpowers-marketplace
```
```text ### Codex App
/add-plugin superpowers
```
or search for "superpowers" in the plugin marketplace. Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins).
### Codex - In the Codex app, click on Plugins in the sidebar.
- You should see `Superpowers` in the Coding section.
- Click the `+` next to Superpowers and follow the prompts.
Tell Codex: ### Codex CLI
``` Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins).
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.codex/INSTALL.md
```
**Detailed docs:** [docs/README.codex.md](docs/README.codex.md) - Open the plugin search interface:
### OpenCode ```bash
/plugins
```
Tell OpenCode: - Search for Superpowers:
``` ```bash
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md superpowers
``` ```
**Detailed docs:** [docs/README.opencode.md](docs/README.opencode.md) - Select `Install Plugin`.
### Cursor
- In Cursor Agent chat, install from marketplace:
```text
/add-plugin superpowers
```
- Or search for "superpowers" in the plugin marketplace.
### Factory Droid
- Register the marketplace:
```bash
droid plugin marketplace add https://github.com/obra/superpowers
```
- Install the plugin:
```bash
droid plugin install superpowers@superpowers
```
### Gemini CLI ### Gemini CLI
```bash - Install the extension:
gemini extensions install https://github.com/obra/superpowers
```
To update: ```bash
gemini extensions install https://github.com/obra/superpowers
```
- Update later:
```bash
gemini extensions update superpowers
```
### GitHub Copilot CLI
- Register the marketplace:
```bash
copilot plugin marketplace add obra/superpowers-marketplace
```
- Install the plugin:
```bash
copilot plugin install superpowers@superpowers-marketplace
```
### OpenCode
OpenCode uses its own plugin install; install Superpowers separately even if you
already use it in another harness.
- Tell OpenCode:
```
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md
```
- Detailed docs: [docs/README.opencode.md](docs/README.opencode.md)
### Pi
Install Superpowers as a Pi package from this repository:
```bash ```bash
gemini extensions update superpowers pi install git:github.com/obra/superpowers
``` ```
### Verify Installation For local development, run Pi with this checkout loaded as a temporary package:
Start a new session in your chosen platform and ask for something that should trigger a skill (for example, "help me plan this feature" or "let's debug this issue"). The agent should automatically invoke the relevant superpowers skill. ```bash
pi -e /path/to/superpowers
```
The Pi package loads the Superpowers skills and a small extension that injects the `using-superpowers` bootstrap at session startup and again after compaction. Pi has native skills, so no compatibility `Skill` tool is required. Subagent and task-list tools remain optional Pi companion packages.
## The Basic Workflow ## The Basic Workflow
@@ -149,32 +218,34 @@ Start a new session in your chosen platform and ask for something that should tr
- **Complexity reduction** - Simplicity as primary goal - **Complexity reduction** - Simplicity as primary goal
- **Evidence over claims** - Verify before declaring success - **Evidence over claims** - Verify before declaring success
Read more: [Superpowers for Claude Code](https://blog.fsck.com/2025/10/09/superpowers/) Read [the original release announcement](https://blog.fsck.com/2025/10/09/superpowers/).
## Contributing ## Contributing
Skills live directly in this repository. To contribute: The general contribution process for Superpowers is below. Keep in mind that we don't generally accept contributions of new skills and that any updates to skills must work across all of the coding agents we support.
1. Fork the repository 1. Fork the repository
2. Create a branch for your skill 2. Switch to the 'dev' branch
3. Follow the `writing-skills` skill for creating and testing new skills 3. Create a branch for your work
4. Submit a PR 4. Follow the `writing-skills` skill for creating and testing new and modified skills
5. Submit a PR, being sure to fill in the pull request template.
Skill-behavior tests use the eval harness submodule at `evals/`. After cloning this repo, run `git submodule update --init evals`, then see `evals/README.md` for setup. Plugin-infrastructure tests live at `tests/` and run via the relevant `run-*.sh` or `npm test`.
See `skills/writing-skills/SKILL.md` for the complete guide. See `skills/writing-skills/SKILL.md` for the complete guide.
## Updating ## Updating
Skills update automatically when you update the plugin: Superpowers updates are somewhat coding-agent dependent, but are often automatic.
```bash
/plugin update superpowers
```
## License ## License
MIT License - see LICENSE file for details MIT License - see LICENSE file for details
## Support ## Community
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
- **Issues**: https://github.com/obra/superpowers/issues - **Issues**: https://github.com/obra/superpowers/issues
- **Marketplace**: https://github.com/obra/superpowers-marketplace - **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions

View File

@@ -1,5 +1,130 @@
# Superpowers Release Notes # Superpowers Release Notes
## v5.1.0 (2026-04-30)
### Removals
- **Legacy slash commands removed** — `/brainstorm`, `/execute-plan`, and `/write-plan` are gone. They were deprecated stubs that did nothing but tell the user to invoke the corresponding skill. Invoke `superpowers:brainstorming`, `superpowers:executing-plans`, and `superpowers:writing-plans` directly instead. (#1188)
- **`superpowers:code-reviewer` named agent removed** — the agent was the plugin's only named agent and was used by exactly two skills, while every other reviewer/implementer subagent in the repo dispatches `general-purpose` with a prompt template alongside its skill. The agent's persona and checklist have been merged into `skills/requesting-code-review/code-reviewer.md` as a self-contained Task-dispatch template. Anyone dispatching `Task (superpowers:code-reviewer)` should switch to `Task (general-purpose)` with the prompt template instead. (PR #1299)
- **Integration sections removed from skills** — these were a legacy of the time before agents had native skills systems and didn't help with steering.
### Worktree Skills Rewrite
`using-git-worktrees` and `finishing-a-development-branch` now detect when the agent is already running inside an isolated worktree and prefer the harness's native worktree controls before falling back to `git worktree`. Behavior was TDD-validated and cross-platform-checked across five harnesses. (PRI-974, PR #1121)
- **Environment detection** — both skills check `GIT_DIR != GIT_COMMON` before doing anything; if already in a linked worktree, creation is skipped entirely. A submodule guard prevents false detection.
- **Consent before creating worktrees** — `using-git-worktrees` no longer creates worktrees implicitly; the skill asks the user first. Fixes #991 (subagent-driven-development was auto-creating worktrees without consent).
- **Native tool preference (Step 1a)** — when the harness exposes its own worktree tool (e.g. Codex), the skill defers to it. The user's stated preference is respected when expressed.
- **Provenance-based cleanup** — `finishing-a-development-branch` only cleans up worktrees inside `.worktrees/` (created by superpowers); anything outside is left alone. Fixes #940 (Option 2 was incorrectly cleaning up worktrees), #999 (merge-then-remove ordering), and #238 (`cd` to repo root before `git worktree remove`).
- **Detached HEAD handling** — the finishing menu collapses to two options when there is no branch to merge from.
- **Hardcoded `/Users/jesse` paths** in skill examples replaced with generic placeholders. (#858, PR #1122)
### Contributor Guidelines for AI Agents
Two new sections at the top of `CLAUDE.md` (symlinked to `AGENTS.md`) speak directly to AI agents. An audit of the last 100 closed PRs against this repo showed a 94% rejection rate driven by AI-generated slop: agents that didn't read the PR template, opened duplicates, fabricated problem descriptions, or pushed fork- or domain-specific changes upstream.
- **Pre-submission checklist** — read the PR template, search for existing PRs, verify a real problem exists, confirm the change belongs in core, and show the human partner the complete diff before submitting.
- **What we will not accept** — third-party dependencies, "compliance" rewrites of skill content, project-specific configuration, bulk PRs, speculative fixes, domain-specific skills, fork-specific changes, fabricated content, and bundled unrelated changes.
- **New harness PRs require a session transcript** — most past new-harness integrations copied skill files or wrapped with `npx skills` instead of loading the `using-superpowers` bootstrap at session start. The acceptance test ("Let's make a react todo list" must auto-trigger `brainstorming` in a clean session) and a complete transcript are now required.
### Codex Plugin Mirror Tooling
New `sync-to-codex-plugin` script mirrors superpowers into the OpenAI Codex plugin marketplace as `prime-radiant-inc/openai-codex-plugins`. Path/user-agnostic so any team member can run it. (PR #1165)
- Clones the fork fresh into a temp directory per run, regenerates overlays inline, and opens a PR; auto-detects upstream from the script's own location and preflights `rsync`/`git`/`gh auth`/`python3`.
- `--bootstrap` flag for first-time setup; `EXCLUDES` patterns anchored to source root; `assets/` excluded.
- Mirrors `CODE_OF_CONDUCT.md`; drops the `agents/openai.yaml` overlay.
- Seeds `interface.defaultPrompt` in the mirrored `plugin.json`. (PR #1180 by @arittr)
- Codex plugin files are committed to the source repo so the sync script uses canonical versions; Codex marketplace metadata is preserved.
### OpenCode
- **Bootstrap content cached at module level** — `getBootstrapContent()` was calling `fs.existsSync` + `fs.readFileSync` + frontmatter regex on every agent step (the `experimental.chat.messages.transform` hook fires on every step in OpenCode's agent loop). Now read once, cached for the session lifetime, with a null sentinel for the missing-file case. 15 regression tests cover cache behavior, fs call counts, the injection guard, the missing-file sentinel, and cache reset. (Fixes #1202)
- **Integration tests modernized**.
- **Install caveats clarified** in the README.
### Code Review Consolidation
`requesting-code-review` is now self-contained: the persona, checklist, and dispatch template live in `skills/requesting-code-review/code-reviewer.md` and the skill dispatches `Task (general-purpose)` directly. (PR #1299)
- **Single source of truth** — the persona/checklist that previously lived in both `agents/code-reviewer.md` and the skill's placeholder template (and drifted independently) is now one file.
- **`subagent-driven-development` follows suit** — its `code-quality-reviewer-prompt.md` now dispatches `Task (general-purpose)` instead of the named agent.
- **Behavioral test added** — `tests/claude-code/test-requesting-code-review.sh` plants real bugs (SQL injection, plaintext password handling, credential logging) into a tiny project and asserts the dispatched reviewer flags every planted issue at Critical/Important severity and refuses to approve the diff.
> Note: `tests/claude-code/test-requesting-code-review.sh` and `tests/claude-code/test-document-review-system.sh` (mentioned later in this document) were lifted into drill scenarios on 2026-05-06 and removed from `tests/`. See `evals/scenarios/code-review-catches-planted-bugs.yaml` and `evals/scenarios/spec-reviewer-catches-planted-flaws.yaml`. The references above and below are preserved as dated artifacts of the work this section describes.
- **Codex and Copilot workaround docs trimmed** — the "Named agent dispatch" sections in `references/codex-tools.md` and `references/copilot-tools.md` documented how to flatten a named agent into a generic dispatch. With no named agents shipping, the workaround is unnecessary; both sections were dropped.
### Subagent-Driven Development
- **No more pause every 3 tasks** — the "review after each batch (3 tasks)" cadence in `requesting-code-review` (originally for `executing-plans`) was leaking into `subagent-driven-development`. Replaced with "each task or at natural checkpoints" plus an explicit continuous-execution directive.
- **SDD integration test now runs its assertions** — three independent bugs caused the test to silently bail before printing any verification results: an unresolved `..` segment in the working-dir path, a `set -euo pipefail` interaction with `find | sort | head -1` (SIGPIPE on the producer killed the script), and a missing `--plugin-dir` on the `claude -p` invocation that caused the test to load the installed plugin instead of the working tree. All three fixed; six verification tests now actually run against a real end-to-end SDD run.
### Cursor
- **Windows SessionStart hook** routed through `run-hook.cmd` instead of invoking the extensionless `session-start` script directly. Fixes Windows opening the file in an editor instead of running it. Also removed an accidental UTF-8 BOM from `hooks-cursor.json`.
### Gemini CLI
- **Subagent dispatch mapping** — Gemini's `Task` dispatch now maps to `@agent-name` / `@generalist`, with parallel subagent dispatch documented for independent tasks.
### Skills
- **Terminology cleanups** across skill content.
### Documentation & Install
- **Factory Droid installation instructions** added to README.
- **Quickstart install links** in README. (PR #1293 by @arittr)
- **Codex plugin install guidance** updated. (PR #1288 by @arittr)
- **Codex `wait` mapping corrected** to `wait_agent` in the tools reference.
- **Install order reorganized**; Codex install instructions cleaned up.
- **Removed vestigial `CHANGELOG.md`** in favor of `RELEASE-NOTES.md` as the single source. (PR #1163 by @shaanmajid)
- **Discord invite link** fixed; release announcements link and a detailed Discord description added to the Community section.
### Community
- @shaanmajid — vestigial `CHANGELOG.md` removal (PR #1163)
- @arittr — README quickstart install links (#1293), Codex plugin install guidance (#1288), `sync-to-codex-plugin` `interface.defaultPrompt` seed (#1180)
## v5.0.7 (2026-03-31)
### GitHub Copilot CLI Support
- **SessionStart context injection** — Copilot CLI v1.0.11 added support for `additionalContext` in sessionStart hook output. The session-start hook now detects the `COPILOT_CLI` environment variable and emits the SDK-standard `{ "additionalContext": "..." }` format, giving Copilot CLI users the full superpowers bootstrap at session start. (Original fix by @culinablaz in PR #910)
- **Tool mapping** — added `references/copilot-tools.md` with the full Claude Code to Copilot CLI tool equivalence table
- **Skill and README updates** — added Copilot CLI to the `using-superpowers` skill's platform instructions and README installation section
### OpenCode Fixes
- **Skills path consistency** — the bootstrap text no longer advertises a misleading `configDir/skills/superpowers/` path that didn't match the runtime path. The agent should use the native `skill` tool, not navigate to files by path. Tests now use consistent paths derived from a single source of truth. (#847, #916)
- **Bootstrap as user message** — moved bootstrap injection from `experimental.chat.system.transform` to `experimental.chat.messages.transform`, prepending to the first user message instead of adding a system message. Avoids token bloat from system messages repeated every turn (#750) and fixes compatibility with Qwen and other models that break on multiple system messages (#894).
## v5.0.6 (2026-03-24)
### Inline Self-Review Replaces Subagent Review Loops
The subagent review loop (dispatching a fresh agent to review plans/specs) doubled execution time (~25 min overhead) without measurably improving plan quality. Regression testing across 5 versions with 5 trials each showed identical quality scores regardless of whether the review loop ran.
- **brainstorming** — replaced Spec Review Loop (subagent dispatch + 3-iteration cap) with inline Spec Self-Review checklist: placeholder scan, internal consistency, scope check, ambiguity check
- **writing-plans** — replaced Plan Review Loop (subagent dispatch + 3-iteration cap) with inline Self-Review checklist: spec coverage, placeholder scan, type consistency
- **writing-plans** — added explicit "No Placeholders" section defining plan failures (TBD, vague descriptions, undefined references, "similar to Task N")
- Self-review catches 3-5 real bugs per run in ~30s instead of ~25 min, with comparable defect rates to the subagent approach
### Brainstorm Server
- **Session directory restructured** — the brainstorm server session directory now contains two peer subdirectories: `content/` (HTML files served to the browser) and `state/` (events, server-info, pid, log). Previously, server state and user interaction data were stored alongside served content, making them accessible over HTTP. The `screen_dir` and `state_dir` paths are both included in the server-started JSON. (Reported by 吉田仁)
### Bug Fixes
- **Owner-PID lifecycle fixes** — the brainstorm server's owner-PID monitoring had two bugs causing false shutdowns within 60 seconds: (1) EPERM from cross-user PIDs (Tailscale SSH, etc.) was treated as "process dead", and (2) on WSL the grandparent PID resolves to a short-lived subprocess that exits before the first lifecycle check. Fixed by treating EPERM as "alive" and validating the owner PID at startup — if it's already dead, monitoring is disabled and the server relies on the 30-minute idle timeout. This also removes the Windows/MSYS2-specific carve-out from `start-server.sh` since the server now handles it generically. (#879)
- **writing-skills** — corrected false claim that SKILL.md frontmatter supports "only two fields"; now says "two required fields" and links to the agentskills.io specification for all supported fields (PR #882 by @arittr)
### Codex App Compatibility
- **codex-tools** — added named agent dispatch mapping documenting how to translate Claude Code's named agent types to Codex's `spawn_agent` with worker roles (PR #647 by @arittr)
- **codex-tools** — added environment detection and Codex App finishing sections for worktree-aware skills (by @arittr)
- **Design spec** — added Codex App compatibility design spec (PRI-823) covering read-only environment detection, worktree-safe skill behavior, and sandbox fallback patterns (by @arittr)
## v5.0.5 (2026-03-17) ## v5.0.5 (2026-03-17)
### Bug Fixes ### Bug Fixes

View File

@@ -1,48 +0,0 @@
---
name: code-reviewer
description: |
Use this agent when a major project step has been completed and needs to be reviewed against the original plan and coding standards. Examples: <example>Context: The user is creating a code-review agent that should be called after a logical chunk of code is written. user: "I've finished implementing the user authentication system as outlined in step 3 of our plan" assistant: "Great work! Now let me use the code-reviewer agent to review the implementation against our plan and coding standards" <commentary>Since a major project step has been completed, use the code-reviewer agent to validate the work against the plan and identify any issues.</commentary></example> <example>Context: User has completed a significant feature implementation. user: "The API endpoints for the task management system are now complete - that covers step 2 from our architecture document" assistant: "Excellent! Let me have the code-reviewer agent examine this implementation to ensure it aligns with our plan and follows best practices" <commentary>A numbered step from the planning document has been completed, so the code-reviewer agent should review the work.</commentary></example>
model: inherit
---
You are a Senior Code Reviewer with expertise in software architecture, design patterns, and best practices. Your role is to review completed project steps against original plans and ensure code quality standards are met.
When reviewing completed work, you will:
1. **Plan Alignment Analysis**:
- Compare the implementation against the original planning document or step description
- Identify any deviations from the planned approach, architecture, or requirements
- Assess whether deviations are justified improvements or problematic departures
- Verify that all planned functionality has been implemented
2. **Code Quality Assessment**:
- Review code for adherence to established patterns and conventions
- Check for proper error handling, type safety, and defensive programming
- Evaluate code organization, naming conventions, and maintainability
- Assess test coverage and quality of test implementations
- Look for potential security vulnerabilities or performance issues
3. **Architecture and Design Review**:
- Ensure the implementation follows SOLID principles and established architectural patterns
- Check for proper separation of concerns and loose coupling
- Verify that the code integrates well with existing systems
- Assess scalability and extensibility considerations
4. **Documentation and Standards**:
- Verify that code includes appropriate comments and documentation
- Check that file headers, function documentation, and inline comments are present and accurate
- Ensure adherence to project-specific coding standards and conventions
5. **Issue Identification and Recommendations**:
- Clearly categorize issues as: Critical (must fix), Important (should fix), or Suggestions (nice to have)
- For each issue, provide specific examples and actionable recommendations
- When you identify plan deviations, explain whether they're problematic or beneficial
- Suggest specific improvements with code examples when helpful
6. **Communication Protocol**:
- If you find significant deviations from the plan, ask the coding agent to review and confirm the changes
- If you identify issues with the original plan itself, recommend plan updates
- For implementation problems, provide clear guidance on fixes needed
- Always acknowledge what was done well before highlighting issues
Your output should be structured, actionable, and focused on helping maintain high code quality while ensuring project goals are met. Be thorough but concise, and always provide constructive feedback that helps improve both the current implementation and future development practices.

BIN
assets/app-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="Calque_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M394.28,207.8c.81,2.41,1.39,4.78,1.8,7.07,1.61,9.03-.93,17.78-5.99,21.74-22.6,17.7-49.85,29.35-75.34,38.6-.59.22-1.09.28-1.4.34-2.22.47-4.95,1.04-7.25,0-1.46-.66-2.25-1.74-2.66-2.3-1.56-2.1-1.59-4.31-1.56-5.13.1-2.67-.01-4.69,0-4.82.45-3.52.91-10.66,1.41-21.28.6-3.87,2.16-9.63,6.94-13.96,4.01-3.62,8.33-4.6,14.59-5.87,10.76-2.19,37.21-8.22,47.42-16.56,1.63-1.33,2.97-2.65,4.19-3.96,3.72-3.99,6.39-7.92,7.93-10.36,3.22,3.22,7.25,8.48,9.92,16.47Z"/><path d="M428.67,185.28c-2.33,11.99-8.91,22.32-15.88,30.38.27-5.5-.05-12.11-1.86-19.08-5.04-19.36-19.74-34.7-37.78-37.78-32.21-9.74-70.59,3.79-99.08,18.29-3.87,1.95-9.52-2.77-11.84-8.16-3.32-7.71-1.63-6.28,2.61-8.49,38.31-20.03,82.01-39.61,123.91-29.7,8.26,1.95,15.96,5.26,23.48,10.54,11.32,7.96,20.21,24.74,16.44,44Z"/><path d="M117.72,304.2c-.81-2.41-1.39-4.78-1.8-7.07-1.61-9.03.93-17.78,5.99-21.74,22.6-17.7,49.85-29.35,75.34-38.6.59-.22,1.09-.28,1.4-.34,2.22-.47,4.95-1.04,7.25,0,1.46.66,2.25,1.74,2.66,2.3,1.56,2.1,1.59,4.31,1.56,5.13-.1,2.67.01,4.69,0,4.82-.45,3.52-.91,10.66-1.41,21.28-.6,3.87-2.16,9.63-6.94,13.96-4.01,3.62-8.33,4.6-14.59,5.87-10.76,2.19-37.21,8.22-47.42,16.56-1.63,1.33-2.97,2.65-4.19,3.96-3.72,3.99-6.39,7.92-7.93,10.36-3.22-3.22-7.25-8.48-9.92-16.47Z"/><path d="M83.33,326.72c2.33-11.99,8.91-22.32,15.88-30.38-.27,5.5.05,12.11,1.86,19.08,5.04,19.36,19.74,34.7,37.78,37.78,32.21,9.74,70.59-3.79,99.08-18.29,3.87-1.95,9.52,2.77,11.84,8.16,3.32,7.71,1.63,6.28-2.61,8.49-38.31,20.03-82.01,39.61-123.91,29.7-8.26-1.95-15.96-5.26-23.48-10.54-11.32-7.96-20.21-24.74-16.44-44Z"/><ellipse cx="255.16" cy="258.86" rx="28.95" ry="28.76"/></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,5 +0,0 @@
---
description: "Deprecated - use the superpowers:brainstorming skill instead"
---
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers brainstorming" skill instead.

View File

@@ -1,5 +0,0 @@
---
description: "Deprecated - use the superpowers:executing-plans skill instead"
---
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers executing-plans" skill instead.

View File

@@ -1,5 +0,0 @@
---
description: "Deprecated - use the superpowers:writing-plans skill instead"
---
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers writing-plans" skill instead.

View File

@@ -1,126 +0,0 @@
# Superpowers for Codex
Guide for using Superpowers with OpenAI Codex via native skill discovery.
## Quick Install
Tell Codex:
```
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.codex/INSTALL.md
```
## Manual Installation
### Prerequisites
- OpenAI Codex CLI
- Git
### Steps
1. Clone the repo:
```bash
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
```
2. Create the skills symlink:
```bash
mkdir -p ~/.agents/skills
ln -s ~/.codex/superpowers/skills ~/.agents/skills/superpowers
```
3. Restart Codex.
4. **For subagent skills** (optional): Skills like `dispatching-parallel-agents` and `subagent-driven-development` require Codex's multi-agent feature. Add to your Codex config:
```toml
[features]
multi_agent = true
```
### Windows
Use a junction instead of a symlink (works without Developer Mode):
```powershell
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills"
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\superpowers" "$env:USERPROFILE\.codex\superpowers\skills"
```
## How It Works
Codex has native skill discovery — it scans `~/.agents/skills/` at startup, parses SKILL.md frontmatter, and loads skills on demand. Superpowers skills are made visible through a single symlink:
```
~/.agents/skills/superpowers/ → ~/.codex/superpowers/skills/
```
The `using-superpowers` skill is discovered automatically and enforces skill usage discipline — no additional configuration needed.
## Usage
Skills are discovered automatically. Codex activates them when:
- You mention a skill by name (e.g., "use brainstorming")
- The task matches a skill's description
- The `using-superpowers` skill directs Codex to use one
### Personal Skills
Create your own skills in `~/.agents/skills/`:
```bash
mkdir -p ~/.agents/skills/my-skill
```
Create `~/.agents/skills/my-skill/SKILL.md`:
```markdown
---
name: my-skill
description: Use when [condition] - [what it does]
---
# My Skill
[Your skill content here]
```
The `description` field is how Codex decides when to activate a skill automatically — write it as a clear trigger condition.
## Updating
```bash
cd ~/.codex/superpowers && git pull
```
Skills update instantly through the symlink.
## Uninstalling
```bash
rm ~/.agents/skills/superpowers
```
**Windows (PowerShell):**
```powershell
Remove-Item "$env:USERPROFILE\.agents\skills\superpowers"
```
Optionally delete the clone: `rm -rf ~/.codex/superpowers` (Windows: `Remove-Item -Recurse -Force "$env:USERPROFILE\.codex\superpowers"`).
## Troubleshooting
### Skills not showing up
1. Verify the symlink: `ls -la ~/.agents/skills/superpowers`
2. Check skills exist: `ls ~/.codex/superpowers/skills`
3. Restart Codex — skills are discovered at startup
### Windows junction issues
Junctions normally work without special permissions. If creation fails, try running PowerShell as administrator.
## Getting Help
- Report issues: https://github.com/obra/superpowers/issues
- Main documentation: https://github.com/obra/superpowers

View File

@@ -12,10 +12,14 @@ Add superpowers to the `plugin` array in your `opencode.json` (global or project
} }
``` ```
Restart OpenCode. The plugin auto-installs via Bun and registers all skills automatically. Restart OpenCode. The plugin installs through OpenCode's plugin manager and
registers all skills.
Verify by asking: "Tell me about your superpowers" Verify by asking: "Tell me about your superpowers"
OpenCode uses its own plugin install. If you also use Claude Code, Codex, or
another harness, install Superpowers separately for each one.
### Migrating from the old symlink-based install ### Migrating from the old symlink-based install
If you previously installed superpowers using `git clone` and symlinks, remove the old setup: If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
@@ -46,7 +50,7 @@ use skill tool to list skills
### Loading a Skill ### Loading a Skill
``` ```
use skill tool to load superpowers/brainstorming use skill tool to load brainstorming
``` ```
### Personal Skills ### Personal Skills
@@ -78,7 +82,10 @@ Create project-specific skills in `.opencode/skills/` within your project.
## Updating ## Updating
Superpowers updates automatically when you restart OpenCode. The plugin is re-installed from the git repository on each launch. OpenCode installs Superpowers through a git-backed package spec. Some OpenCode
and Bun versions pin that resolved git dependency in a lockfile or cache, so a
restart may not pick up the newest Superpowers commit. If updates do not appear,
clear OpenCode's package cache or reinstall the plugin.
To pin a specific version, use a branch or tag: To pin a specific version, use a branch or tag:
@@ -92,17 +99,23 @@ To pin a specific version, use a branch or tag:
The plugin does two things: The plugin does two things:
1. **Injects bootstrap context** via the `experimental.chat.system.transform` hook, adding superpowers awareness to every conversation. 1. **Injects bootstrap context** via the `experimental.chat.messages.transform` hook, adding superpowers awareness to every conversation.
2. **Registers the skills directory** via the `config` hook, so OpenCode discovers all superpowers skills without symlinks or manual config. 2. **Registers the skills directory** via the `config` hook, so OpenCode discovers all superpowers skills without symlinks or manual config.
### Tool Mapping ### Tool Mapping
Skills written for Claude Code are automatically adapted for OpenCode: Skills speak in actions rather than naming any one runtime's tools. On OpenCode these resolve to:
- `TodoWrite``todowrite` - "Create a todo" / "mark complete in todo list"`todowrite`
- `Task` with subagents → OpenCode's `@mention` system - `Subagent (general-purpose):` template → OpenCode's `task` tool with `subagent_type: "general"` (or `"explore"` for codebase exploration)
- `Skill` tool → OpenCode's native `skill` tool - "Invoke a skill" → OpenCode's native `skill` tool
- File operations → Native OpenCode tools - "Read a file" → `read`
- "Create a file" / "edit a file" / "delete a file" → `apply_patch`
- "Run a shell command" → `bash`
- "Search file contents" / "find files by name" → `grep`, `glob`
- "Fetch a URL" → `webfetch`
(Verified against the installed OpenCode CLI's tool inventory.)
## Troubleshooting ## Troubleshooting
@@ -112,6 +125,26 @@ Skills written for Claude Code are automatically adapted for OpenCode:
2. Verify the plugin line in your `opencode.json` is correct 2. Verify the plugin line in your `opencode.json` is correct
3. Make sure you're running a recent version of OpenCode 3. Make sure you're running a recent version of OpenCode
### Windows install issues
Some Windows OpenCode builds have upstream installer issues with git-backed
plugin specs, including cache paths for `git+https` URLs and Bun not finding
`git.exe` even when it works in a normal terminal. If OpenCode cannot install
the plugin, try installing with system npm and pointing OpenCode at the local
package:
```powershell
npm install superpowers@git+https://github.com/obra/superpowers.git --prefix "$HOME\.config\opencode"
```
Then use the installed package path in `opencode.json`:
```json
{
"plugin": ["~/.config/opencode/node_modules/superpowers"]
}
```
### Skills not found ### Skills not found
1. Use OpenCode's `skill` tool to list available skills 1. Use OpenCode's `skill` tool to list available skills
@@ -120,7 +153,7 @@ Skills written for Claude Code are automatically adapted for OpenCode:
### Bootstrap not appearing ### Bootstrap not appearing
1. Check OpenCode version supports `experimental.chat.system.transform` hook 1. Check OpenCode version supports `experimental.chat.messages.transform` hook
2. Restart OpenCode after config changes 2. Restart OpenCode after config changes
## Getting Help ## Getting Help

View File

@@ -555,6 +555,8 @@ Should show exactly 6 files changed (5 skill files + 1 test file). No other file
If test runner exists: If test runner exists:
```bash ```bash
# Run skill-triggering tests # Run skill-triggering tests
# Note: tests/skill-triggering/ was lifted into drill scenarios on 2026-05-06.
# See evals/scenarios/triggering-*.yaml. The reference below is a dated artifact.
./tests/skill-triggering/run-all.sh 2>/dev/null || echo "Skill triggering tests not available in this environment" ./tests/skill-triggering/run-all.sh 2>/dev/null || echo "Skill triggering tests not available in this environment"
# Run SDD integration test # Run SDD integration test

View File

@@ -0,0 +1,866 @@
# Worktree Rototill Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Make superpowers defer to native harness worktree systems when available, fall back to manual git worktrees when not, and fix three known finishing bugs.
**Architecture:** Two skill files are rewritten (`using-git-worktrees`, `finishing-a-development-branch`), three files get one-line integration updates (`executing-plans`, `subagent-driven-development`, `writing-plans`). The core change is adding detection (`GIT_DIR != GIT_COMMON`) and a native-tool-first creation path. These are markdown skill instruction files, not application code — "tests" are agent behavior tests using the testing-skills-with-subagents TDD framework.
**Tech Stack:** Markdown (skill files), bash (test scripts), Claude Code CLI (`claude -p` for headless testing)
**Spec:** `docs/superpowers/specs/2026-04-06-worktree-rototill-design.md`
---
### Task 1: GATE — TDD Validation of Step 1a (Native Tool Preference)
Step 1a is the load-bearing assumption of the entire design. If agents don't prefer native worktree tools over `git worktree add`, the spec fails. Validate this FIRST, before touching any skill files.
**Files:**
- Create: `tests/claude-code/test-worktree-native-preference.sh`
- Read: `skills/using-git-worktrees/SKILL.md` (current version, for RED baseline)
- Read: `tests/claude-code/test-helpers.sh` (for `run_claude`, `assert_contains`, etc.)
- Read: `skills/writing-skills/testing-skills-with-subagents.md` (TDD framework)
**This task is a gate.** If the GREEN phase fails after 2 REFACTOR iterations, STOP. Do not proceed to Task 2. Report back — the creation approach needs redesign.
- [ ] **Step 1: Write the RED baseline test script**
Create the test script that will run scenarios both WITHOUT and WITH the updated skill text. The RED phase runs against the current skill (which has no Step 1a).
```bash
#!/usr/bin/env bash
# Test: Does the agent prefer native worktree tools (EnterWorktree) over git worktree add?
# Framework: RED-GREEN-REFACTOR per testing-skills-with-subagents.md
#
# RED: Current skill has no native tool preference. Agent should use git worktree add.
# GREEN: Updated skill has Step 1a. Agent should use EnterWorktree on Claude Code.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/test-helpers.sh"
# Pressure scenario: realistic implementation task where agent needs isolation
SCENARIO='IMPORTANT: This is a real task. Choose and act.
You need to implement a small feature (add a "version" field to package.json).
This should be done in an isolated workspace to protect the main branch.
You have the using-git-worktrees skill available. Set up the isolated workspace now.
Do NOT actually implement the feature — just set up the workspace and report what you did.
Respond with EXACTLY what tool/command you used to create the workspace.'
echo "=== Worktree Native Preference Test ==="
echo ""
# Phase selection
PHASE="${1:-red}"
if [ "$PHASE" = "red" ]; then
echo "--- RED PHASE: Running WITHOUT Step 1a (current skill) ---"
echo "Expected: Agent uses 'git worktree add' (no native tool awareness)"
echo ""
test_dir=$(create_test_project)
cd "$test_dir"
git init && git commit --allow-empty -m "init"
mkdir -p .worktrees
output=$(run_claude "$SCENARIO" 120)
echo "Agent output:"
echo "$output"
echo ""
# RED expectation: agent uses git worktree add (current behavior)
if echo "$output" | grep -qi "EnterWorktree"; then
echo "[UNEXPECTED] Agent used EnterWorktree WITHOUT Step 1a — skill may not be needed"
echo "Investigate: is Claude Code's default behavior already correct?"
else
echo "[RED CONFIRMED] Agent did NOT use EnterWorktree"
assert_contains "$output" "git worktree" "Agent used git worktree (expected in RED)"
fi
cleanup_test_project "$test_dir"
elif [ "$PHASE" = "green" ]; then
echo "--- GREEN PHASE: Running WITH Step 1a (updated skill) ---"
echo "Expected: Agent uses EnterWorktree instead of git worktree add"
echo ""
test_dir=$(create_test_project)
cd "$test_dir"
git init && git commit --allow-empty -m "init"
output=$(run_claude "$SCENARIO" 120)
echo "Agent output:"
echo "$output"
echo ""
# GREEN expectation: agent uses EnterWorktree
assert_contains "$output" "EnterWorktree" "Agent used native EnterWorktree tool"
assert_not_contains "$output" "git worktree add" "Agent did NOT fall back to git worktree add"
cleanup_test_project "$test_dir"
elif [ "$PHASE" = "pressure" ]; then
echo "--- PRESSURE PHASE: Multiple pressures to skip native tools ---"
echo ""
PRESSURE_SCENARIO='IMPORTANT: This is a real task. Choose and act.
You need to set up an isolated workspace URGENTLY. Production is impacted and
the fix needs to go in a worktree. You know git worktree add works reliably.
The .worktrees/ directory already exists and is gitignored.
You have the using-git-worktrees skill. Set up the workspace NOW.
Speed matters. Report EXACTLY what tool/command you used.'
test_dir=$(create_test_project)
cd "$test_dir"
git init && git commit --allow-empty -m "init"
mkdir -p .worktrees
echo ".worktrees/" >> .gitignore
output=$(run_claude "$PRESSURE_SCENARIO" 120)
echo "Agent output:"
echo "$output"
echo ""
# Should STILL use EnterWorktree even under pressure
assert_contains "$output" "EnterWorktree" "Agent used native tool even under time pressure"
assert_not_contains "$output" "git worktree add" "Agent resisted falling back to git despite pressure"
cleanup_test_project "$test_dir"
fi
echo ""
echo "=== Test Complete ==="
```
- [ ] **Step 2: Run RED phase — confirm agent uses git worktree add today**
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh red`
Expected: `[RED CONFIRMED] Agent did NOT use EnterWorktree` — agent uses `git worktree add` because current skill has no native tool preference.
Document the agent's exact output and any rationalizations verbatim. This is the baseline failure the skill must fix.
- [ ] **Step 3: If RED confirmed, proceed. Write the Step 1a skill text.**
Create a temporary test version of the skill with ONLY the Step 1a addition (minimal change to isolate the variable). Add this section to the top of the skill's creation instructions, BEFORE the existing directory selection process:
```markdown
## Step 1: Create Isolated Workspace
**You have two mechanisms. Try them in this order.**
### 1a. Native Worktree Tools (preferred)
If your platform provides a worktree or workspace-isolation tool, use it. You know your own toolkit — the skill does not need to name specific tools. Native tools handle directory placement, branch creation, and cleanup automatically.
After using a native tool, skip to Step 3 (Project Setup).
### 1b. Git Worktree Fallback
If no native tool is available, create a worktree manually using git.
```
- [ ] **Step 4: Run GREEN phase — confirm agent now uses EnterWorktree**
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh green`
Expected: `[PASS] Agent used native EnterWorktree tool`
If FAIL: Document the agent's exact output and rationalizations. This is a REFACTOR signal — the Step 1a text needs revision. Try up to 2 REFACTOR iterations. If still failing after 2 iterations, STOP and report back.
- [ ] **Step 5: Run PRESSURE phase — confirm agent resists fallback under pressure**
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh pressure`
Expected: `[PASS] Agent used native tool even under time pressure`
If FAIL: Document rationalizations verbatim. Add explicit counters to Step 1a text (e.g., a Red Flag entry: "Never use git worktree add when your platform provides a native worktree tool"). Re-run.
- [ ] **Step 6: Commit test script**
```bash
git add tests/claude-code/test-worktree-native-preference.sh
git commit -m "test: add RED/GREEN validation for native worktree preference (PRI-974)
Gate test for Step 1a — validates agents prefer EnterWorktree over
git worktree add on Claude Code. Must pass before skill rewrite."
```
---
### Task 2: Rewrite `using-git-worktrees` SKILL.md
Full rewrite of the creation skill. Replaces the existing file entirely.
**Files:**
- Modify: `skills/using-git-worktrees/SKILL.md` (full rewrite, 219 lines → ~210 lines)
**Depends on:** Task 1 GREEN passing.
- [ ] **Step 1: Write the complete new SKILL.md**
Replace the entire contents of `skills/using-git-worktrees/SKILL.md` with:
```markdown
---
name: using-git-worktrees
description: Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback
---
# Using Git Worktrees
## Overview
Ensure work happens in an isolated workspace. Prefer your platform's native worktree tools. Fall back to manual git worktrees only when no native tool is available.
**Core principle:** Detect existing isolation first. Then use native tools. Then fall back to git. Never fight the harness.
**Announce at start:** "I'm using the using-git-worktrees skill to set up an isolated workspace."
## Step 0: Detect Existing Isolation
**Before creating anything, check if you are already in an isolated workspace.**
```bash
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
BRANCH=$(git branch --show-current)
```
**Submodule guard:** `GIT_DIR != GIT_COMMON` is also true inside git submodules. Before concluding "already in a worktree," verify you are not in a submodule:
```bash
# If this returns a path, you're in a submodule, not a worktree — proceed to Step 1
git rev-parse --show-superproject-working-tree 2>/dev/null
```
**If `GIT_DIR != GIT_COMMON` (and not a submodule):** You are already in a linked worktree. Skip to Step 3 (Project Setup). Do NOT create another worktree.
Report with branch state:
- On a branch: "Already in isolated workspace at `<path>` on branch `<name>`."
- Detached HEAD: "Already in isolated workspace at `<path>` (detached HEAD, externally managed). Branch creation needed at finish time."
**If `GIT_DIR == GIT_COMMON` (or in a submodule):** You are in a normal repo checkout.
Has the user already indicated their worktree preference in your instructions? If not, ask for consent before creating a worktree:
> "Would you like me to set up an isolated worktree? It protects your current branch from changes."
Honor any existing declared preference without asking. If the user declines consent, work in place and skip to Step 3.
## Step 1: Create Isolated Workspace
**You have two mechanisms. Try them in this order.**
### 1a. Native Worktree Tools (preferred)
If your platform provides a worktree or workspace-isolation tool, use it. You know your own toolkit — the skill does not need to name specific tools. Native tools handle directory placement, branch creation, and cleanup automatically.
After using a native tool, skip to Step 3 (Project Setup).
### 1b. Git Worktree Fallback
If no native tool is available, create a worktree manually using git.
#### Directory Selection
Follow this priority order:
1. **Check your instructions for a worktree directory preference.** If specified, use it without asking.
2. **Check existing project-local directories:**
```bash
ls -d .worktrees 2>/dev/null # Preferred (hidden)
ls -d worktrees 2>/dev/null # Alternative
```
If found, use that directory. If both exist, `.worktrees` wins.
3. **Default to `.worktrees/`.**
#### Safety Verification (project-local directories only)
**MUST verify directory is ignored before creating worktree:**
```bash
git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/dev/null
```
**If NOT ignored:** Add to .gitignore, commit the change, then proceed.
**Why critical:** Prevents accidentally committing worktree contents to repository.
#### Create the Worktree
```bash
# Determine path based on chosen location
path="$LOCATION/$BRANCH_NAME"
git worktree add "$path" -b "$BRANCH_NAME"
cd "$path"
```
#### Hooks Awareness
Git worktrees do not inherit the parent repo's hooks directory. After creating the worktree, symlink hooks from the main repo if they exist:
```bash
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
if [ -d "$MAIN_ROOT/.git/hooks" ]; then
ln -sf "$MAIN_ROOT/.git/hooks" "$path/.git/hooks"
fi
```
This prevents pre-commit checks, linters, and other hooks from silently stopping when work moves to a worktree.
**Sandbox fallback:** If `git worktree add` fails with a permission error (sandbox denial), treat this as a restricted environment. Skip creation, run setup and baseline tests in the current directory, report accordingly.
## Step 3: Project Setup
Auto-detect and run appropriate setup:
```bash
# Node.js
if [ -f package.json ]; then npm install; fi
# Rust
if [ -f Cargo.toml ]; then cargo build; fi
# Python
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ -f pyproject.toml ]; then poetry install; fi
# Go
if [ -f go.mod ]; then go mod download; fi
```
## Step 4: Verify Clean Baseline
Run tests to ensure workspace starts clean:
```bash
# Use project-appropriate command
npm test / cargo test / pytest / go test ./...
```
**If tests fail:** Report failures, ask whether to proceed or investigate.
**If tests pass:** Report ready.
### Report
```
Worktree ready at <full-path>
Tests passing (<N> tests, 0 failures)
Ready to implement <feature-name>
```
## Quick Reference
| Situation | Action |
|-----------|--------|
| Already in linked worktree | Skip creation (Step 0) |
| In a submodule | Treat as normal repo (Step 0 guard) |
| Native worktree tool available | Use it (Step 1a) |
| No native tool | Git worktree fallback (Step 1b) |
| `.worktrees/` exists | Use it (verify ignored) |
| `worktrees/` exists | Use it (verify ignored) |
| Both exist | Use `.worktrees/` |
| Neither exists | Check instruction file, then default `.worktrees/` |
| Directory not ignored | Add to .gitignore + commit |
| Permission error on create | Sandbox fallback, work in place |
| Tests fail during baseline | Report failures + ask |
| No package.json/Cargo.toml | Skip dependency install |
## Common Mistakes
### Fighting the harness
- **Problem:** Using `git worktree add` when the platform already provides isolation
- **Fix:** Step 0 detects existing isolation. Step 1a defers to native tools.
### Skipping detection
- **Problem:** Creating a nested worktree inside an existing one
- **Fix:** Always run Step 0 before creating anything
### Skipping ignore verification
- **Problem:** Worktree contents get tracked, pollute git status
- **Fix:** Always use `git check-ignore` before creating project-local worktree
### Assuming directory location
- **Problem:** Creates inconsistency, violates project conventions
- **Fix:** Follow priority: existing > instruction file > default
### Proceeding with failing tests
- **Problem:** Can't distinguish new bugs from pre-existing issues
- **Fix:** Report failures, get explicit permission to proceed
## Red Flags
**Never:**
- Create a worktree when Step 0 detects existing isolation
- Use git commands when a native worktree tool is available
- Create worktree without verifying it's ignored (project-local)
- Skip baseline test verification
- Proceed with failing tests without asking
**Always:**
- Run Step 0 detection first
- Prefer native tools over git fallback
- Follow directory priority: existing > instruction file > default
- Verify directory is ignored for project-local
- Auto-detect and run project setup
- Verify clean test baseline
- Symlink hooks after creating worktree via 1b
## Integration
**Called by:**
- **subagent-driven-development** - Ensures isolated workspace (creates one or verifies existing)
- **executing-plans** - Ensures isolated workspace (creates one or verifies existing)
- Any skill needing isolated workspace
**Pairs with:**
- **finishing-a-development-branch** - REQUIRED for cleanup after work complete
```
- [ ] **Step 2: Verify the file reads correctly**
Run: `wc -l skills/using-git-worktrees/SKILL.md`
Expected: Approximately 200-220 lines. Scan for any markdown formatting issues.
- [ ] **Step 3: Commit**
```bash
git add skills/using-git-worktrees/SKILL.md
git commit -m "feat: rewrite using-git-worktrees with detect-and-defer (PRI-974)
Step 0: GIT_DIR != GIT_COMMON detection (skip if already isolated)
Step 0 consent: opt-in prompt before creating worktree (#991)
Step 1a: native tool preference (short, first, declarative)
Step 1b: git worktree fallback with project-local directory policy
Submodule guard prevents false detection
Platform-neutral instruction file references (#1049)"
```
---
### Task 3: Rewrite `finishing-a-development-branch` SKILL.md
Full rewrite of the finishing skill. Adds environment detection, fixes three bugs, adds provenance-based cleanup.
**Files:**
- Modify: `skills/finishing-a-development-branch/SKILL.md` (full rewrite, 201 lines → ~220 lines)
- [ ] **Step 1: Write the complete new SKILL.md**
Replace the entire contents of `skills/finishing-a-development-branch/SKILL.md` with:
```markdown
---
name: finishing-a-development-branch
description: Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
---
# Finishing a Development Branch
## Overview
Guide completion of development work by presenting clear options and handling chosen workflow.
**Core principle:** Verify tests → Detect environment → Present options → Execute choice → Clean up.
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
## The Process
### Step 1: Verify Tests
**Before presenting options, verify tests pass:**
```bash
# Run project's test suite
npm test / cargo test / pytest / go test ./...
```
**If tests fail:**
```
Tests failing (<N> failures). Must fix before completing:
[Show failures]
Cannot proceed with merge/PR until tests pass.
```
Stop. Don't proceed to Step 2.
**If tests pass:** Continue to Step 2.
### Step 2: Detect Environment
**Determine workspace state before presenting options:**
```bash
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
```
This determines which menu to show and how cleanup works:
| State | Menu | Cleanup |
|-------|------|---------|
| `GIT_DIR == GIT_COMMON` (normal repo) | Standard 4 options | No worktree to clean up |
| `GIT_DIR != GIT_COMMON`, named branch | Standard 4 options | Provenance-based (see Step 6) |
| `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced 3 options (no merge) | No cleanup (externally managed) |
### Step 3: Determine Base Branch
```bash
# Try common base branches
git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
```
Or ask: "This branch split from main - is that correct?"
### Step 4: Present Options
**Normal repo and named-branch worktree — present exactly these 4 options:**
```
Implementation complete. What would you like to do?
1. Merge back to <base-branch> locally
2. Push and create a Pull Request
3. Keep the branch as-is (I'll handle it later)
4. Discard this work
Which option?
```
**Detached HEAD — present exactly these 3 options:**
```
Implementation complete. You're on a detached HEAD (externally managed workspace).
1. Push as new branch and create a Pull Request
2. Keep as-is (I'll handle it later)
3. Discard this work
Which option?
```
**Don't add explanation** - keep options concise.
### Step 5: Execute Choice
#### Option 1: Merge Locally
```bash
# Get main repo root for CWD safety
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
# Merge first — verify success before removing anything
git checkout <base-branch>
git pull
git merge <feature-branch>
# Verify tests on merged result
<test command>
# Only after merge succeeds: remove worktree, then delete branch
# (See Step 6 for worktree cleanup)
git branch -d <feature-branch>
```
Then: Cleanup worktree (Step 6)
#### Option 2: Push and Create PR
```bash
# Push branch
git push -u origin <feature-branch>
# Create PR
gh pr create --title "<title>" --body "$(cat <<'EOF'
## Summary
<2-3 bullets of what changed>
## Test Plan
- [ ] <verification steps>
EOF
)"
```
**Do NOT clean up worktree** — user needs it alive to iterate on PR feedback.
#### Option 3: Keep As-Is
Report: "Keeping branch <name>. Worktree preserved at <path>."
**Don't cleanup worktree.**
#### Option 4: Discard
**Confirm first:**
```
This will permanently delete:
- Branch <name>
- All commits: <commit-list>
- Worktree at <path>
Type 'discard' to confirm.
```
Wait for exact confirmation.
If confirmed:
```bash
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
```
Then: Cleanup worktree (Step 6), then force-delete branch:
```bash
git branch -D <feature-branch>
```
### Step 6: Cleanup Workspace
**Only runs for Options 1 and 4.** Options 2 and 3 always preserve the worktree.
```bash
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
WORKTREE_PATH=$(git rev-parse --show-toplevel)
```
**If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
**If worktree path is under `.worktrees/` or `worktrees/`:** Superpowers created this worktree — we own cleanup.
```bash
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
git worktree remove "$WORKTREE_PATH"
git worktree prune # Self-healing: clean up any stale registrations
```
**Otherwise:** The host environment (harness) owns this workspace. Do NOT remove it. If your platform provides a workspace-exit tool, use it. Otherwise, leave the workspace in place.
## Quick Reference
| Option | Merge | Push | Keep Worktree | Cleanup Branch |
|--------|-------|------|---------------|----------------|
| 1. Merge locally | yes | - | - | yes |
| 2. Create PR | - | yes | yes | - |
| 3. Keep as-is | - | - | yes | - |
| 4. Discard | - | - | - | yes (force) |
## Common Mistakes
**Skipping test verification**
- **Problem:** Merge broken code, create failing PR
- **Fix:** Always verify tests before offering options
**Open-ended questions**
- **Problem:** "What should I do next?" is ambiguous
- **Fix:** Present exactly 4 structured options (or 3 for detached HEAD)
**Cleaning up worktree for Option 2**
- **Problem:** Remove worktree user needs for PR iteration
- **Fix:** Only cleanup for Options 1 and 4
**Deleting branch before removing worktree**
- **Problem:** `git branch -d` fails because worktree still references the branch
- **Fix:** Merge first, remove worktree, then delete branch
**Running git worktree remove from inside the worktree**
- **Problem:** Command fails silently when CWD is inside the worktree being removed
- **Fix:** Always `cd` to main repo root before `git worktree remove`
**Cleaning up harness-owned worktrees**
- **Problem:** Removing a worktree the harness created causes phantom state
- **Fix:** Only clean up worktrees under `.worktrees/` or `worktrees/`
**No confirmation for discard**
- **Problem:** Accidentally delete work
- **Fix:** Require typed "discard" confirmation
## Red Flags
**Never:**
- Proceed with failing tests
- Merge without verifying tests on result
- Delete work without confirmation
- Force-push without explicit request
- Remove a worktree before confirming merge success
- Clean up worktrees you didn't create (provenance check)
- Run `git worktree remove` from inside the worktree
**Always:**
- Verify tests before offering options
- Detect environment before presenting menu
- Present exactly 4 options (or 3 for detached HEAD)
- Get typed confirmation for Option 4
- Clean up worktree for Options 1 & 4 only
- `cd` to main repo root before worktree removal
- Run `git worktree prune` after removal
## Integration
**Called by:**
- **subagent-driven-development** (Step 7) - After all tasks complete
- **executing-plans** (Step 5) - After all batches complete
**Pairs with:**
- **using-git-worktrees** - Cleans up worktree created by that skill
```
- [ ] **Step 2: Verify the file reads correctly**
Run: `wc -l skills/finishing-a-development-branch/SKILL.md`
Expected: Approximately 210-230 lines.
- [ ] **Step 3: Commit**
```bash
git add skills/finishing-a-development-branch/SKILL.md
git commit -m "feat: rewrite finishing-a-development-branch with detect-and-defer (PRI-974)
Step 2: environment detection (GIT_DIR != GIT_COMMON) before presenting menu
Detached HEAD: reduced 3-option menu (no merge from detached HEAD)
Provenance-based cleanup: .worktrees/ = ours, anything else = hands off
Bug #940: Option 2 no longer cleans up worktree
Bug #999: merge -> verify -> remove worktree -> delete branch
Bug #238: cd to main repo root before git worktree remove
Stale worktree pruning after removal (git worktree prune)"
```
---
### Task 4: Integration Updates
One-line changes to three files that reference `using-git-worktrees`.
**Files:**
- Modify: `skills/executing-plans/SKILL.md:68`
- Modify: `skills/subagent-driven-development/SKILL.md:268`
- Modify: `skills/writing-plans/SKILL.md:16`
- [ ] **Step 1: Update executing-plans integration line**
In `skills/executing-plans/SKILL.md`, change line 68 from:
```markdown
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
```
to:
```markdown
- **superpowers:using-git-worktrees** - Ensures isolated workspace (creates one or verifies existing)
```
- [ ] **Step 2: Update subagent-driven-development integration line**
In `skills/subagent-driven-development/SKILL.md`, change line 268 from:
```markdown
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
```
to:
```markdown
- **superpowers:using-git-worktrees** - Ensures isolated workspace (creates one or verifies existing)
```
- [ ] **Step 3: Update writing-plans context line**
In `skills/writing-plans/SKILL.md`, change line 16 from:
```markdown
**Context:** This should be run in a dedicated worktree (created by brainstorming skill).
```
to:
```markdown
**Context:** If working in an isolated worktree, it should have been created via the using-git-worktrees skill at execution time.
```
- [ ] **Step 4: Commit all three**
```bash
git add skills/executing-plans/SKILL.md skills/subagent-driven-development/SKILL.md skills/writing-plans/SKILL.md
git commit -m "fix: update worktree integration references across skills (PRI-974)
Remove REQUIRED language from executing-plans and subagent-driven-development.
Consent and detection now live inside using-git-worktrees itself.
Fix stale 'created by brainstorming' claim in writing-plans."
```
---
### Task 5: End-to-End Validation
Verify the full rewritten skills work together. Run the existing test suite plus manual verification.
**Files:**
- Read: `tests/claude-code/run-skill-tests.sh`
- Read: `skills/using-git-worktrees/SKILL.md` (verify final state)
- Read: `skills/finishing-a-development-branch/SKILL.md` (verify final state)
- [ ] **Step 1: Run existing test suite**
Run: `cd tests/claude-code && bash run-skill-tests.sh`
Expected: All existing tests pass. If any fail, investigate — the integration changes (Task 4) may have broken a content assertion.
- [ ] **Step 2: Re-run Step 1a GREEN test**
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh green`
Expected: PASS — agent still uses EnterWorktree with the final skill text (not just the minimal Step 1a addition from Task 1).
- [ ] **Step 3: Manual verification — read both rewritten skills end-to-end**
Read `skills/using-git-worktrees/SKILL.md` and `skills/finishing-a-development-branch/SKILL.md` in their entirety. Check:
1. No references to old behavior (hardcoded `CLAUDE.md`, interactive directory prompt, "REQUIRED" language)
2. Step numbering is consistent within each file
3. Quick Reference tables match the prose
4. Integration sections cross-reference correctly
5. No markdown formatting issues
- [ ] **Step 4: Verify git status is clean**
Run: `git status`
Expected: Clean working tree. All changes committed across Tasks 1-4.
- [ ] **Step 5: Final commit if any fixups needed**
If manual verification found issues, fix them and commit:
```bash
git add -A
git commit -m "fix: address review findings in worktree skill rewrite (PRI-974)"
```
If no issues found, skip this step.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,143 @@
# Pi Extension and Evals Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add first-class Pi package support for Superpowers and add Pi as a Drill eval backend.
**Architecture:** The Pi package is declared in the root `package.json` and loads existing `skills/` plus a small Pi extension. The extension injects the `using-superpowers` bootstrap into provider context as a user-role message on session startup and after compaction, with Pi-specific tool mapping. Drill gains a `pi` backend, Pi session-log normalization, and tests.
**Tech Stack:** Pi TypeScript extension API, Node built-in test runner, Drill Python eval harness, pytest.
---
### Task 1: Pi package manifest and extension tests
**Files:**
- Modify: `package.json`
- Create: `tests/pi/test-pi-extension.mjs`
- [ ] **Step 1: Write failing package/extension tests**
Create `tests/pi/test-pi-extension.mjs` with tests that import `extensions/superpowers.ts`, register fake Pi handlers, and assert:
- root `package.json` has `keywords` containing `pi-package`
- root `package.json` has `pi.skills: ["./skills"]`
- root `package.json` has `pi.extensions: ["./extensions/superpowers.ts"]`
- the extension registers `resources_discover`, `session_start`, `session_compact`, `context`, and `agent_end`
- startup `context` injects exactly one user-role bootstrap message
- `agent_end` clears startup injection
- `session_compact` re-enables injection
- the extension does not register `session_before_compact`
- [ ] **Step 2: Run tests and verify RED**
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
Expected: FAIL because `extensions/superpowers.ts` does not exist and `package.json` lacks the `pi` manifest.
- [ ] **Step 3: Implement manifest fields**
Update `package.json` with `description`, `keywords`, `pi.extensions`, and `pi.skills` while preserving existing `name`, `version`, `type`, and `main`.
- [ ] **Step 4: Implement `extensions/superpowers.ts`**
Create a zero-runtime-dependency extension that:
- locates the package root from `import.meta.url`
- reads `skills/using-superpowers/SKILL.md`
- strips YAML frontmatter
- appends Pi-specific tool mapping
- exposes `resources_discover` with the skills path
- marks bootstrap pending on `session_start` and `session_compact`
- injects a user-role bootstrap message in `context`
- inserts post-compact bootstrap after leading `compactionSummary` messages
- clears pending bootstrap on `agent_end`
- [ ] **Step 5: Run tests and verify GREEN**
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
Expected: PASS.
### Task 2: Pi tool mapping reference
**Files:**
- Create: `skills/using-superpowers/references/pi-tools.md`
- Modify: `tests/pi/test-pi-extension.mjs`
- [ ] **Step 1: Write failing test for Pi reference doc**
Add assertions that `skills/using-superpowers/references/pi-tools.md` exists and documents mappings for `Skill`, `Task`, `TodoWrite`, and built-in tool names.
- [ ] **Step 2: Run tests and verify RED**
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
Expected: FAIL because `pi-tools.md` does not exist.
- [ ] **Step 3: Add Pi reference doc**
Create `skills/using-superpowers/references/pi-tools.md` explaining Pi-native skills, optional `pi-subagents`, no canonical todo/tasklist plugin, and built-in lowercase tools.
- [ ] **Step 4: Run tests and verify GREEN**
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
Expected: PASS.
### Task 3: Drill Pi backend and session log normalization
**Files:**
- Create: `evals/backends/pi.yaml`
- Modify: `evals/drill/backend.py`
- Modify: `evals/drill/engine.py`
- Modify: `evals/drill/normalizer.py`
- Modify: `evals/tests/test_backend.py`
- Modify: `evals/tests/test_normalizer.py`
- [ ] **Step 1: Write failing backend/normalizer tests**
Add pytest coverage for:
- `load_backend("pi")` returns `family == "pi"`
- Pi backend command starts with `pi` and includes `-e ${SUPERPOWERS_ROOT}`
- `_resolve_log_dir()` for Pi points under `~/.pi/agent/sessions`
- `filter_pi_logs_by_cwd()` keeps only session files whose header `cwd` matches the scenario workdir
- `normalize_pi_logs()` extracts `toolCall` blocks from Pi assistant session entries and maps built-in lowercase tools to canonical names
- [ ] **Step 2: Run tests and verify RED**
Run: `uv run pytest evals/tests/test_backend.py evals/tests/test_normalizer.py -q`
Expected: FAIL because the Pi backend and normalizer do not exist.
- [ ] **Step 3: Add `evals/backends/pi.yaml`**
Configure the backend to run `pi -e ${SUPERPOWERS_ROOT}`, use permissive TUI readiness, `/quit` shutdown, and Pi session log location.
- [ ] **Step 4: Implement Pi family support**
Update `Backend.family`, `Engine._resolve_log_dir`, `Engine._collect_tool_calls`, and `normalizer.py` with Pi log filtering and normalizing.
- [ ] **Step 5: Run tests and verify GREEN**
Run: `uv run pytest evals/tests/test_backend.py evals/tests/test_normalizer.py -q`
Expected: PASS.
### Task 4: Documentation and full verification
**Files:**
- Modify: `README.md`
- Modify: `evals/README.md`
- [ ] **Step 1: Document Pi install and eval backend**
Add Pi to README quickstart/install list and add backend entry/usage to `evals/README.md`.
- [ ] **Step 2: Run verification**
Run:
```bash
node --experimental-strip-types --test tests/pi/test-pi-extension.mjs
uv run pytest evals/tests/test_backend.py evals/tests/test_setup.py evals/tests/test_normalizer.py -q
```
Expected: all tests pass.

View File

@@ -0,0 +1,341 @@
# Worktree Rototill: Detect-and-Defer
**Date:** 2026-04-06
**Status:** Draft
**Ticket:** PRI-974
**Subsumes:** PRI-823 (Codex App compatibility)
## Problem
Superpowers is opinionated about worktree management — specific paths (`.worktrees/<branch>`), specific commands (`git worktree add`), specific cleanup (`git worktree remove`). Meanwhile, Claude Code, Codex App, Gemini CLI, and Cursor all provide native worktree support with their own paths, lifecycle management, and cleanup.
This creates three failure modes:
1. **Duplication** — on Claude Code, the skill does what `EnterWorktree`/`ExitWorktree` already does
2. **Conflict** — on Codex App, the skill tries to create worktrees inside an already-managed worktree
3. **Phantom state** — skill-created worktrees at `.worktrees/` are invisible to the harness; harness-created worktrees at `.claude/worktrees/` are invisible to the skill
For harnesses without native support (Codex CLI, OpenCode, Copilot standalone), superpowers fills a real gap. The skill shouldn't go away — it should get out of the way when native support exists.
## Goals
1. Defer to native harness worktree systems when they exist
2. Continue providing worktree support for harnesses that lack it
3. Fix three known bugs in finishing-a-development-branch (#940, #999, #238)
4. Make worktree creation opt-in rather than mandatory (#991)
5. Replace hardcoded `CLAUDE.md` references with platform-neutral language (#1049)
## Non-Goals
- Per-worktree environment conventions (`.worktree-env.sh`, port offsetting) — Phase 4
- PreToolUse hooks for path enforcement — Phase 4
- Multi-repo worktree documentation — Phase 4
- Brainstorming checklist changes for worktrees — Phase 4
- `.superpowers-session.json` metadata tracking (interesting PR #997 idea, not needed for v1)
- Hooks symlinking into worktrees (PR #965 idea, separate concern)
## Design Principles
### Detect state, not platform
Use `GIT_DIR != GIT_COMMON` to determine "am I already in a worktree?" rather than sniffing environment variables to identify the harness. This is a stable git primitive (since git 2.5, 2015), works universally across all harnesses, and requires zero maintenance as new harnesses appear.
### Declarative intent, prescriptive fallback
The skill describes the goal ("ensure work happens in an isolated workspace") and defers to native tools when available. It prescribes specific git commands only as a fallback for harnesses without native worktree support. Step 1a comes first and names native tools explicitly (`EnterWorktree`, `WorktreeCreate`, `/worktree`, `--worktree`); Step 1b comes second with the git fallback. The original spec kept Step 1a abstract ("you know your own toolkit"), but TDD proved that agents anchor on Step 1b's concrete commands when Step 1a is too vague. Explicit tool naming and a consent-authorization bridge were required to make the preference reliable.
### Provenance-based ownership
Whoever creates the worktree owns its cleanup. If the harness created it, superpowers doesn't touch it. If superpowers created it (via git fallback), superpowers cleans it up. The heuristic: if the worktree lives under `.worktrees/` or `worktrees/`, superpowers owns it. Anything else (`.claude/worktrees/`, `~/.codex/worktrees/`, `.gemini/worktrees/`, or old user-global Superpowers paths) belongs to the harness or user and is left alone.
## Design
### 1. `using-git-worktrees` SKILL.md Rewrite
The skill gains three new steps before creation and simplifies the creation flow.
#### Step 0: Detect Existing Isolation
```bash
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
BRANCH=$(git branch --show-current)
```
Three outcomes:
| Condition | Meaning | Action |
|-----------|---------|--------|
| `GIT_DIR == GIT_COMMON` | Normal repo checkout | Proceed to Step 0.5 |
| `GIT_DIR != GIT_COMMON`, named branch | Already in a linked worktree | Skip to Step 3 (project setup). Report: "Already in isolated workspace at `<path>` on branch `<name>`." |
| `GIT_DIR != GIT_COMMON`, detached HEAD | Externally managed worktree (e.g., Codex App sandbox) | Skip to Step 3. Report: "Already in isolated workspace at `<path>` (detached HEAD, externally managed)." |
Step 0 does not care who created the worktree or which harness is running. A worktree is a worktree regardless of origin.
**Submodule guard:** `GIT_DIR != GIT_COMMON` is also true inside git submodules. Before concluding "already in a worktree," check that we're not in a submodule:
```bash
# If this returns a path, we're in a submodule, not a worktree
git rev-parse --show-superproject-working-tree 2>/dev/null
```
If in a submodule, treat as `GIT_DIR == GIT_COMMON` (proceed to Step 0.5).
#### Step 0.5: Consent
When Step 0 finds no existing isolation (`GIT_DIR == GIT_COMMON`), ask before creating:
> "Would you like me to set up an isolated worktree? This protects your current branch from changes. (y/n)"
If yes, proceed to Step 1. If no, work in place — skip to Step 3 with no worktree.
This step is skipped entirely when Step 0 detects existing isolation (no point asking about what already exists).
#### Step 1a: Native Tools (preferred)
> The user has asked for an isolated workspace (Step 0 consent). Check your available tools — do you have `EnterWorktree`, `WorktreeCreate`, a `/worktree` command, or a `--worktree` flag? If YES: the user's consent to create a worktree is your authorization to use it. Use it now and skip to Step 3.
After using a native tool, skip to Step 3 (project setup).
**Design note — TDD revision:** The original spec used a deliberately short, abstract Step 1a ("You know your own toolkit — the skill does not need to name specific tools"). TDD validation disproved this: agents anchored on Step 1b's concrete git commands and ignored the abstract guidance (2/6 pass rate). Three changes fixed it (50/50 pass rate across GREEN and PRESSURE tests):
1. **Explicit tool naming** — listing `EnterWorktree`, `WorktreeCreate`, `/worktree`, `--worktree` by name transforms the decision from interpretation ("do I have a native tool?") into factual lookup ("is `EnterWorktree` in my tool list?"). Agents on platforms without these tools simply check, find nothing, and fall through to Step 1b. No false positives observed.
2. **Consent bridge** — "the user's consent to create a worktree is your authorization to use it" directly addresses `EnterWorktree`'s tool-level guardrail ("ONLY when user explicitly asks"). Tool descriptions override skill instructions (Claude Code #29950), so the skill must frame user consent as the authorization the tool requires.
3. **Red Flag entry** — naming the specific anti-pattern ("Use `git worktree add` when you have a native worktree tool — this is the #1 mistake") in the Red Flags section.
File splitting (Step 1b in a separate skill) was tested and proven unnecessary. The anchoring problem is solved by the quality of Step 1a's text, not by physical separation of git commands. Control tests with the full 240-line skill (all git commands visible) passed 20/20.
#### Step 1b: Git Worktree Fallback
When no native tool is available, create a worktree manually.
**Directory selection** (priority order):
1. Check the project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent) for a worktree directory preference.
2. Check for existing `.worktrees/` or `worktrees/` directory — if found, use it. If both exist, `.worktrees/` wins.
3. Default to `.worktrees/`.
No interactive directory selection prompt. Old user-global Superpowers worktree paths are not detected or offered; new manual worktrees are project-local unless the user explicitly specifies another location.
**Safety verification** (project-local directories only):
```bash
git check-ignore -q .worktrees 2>/dev/null
```
If not ignored, add to `.gitignore` and commit before proceeding.
**Create:**
```bash
git worktree add "$path" -b "$BRANCH_NAME"
cd "$path"
```
**Hooks awareness:** Git worktrees do not inherit the parent repo's hooks directory. After creating a worktree via 1b, symlink the hooks directory from the main repo if one exists:
```bash
if [ -d "$MAIN_ROOT/.git/hooks" ]; then
ln -sf "$MAIN_ROOT/.git/hooks" "$path/.git/hooks"
fi
```
This prevents pre-commit checks, linters, and other hooks from silently stopping when work moves to a worktree. (Idea from PR #965.)
**Sandbox fallback:** If `git worktree add` fails with a permission error, treat as a restricted environment. Skip creation, work in current directory, proceed to Step 3.
**Step numbering note:** The current skill has Steps 1-4 as a flat list. This redesign uses 0, 0.5, 1a, 1b, 3, 4. There is no Step 2 — it was the old monolithic "Create Isolated Workspace" which is now split into the 1a/1b structure. The implementation should renumber cleanly (e.g., 0 → "Step 0: Detect", 0.5 → within Step 0's flow, 1a/1b → "Step 1", 3 → "Step 2", 4 → "Step 3") or keep the current numbering with a note. Implementer's choice.
#### Steps 3-4: Project Setup and Baseline Tests (unchanged)
Regardless of which path created the workspace (Step 0 detected existing, Step 1a native tool, Step 1b git fallback, or no worktree at all), execution converges:
- **Step 3:** Auto-detect and run project setup (`npm install`, `cargo build`, `pip install`, `go mod download`, etc.)
- **Step 4:** Run the test suite. If tests fail, report failures and ask whether to proceed.
### 2. `finishing-a-development-branch` SKILL.md Rewrite
The finishing skill gains environment detection and fixes three bugs.
#### Step 1: Verify Tests (unchanged)
Run the project's test suite. If tests fail, stop. Don't offer completion options.
#### Step 1.5: Detect Environment (new)
Re-run the same detection as Step 0 in creation:
```bash
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
```
Three paths:
| State | Menu | Cleanup |
|-------|------|---------|
| `GIT_DIR == GIT_COMMON` (normal repo) | Standard 4 options | No worktree to clean up |
| `GIT_DIR != GIT_COMMON`, named branch | Standard 4 options | Provenance-based (see Step 5) |
| `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced menu: push as new branch + PR, keep as-is, discard | No merge options (can't merge from detached HEAD) |
#### Step 2: Determine Base Branch (unchanged)
#### Step 3: Present Options
**Normal repo and named-branch worktree:**
1. Merge back to `<base-branch>` locally
2. Push and create a Pull Request
3. Keep the branch as-is (I'll handle it later)
4. Discard this work
**Detached HEAD:**
1. Push as new branch and create a Pull Request
2. Keep as-is (I'll handle it later)
3. Discard this work
#### Step 4: Execute Choice
**Option 1 (Merge locally):**
```bash
# Get main repo root for CWD safety (Bug #238 fix)
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
# Merge first, verify success before removing anything
git checkout <base-branch>
git pull
git merge <feature-branch>
<run tests>
# Only after merge succeeds: remove worktree, then delete branch (Bug #999 fix)
git worktree remove "$WORKTREE_PATH" # only if superpowers owns it
git branch -d <feature-branch>
```
The order is critical: merge → verify → remove worktree → delete branch. The old skill deleted the branch before removing the worktree (which fails because the worktree still references the branch). The naive fix of removing the worktree first is also wrong — if the merge then fails, the working directory is gone and changes are lost.
**Option 2 (Create PR):**
Push branch, create PR. Do NOT clean up worktree — user needs it for PR iteration. (Bug #940 fix: remove contradictory "Then: Cleanup worktree" prose.)
**Option 3 (Keep as-is):** No action.
**Option 4 (Discard):** Require typed "discard" confirmation. Then remove worktree (if superpowers owns it), force-delete branch.
#### Step 5: Cleanup (updated)
```
if GIT_DIR == GIT_COMMON:
# Normal repo, no worktree to clean up
done
if worktree path is under .worktrees/ or worktrees/:
# Superpowers created it — we own cleanup
cd to main repo root # Bug #238 fix
git worktree remove <path>
else:
# Harness created it — hands off
# If platform provides a workspace-exit tool, use it
# Otherwise, leave the worktree in place
```
Cleanup only runs for Options 1 and 4. Options 2 and 3 always preserve the worktree. (Bug #940 fix.)
**Stale worktree pruning:** After any `git worktree remove`, run `git worktree prune` as a self-healing step. Worktree directories can get deleted out-of-band (e.g., by harness cleanup, manual `rm`, or `.claude/` cleanup), leaving stale registrations that cause confusing errors. One line, prevents silent rot. (Idea from PR #1072.)
### 3. Integration Updates
#### `subagent-driven-development` and `executing-plans`
Both currently list `using-git-worktrees` as REQUIRED in their integration sections. Change to:
> `using-git-worktrees` — Ensures isolated workspace (creates one or verifies existing)
The skill itself now handles consent (Step 0.5) and detection (Step 0), so calling skills don't need to gate or prompt.
#### `writing-plans`
Remove the stale claim "should be run in a dedicated worktree (created by brainstorming skill)." Brainstorming is a design skill and does not create worktrees. The worktree prompt happens at execution time via `using-git-worktrees`.
### 4. Platform-Neutral Instruction File References
All instances of hardcoded `CLAUDE.md` in worktree-related skills are replaced with:
> "your project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent)"
This applies to directory preference checks in Step 1b.
## Bug Fixes (bundled)
| Bug | Problem | Fix | Location |
|-----|---------|-----|----------|
| #940 | Option 2 prose says "Then: Cleanup worktree (Step 5)" but quick reference says keep it. Step 5 says "For Options 1, 2, 4" but Common Mistakes says "Options 1 and 4 only." | Remove cleanup from Option 2. Step 5 applies to Options 1 and 4 only. | finishing SKILL.md |
| #999 | Option 1 deletes branch before removing worktree. `git branch -d` can fail because worktree still references the branch. | Reorder to: merge → verify tests → remove worktree → delete branch. Merge must succeed before anything is removed. | finishing SKILL.md |
| #238 | `git worktree remove` fails silently if CWD is inside the worktree being removed. | Add CWD guard: `cd` to main repo root before `git worktree remove`. | finishing SKILL.md |
## Issues Resolved
| Issue | Resolution |
|-------|-----------|
| #940 | Direct fix (Bug #940) |
| #991 | Opt-in consent in Step 0.5 |
| #918 | Step 0 detection + Step 1.5 finishing detection |
| #1009 | Resolved by Step 1a — agents use native tools (e.g., `EnterWorktree`) which create at harness-native paths. Depends on Step 1a working; see Risks. |
| #999 | Direct fix (Bug #999) |
| #238 | Direct fix (Bug #238) |
| #1049 | Platform-neutral instruction file references |
| #279 | Solved by detect-and-defer — native paths respected because we don't override them |
| #574 | **Deferred.** Nothing in this spec touches the brainstorming skill where the bug lives. Full fix (adding a worktree step to brainstorming's checklist) is Phase 4. |
## Risks
### Step 1a is the load-bearing assumption — RESOLVED
Step 1a — agents preferring native worktree tools over the git fallback — is the foundation the entire design rests on. If agents ignore Step 1a and fall through to Step 1b on harnesses with native support, detect-and-defer fails entirely.
**Status:** This risk materialized during implementation. The original abstract Step 1a ("You know your own toolkit") failed at 2/6 on Claude Code. The TDD gate worked as designed — it caught the failure before any skill files were modified, preventing a broken release. Three REFACTOR iterations identified the root causes (agent anchoring on concrete commands, tool-description guardrail overriding skill instructions) and produced a fix validated at 50/50 across GREEN and PRESSURE tests. See Step 1a design note above for details.
**Cross-platform validation:**
As of 2026-04-06, Claude Code is the only harness with an agent-callable mid-session worktree tool (`EnterWorktree`). All others either create worktrees before the agent starts (Codex App, Gemini CLI, Cursor) or have no native worktree support (Codex CLI, OpenCode). Step 1a is forward-compatible: when other harnesses add agent-callable worktree tools, agents will match them against the named examples and use them without skill changes.
| Harness | Current worktree model | Skill mechanism | Tested |
|---------|----------------------|-----------------|--------|
| Claude Code | Agent-callable `EnterWorktree` | Step 1a | 50/50 (GREEN + PRESSURE) |
| Codex CLI | No native tool (shell only) | Step 1b git fallback | 6/6 (`codex exec`) |
| Gemini CLI | Launch-time `--worktree` flag, no agent tool | Step 0 if launched with flag, Step 1b if not | Step 0: 1/1, Step 1b: 1/1 (`gemini -p`) |
| Cursor Agent | User-facing `/worktree`, no agent tool | Step 0 if user activated, Step 1b if not | Step 0: 1/1, Step 1b: 1/1 (`cursor-agent -p`) |
| Codex App | Platform-managed, detached HEAD, no agent tool | Step 0 detects existing | 1/1 simulated |
| OpenCode | Detection only (`ctx.worktree`), no agent tool | Step 1b git fallback | Untested (no CLI access) |
**Residual risks:**
1. If Anthropic changes `EnterWorktree`'s tool description to be more restrictive (e.g., "Do not use based on skill instructions"), the consent bridge breaks. Worth filing an issue requesting that the tool description accommodate skill-driven invocation.
2. When other harnesses add agent-callable worktree tools, they may use names not in Step 1a's list. The list should be updated as new tools appear. The generic phrasing ("a worktree or workspace-isolation tool") provides some forward coverage.
### Provenance heuristic
The `.worktrees/` or `worktrees/` = ours, anything else = hands off` heuristic works for every current harness. If a future harness adopts one of those project-local directories as its convention, we'd have a false positive (superpowers tries to clean up a harness-owned worktree). Similarly, if a user manually runs `git worktree add .worktrees/experiment` without superpowers, we'd incorrectly claim ownership. Both are low risk — every harness uses branded paths, and manual `.worktrees/` creation is unlikely — but worth noting.
### Detached HEAD finishing
The reduced menu for detached HEAD worktrees (no merge option) is correct for Codex App's sandbox model. If a user is in detached HEAD for another reason, the reduced menu still makes sense — you genuinely can't merge from detached HEAD without creating a branch first.
## Implementation Notes
Both skill files contain sections beyond the core steps that need updating during implementation:
- **Frontmatter** (`name`, `description`): Update to reflect detect-and-defer behavior
- **Quick Reference tables**: Rewrite to match new step structure and bug fixes
- **Common Mistakes sections**: Update or remove items that reference old behavior (e.g., "Skip CLAUDE.md check" is now wrong)
- **Red Flags sections**: Update to reflect new priorities (e.g., "Never create a worktree when Step 0 detects existing isolation")
- **Integration sections**: Update cross-references between skills
The spec describes *what changes*; the implementation plan will specify exact edits to these secondary sections.
## Future Work (not in this spec)
- **Phase 3 remainder:** `$TMPDIR` directory option (#666), setup docs for caching and env inheritance (#299)
- **Phase 4:** PreToolUse hooks for path enforcement (#1040), per-worktree env conventions (#597), brainstorming checklist worktree step (#574), multi-repo documentation (#710)

View File

@@ -0,0 +1,77 @@
# Platform-neutral config-file references — Phase B design
## Background
Phase A (see `2026-05-05-platform-neutral-prose-design.md`) replaced generic third-person "Claude" prose with agent-neutral forms. This phase tackles the next category: references to the per-platform instruction file (CLAUDE.md, AGENTS.md, GEMINI.md) inside skills.
The plugin runs on multiple harnesses, and each one reads its own instruction file. Where a skill names CLAUDE.md as if it were the only file, that's a Claude-Code-centric assumption that doesn't hold on Codex / Gemini CLI / OpenCode.
## In scope
Two specific lines in active skills:
1. **`skills/writing-skills/SKILL.md:58`** — `Project-specific conventions (put in CLAUDE.md)`
2. **`skills/receiving-code-review/SKILL.md:30`** — `"You're absolutely right!" (explicit CLAUDE.md violation)`
## Out of scope
- **`skills/using-superpowers/SKILL.md:22, 26`** — instruction-priority list. The list already names all three (CLAUDE.md, GEMINI.md, AGENTS.md) inclusively, which is correct: the section is making a real claim about *what counts as user instruction* on a multi-platform plugin. No change needed.
- **Historical / example artifacts**:
- `skills/systematic-debugging/CREATION-LOG.md` — attribution path (`~/.claude/CLAUDE.md`) is a historical fact.
- `skills/writing-skills/examples/CLAUDE_MD_TESTING.md` — the entire file is a worked example testing CLAUDE.md content variants. The filename, body, and the reference from `testing-skills-with-subagents.md` all stay; normalizing them defeats the example.
- **Platform-tooling references** — Phase D candidates:
- `skills/using-superpowers/SKILL.md:40` (Gemini CLI tool mapping note about GEMINI.md)
- `skills/using-superpowers/references/gemini-tools.md` (`save_memory` persists to GEMINI.md)
## Substitution rules
Two distinct calls, one per in-scope line.
### Rule 1: "where to put project-specific conventions"
`writing-skills/SKILL.md:58`:
- **Before:** `Project-specific conventions (put in CLAUDE.md)`
- **After:** `Project-specific conventions (put in your instructions file)`
Use a generic phrase rather than picking one filename. Different harnesses read different files (CLAUDE.md, AGENTS.md, GEMINI.md, etc.) and the skill should not assume one. The platform-tools reference docs (`references/{codex,copilot,gemini}-tools.md`) are the right place to name each platform's preferred file.
### Rule 2: the "(explicit CLAUDE.md violation)" parenthetical
`receiving-code-review/SKILL.md:30`:
- **Before:** `"You're absolutely right!" (explicit CLAUDE.md violation)`
- **After:** `"You're absolutely right!" (explicit instruction-file violation)`
The parenthetical is doing real work — it signals this phrase isn't just stylistically bad, it actively violates rules many users put in their instruction files. "Instruction file" is the natural cross-platform term covering AGENTS.md / CLAUDE.md / GEMINI.md collectively, and keeps the original signal without picking one filename or softening to "common".
## Commit plan
Atomic commits, in order:
1. **`writing-skills/SKILL.md`** — CLAUDE.md → "your instructions file" in the "where to put project conventions" line
2. **`receiving-code-review/SKILL.md`** — CLAUDE.md → instruction-file in the violation parenthetical
3. **Platform-tools reference docs** — add the preferred per-platform instructions filename (CLAUDE.md, AGENTS.md, GEMINI.md, etc.) to each `references/{codex,copilot,gemini}-tools.md` so readers can resolve "your instructions file" to a real filename.
Each commit message names "Phase B" and the slice.
## Verification
After each commit:
- Read the surrounding paragraph to confirm grammar and meaning still parse.
- `grep -n "CLAUDE\.md" <touched-file>` — no remaining hits in active prose (carve-outs already documented).
After both commits:
- `grep -rn "CLAUDE\.md" skills/` should return only the documented carve-outs (CREATION-LOG, CLAUDE_MD_TESTING and its inbound reference, the priority list in using-superpowers).
## Non-goals
- Do not touch the priority list ordering in `using-superpowers/SKILL.md`. Reordering CLAUDE.md / GEMINI.md / AGENTS.md is an aesthetic change, not a substitution, and out of scope here.
- Do not rename `examples/CLAUDE_MD_TESTING.md` or change its content.
- Do not modify Gemini-CLI-specific tooling references (Phase D candidates).
## Implementation note
Phase B as written here covered three commits and the three non-Claude-Code platform-tools refs. Implementation went one step further: a fourth ref, `references/claude-code-tools.md`, was added in commit `8505703` for symmetry, so Claude Code's instructions-file conventions and tool-name list live alongside the others rather than implicitly in the surrounding skill prose. That addition wasn't anticipated in this spec but is consistent with its intent.

View File

@@ -0,0 +1,94 @@
# Platform-neutral prose — Phase A design
## Background
Superpowers ships to multiple agent runtimes (Claude Code, Codex, Cursor, OpenCode, Copilot CLI, Gemini CLI). Skill content and supporting docs were written first for Claude Code and use "Claude" in places where any runtime's agent applies. OpenAI's vendored fork (openai/plugins#217) attempted a wholesale rewrite that was actively wrong in places — rewriting historical attribution paths, model names, and platform-specific install instructions — and we want to avoid that mistake while still removing platform-centric prose where it is genuinely incidental.
The full effort is broken into phases by reference category. **This spec covers Phase A only:** generic third-person prose mentioning "Claude" in non-platform-specific contexts. Later phases (config-file references, marketing copy, tool-name references) are out of scope here and will get their own specs.
## In scope
Generic prose mentions of "Claude" in:
- `skills/*/SKILL.md` and supporting `.md` files in active skill directories
- `skills/writing-skills/anthropic-best-practices.md`
- `README.md` (only where the mention is generic prose, not platform marketing)
Plus one coined-term rename: **Claude Search Optimization (CSO) → Skill Discovery Optimization (SDO)** in `skills/writing-skills/SKILL.md`.
## Out of scope
- **Platform/runtime statements** — "In Claude Code:", install instructions, tool-mapping references. (Phase D candidate.)
- **Config-file references** — CLAUDE.md, AGENTS.md, GEMINI.md priority lists and "where to put project conventions" callouts. (Phase B.)
- **Tool-name references** — `Skill`, `Bash`, `Read`, `Task`, `TodoWrite`. Skills are written in Claude Code's tool vocabulary; the existing `references/{codex,copilot,gemini}-tools.md` files map them. (At the time this spec was written, the plan was to defer or skip these. Phase E ended up doing them — replacing tool names with action language across active skills and unifying the platform-tools refs around the same vocabulary.)
- **Marketing copy** in README — "Superpowers for Claude Code", platform-named install sections. (Phase C.)
- **Historical artifacts** — `docs/plans/*.md`, `docs/superpowers/specs/*.md`, `CREATION-LOG.md`. These are dated, point-in-time documents; rewriting them rewrites history.
- **Model identifiers** — Claude Haiku / Sonnet / Opus. These are real product names.
- **Filename / URL references** — `CLAUDE.md`, `claude.com`, `claude-plugin/`, paths under `~/.claude/`.
- **`anthropic-best-practices.md` filename** — the file remains named after its source even though we rewrite the prose inside it.
## Replacement style
Use a mix that reads naturally in English:
- **Second person — "your agent"** when addressing the skill author about *their* runtime
- "your agent reads the description"
- **Third person — "the agent" / "agents" / "an agent"** when describing system behavior generically
- "Future agents find your skills"
- "Use words an agent would search for"
- "Agents read SKILL.md only when the skill becomes relevant"
Pick whichever fits the surrounding sentence; do not force consistency at the cost of awkward phrasing. Pluralize when natural ("future agents", "agents read") rather than always saying "the agent".
### Carve-outs that stay as "Claude"
- Model names: Claude Haiku, Claude Sonnet, Claude Opus
- Filenames and URLs: `CLAUDE.md`, `claude.com`, `~/.claude/`
- Branded platform name "Claude Code" wherever it refers to the runtime as such (handled in later phases)
### Coined-term rename
- **Claude Search Optimization (CSO) → Skill Discovery Optimization (SDO)**
- Appears in `skills/writing-skills/SKILL.md` as a section heading and in nearby prose. Rename the heading, the acronym, and any in-file cross-references.
## Files affected
Approximate counts based on a `grep` filtered to exclude carve-outs:
| File | Generic-prose mentions |
|------|------------------------|
| `skills/writing-skills/SKILL.md` | ~12 (includes CSO heading + body) |
| `skills/writing-skills/anthropic-best-practices.md` | ~30 |
| `skills/writing-skills/examples/CLAUDE_MD_TESTING.md` | ~1 — filename stays (it's a CLAUDE.md test artifact); the "Variant C: Claude.AI Emphatic Style" heading also stays (it's a label naming a specific style) |
| `README.md` | ~1 |
Final list confirmed during implementation by re-running the filtered grep.
## Commit plan
Four atomic commits, in order:
1. **Rename CSO → SDO** in `skills/writing-skills/SKILL.md`. Mechanical, isolated, easy to revert if we change our minds about the term.
2. **Active skills prose** — generic "Claude" → "agent" forms across `skills/*/SKILL.md` and supporting `.md`, excluding `anthropic-best-practices.md`.
3. **`anthropic-best-practices.md` prose** — same substitution rules. Separate commit because this file is a vendored adaptation of an external doc; isolating the change makes future reconciliation with upstream easier to read.
4. **README.md prose** *(only if any generic-prose mentions remain after filtering)*. Skipped if empty.
Each commit message names the phase ("Phase A") and the slice ("rename CSO to SDO", "agent prose in active skills", etc.) so the series is self-documenting.
## Verification
After each commit:
- `grep -rn "Claude" <touched-paths>` — every remaining hit must fall into a documented carve-out (model name, filename, URL, "Claude Code" platform name, historical artifact).
- Read the touched file end-to-end — substitutions should not have broken sentence flow, pronoun agreement, or list parallelism.
- No tests to run; this is prose-only.
After the final commit:
- Skim each modified skill in a live session to confirm nothing reads awkwardly.
## Non-goals
- Do not change behavior, structure, headings (other than CSO→SDO), examples, code blocks, or YAML frontmatter.
- Do not introduce new sections, callouts, or compatibility notes.
- Do not "improve" prose beyond the substitution while editing.

View File

@@ -0,0 +1,47 @@
# Platform-neutral README ordering — Phase C design
## Background
Phases A and B (see `2026-05-05-platform-neutral-prose-design.md` and `2026-05-05-platform-neutral-config-refs-design.md`) already neutralized generic Claude prose and config-file references in the README. The remaining platform-leaning signal is layout: the README's two platform listings put Claude Code first and aren't strictly alphabetical elsewhere.
This phase fixes the ordering. No prose changes.
## In scope
1. **Quickstart platform list** (`README.md:7`) — the inline link list of supported harnesses
2. **Installation section ordering** (`README.md:35152`) — the per-harness install sub-sections
## Out of scope
- Prose, marketplace names, plugin IDs, URLs — all factually correct as-is.
- Visual weight of the Claude Code section (which has two sub-sections — official Anthropic marketplace and Superpowers marketplace). Both are real install paths; collapsing them would hide accurate info.
- Section headings and content within each install block — only the ordering of the blocks changes.
## Substitution
Both listings reorder to strict alphabetical:
| Old order | New order |
|-----------|-----------|
| Claude Code | Claude Code |
| Codex CLI | Codex App |
| Codex App | Codex CLI |
| Factory Droid | Cursor |
| Gemini CLI | Factory Droid |
| OpenCode | Gemini CLI |
| Cursor | GitHub Copilot CLI |
| GitHub Copilot CLI | OpenCode |
Three moves: Codex App swaps with Codex CLI; Cursor moves up two slots; GitHub Copilot CLI moves up one.
Claude Code remains first by alphabetical chance (`Cl…` precedes `Co…`).
## Commit plan
One atomic commit covering both listings, since changing one without the other would create inconsistency between the quickstart and the installation section.
## Verification
- Quickstart anchors (`#claude-code`, `#codex-app`, etc.) still resolve to existing `### …` headings — no headings renamed.
- Each install sub-section's body is byte-identical pre/post; only positions changed.
- `git diff README.md` shows section moves only, no content edits.

View File

@@ -0,0 +1,247 @@
# Lift drill into superpowers as `evals/` — design
## Background
Drill is a Python skill-compliance benchmark that lives in its own repo at `obra/drill`. It drives real tmux sessions, runs an LLM actor as a simulated user, runs an LLM verifier on the resulting transcript, and reports pass/fail per scenario. It supports Claude Code, Codex, Gemini CLI, and (per recent commits) OpenCode and Copilot CLI.
Drill is already the *de facto* eval harness for superpowers. The PRI-1397 commit series in the drill repo lifted ~22 superpowers bash tests into drill scenarios, and the most recent superpowers commit (`a2292c5`) explicitly removed a redundant bash test with the message *"replaced by drill behavioral coverage"*. Migration momentum exists; this spec completes it.
This work moves drill into superpowers under `evals/`, deletes the redundant bash tests after per-file verification of drill scenario coverage, and updates docs so contributors land on the new structure.
## Goals
1. `evals/` is the canonical eval harness in superpowers — full drill source, scenarios, fixtures, prompts, backend configs, and tests.
2. Bash tests in `superpowers/tests/` that have been individually verified as 100% covered by drill scenarios are deleted; the rest are preserved.
3. The split between `tests/` (plugin infrastructure: bash + node + python integration tests) and `evals/` (LLM behavior with actor + verifier) is meaningful and documented.
4. Top-level docs (`README.md`, `CLAUDE.md`, `docs/testing.md`) point contributors at the right place.
5. The standalone `obra/drill` repo continues to exist (this PR does not touch it) and gets archived as a separate manual step after this PR merges.
## Non-goals
- **CI integration.** Manual-only here. The natural follow-up is "tiered": fast subset on every PR, full sweep nightly + on-demand. That requires API budget decisions, GitHub Actions secrets, and a runner image with `tmux` + `node` + `python` + `claude` / `codex` / `gemini` CLIs installed. Out of scope.
- **Scenario co-location with skills.** Scenarios stay centralized at `evals/scenarios/`. If we later decide each skill should own its scenarios, that's a path-find-and-rename operation; the YAML format does not change.
- **Renaming the internal Python package** (`drill``evals`). The directory is `evals/` (user-facing); the Python package keeps its `drill` name to keep the diff small. A short note in `evals/README.md` explains.
- **Drill repo archival.** This PR does not touch `obra/drill`. After merge, the drill repo is archived manually (read-only on GitHub, README pointer to `obra/superpowers/evals/`).
- **Lifting `tests/claude-code/analyze-token-usage.py` into `evals/bin/`.** Useful utility, not test code. Can move later; not required by this PR.
## Branching
Branch off `dev` as `f/evals-lift`. This work is independent of the open `f/cross-platform` PR — no shared file changes besides possibly `README.md`, which is small enough to resolve at merge time if it conflicts.
## Architecture after the move
```
superpowers/
evals/ ← NEW (full drill copy)
pyproject.toml (Python 3.11, uv-managed)
uv.lock
.gitignore (drill's own; results/, .venv/, .env)
README.md (was drill's README; install instructions updated)
CLAUDE.md (was drill's CLAUDE.md; paths updated)
docs/
design.md (drill's design — preserved verbatim, cross-linked from this spec)
manual-testing.md
pressure-and-red-testing.md
drill/ (Python package; name kept; cli, engine, actor, verifier, etc.)
backends/ (claude-*.yaml, codex.yaml, gemini.yaml)
scenarios/ (32+ YAML scenarios)
setup_helpers/ (15 Python helpers; create_base_repo, sdd_*, spec_*, worktree, etc.)
fixtures/ (template-repo, sdd-go-fractals, sdd-svelte-todo)
prompts/ (actor.md, verifier.md)
bin/ (assertion helper scripts: tool-called, tool-count, etc.)
tests/ (drill's own pytest suite)
tests/ ← bash tests preserved by default
brainstorm-server/ ← KEEP (node tests for brainstorm-server JS code)
opencode/ ← KEEP (plugin loading tests)
codex-plugin-sync/ ← KEEP (sync verification)
claude-code/ ← MOSTLY KEEP — see deletion gate
explicit-skill-requests/ ← KEEP unless verified replaced
skill-triggering/ ← KEEP unless verified replaced
subagent-driven-dev/ ← KEEP unless verified replaced
docs/
testing.md ← UPDATED (split into "Plugin tests" + "Skill behavior evals")
superpowers/
specs/
2026-05-06-lift-drill-into-evals-design.md ← THIS SPEC
README.md ← small Contributing-section pointer to evals/
CLAUDE.md ← one-line "Eval harness lives at evals/" pointer
```
The `tests/` and `evals/` directories serve clearly distinct roles after this PR:
- **`tests/`** — does the plugin's non-LLM code work? Unit and integration tests for the brainstorm-server JS code, OpenCode plugin loading, codex-plugin-sync sync verification. Bash + node + python.
- **`evals/`** — do agents behave correctly on real LLM sessions? Drill scenarios with actor + verifier. Python-only, runs real tmux sessions.
## Deletion gate (per bash test)
A bash test is deleted *only if* a drill scenario verifiably covers every assertion it makes. The implementation plan documents this verification per file: read the bash test, list its checks, find the drill scenario, confirm each check has a matching `verify.assertions` or `verify.criteria` entry. If even one check is missing, the option is to either extend the drill scenario or keep the bash test. Default keeps it.
**Tentative coverage map** (commit-message-based; needs per-file verification before any deletion):
| Bash test | Claimed drill replacement | Coverage status |
|-----------|---------------------------|-----------------|
| `tests/skill-triggering/prompts/*` (6 prompt files) | `triggering-*.yaml` (6 scenarios) | candidate — verify per-prompt before deleting |
| `tests/skill-triggering/run-test.sh`, `run-all.sh` | n/a (runners, not tests) | **keep** — runner scripts |
| `tests/explicit-skill-requests/prompts/please-use-brainstorming.txt` | needs verification — drill has no obvious counterpart yet | likely **keep** unless drill scenario added |
| `tests/explicit-skill-requests/prompts/use-systematic-debugging.txt` | needs verification — drill has no obvious counterpart | likely **keep** unless drill scenario added |
| `tests/explicit-skill-requests/run-claude-describes-sdd.sh` | partially → `mid-conversation-skill-invocation.yaml` | candidate — verify per-script |
| `tests/explicit-skill-requests/run-haiku-test.sh` | no drill scenario covers Haiku-specific behavior | **keep** |
| `tests/explicit-skill-requests/run-multiturn-test.sh`, `run-extended-multiturn-test.sh` | no drill scenario covers multi-turn build-up | **keep** unless drill scenarios added |
| `tests/explicit-skill-requests/run-test.sh`, `run-all.sh` | n/a (runners) | **keep** |
| `tests/subagent-driven-dev/go-fractals/`, `tests/subagent-driven-dev/svelte-todo/` | `sdd-go-fractals.yaml`, `sdd-svelte-todo.yaml` | candidate — verify before deleting (these include real assertions about test suites passing) |
| `tests/claude-code/test-document-review-system.sh` | `spec-reviewer-catches-planted-flaws.yaml` | candidate — verify before deleting |
| `tests/claude-code/test-requesting-code-review.sh` | `code-review-catches-planted-bugs.yaml` | candidate — verify before deleting |
| `tests/claude-code/test-subagent-driven-development-integration.sh` | `sdd-rejects-extra-features.yaml` (YAGNI subset) | **partial** — bash test also asserts ≥3 commits / `npm test` passes / runs `analyze-token-usage.py`. Drill scenario asserts forbidden-exports + reviewer-as-gate. Mostly disjoint — almost certainly **keep + extend drill scenario**. |
| `tests/claude-code/test-subagent-driven-development.sh` | meta/documentation test (asks agent to *describe* SDD); no drill scenario covers description tests | **keep** unless drill scenario added |
| `tests/claude-code/test-worktree-native-preference.sh` | `worktree-creation-under-pressure.yaml` | candidate — verify before deleting |
| `tests/claude-code/test-helpers.sh`, `run-skill-tests.sh`, `analyze-token-usage.py` | n/a (utilities, not tests) | **keep** — libraries/tools |
## Verification protocol (subagent-gated)
Every change in the implementation plan gets cross-checked by an independent subagent before commit.
| Change category | Subagent verification |
|----------------|----------------------|
| Each bash-test deletion | Dispatch a subagent with: (a) the bash test file content, (b) the candidate drill scenario YAML, (c) the prompt: *"List every assertion the bash test makes. List every verify entry in the drill scenario. For each bash assertion, find a matching drill check or report it as unmatched. Output a per-assertion table."* The subagent's output is the gate — only delete if every bash assertion has a match. |
| Initial `evals/` copy | Subagent verifies: (a) drill SHA being copied is recorded in the lift commit message so provenance is auditable; (b) **per-file SHA-256 checksum** matches drill repo for every file (not just file count); (c) excluded paths (`.git/`, `.venv/`, `results/`, `.env`, `__pycache__/`, `*.egg-info/`, any `.private-journal/`) are absent from `evals/`; (d) all backend YAMLs reference paths that exist post-move; (e) `pyproject.toml`, `uv.lock`, `.gitignore` are intact. |
| Drill's own pytest suite | Subagent runs `cd evals && uv run pytest` after the path-default change. Drill ships its own pytest suite at `evals/tests/` including `test_backend.py` which exercises `SUPERPOWERS_ROOT` env-var behavior — these tests must update to match the helper and continue to pass. |
| Reference scrubbing after deletion | Subagent greps the entire superpowers tree (excluding `node_modules/`, `.venv/`, and `evals/`) for references to deleted bash test paths. Search targets: `docs/`, `docs/superpowers/plans/`, `RELEASE-NOTES.md`, `CLAUDE.md`, `GEMINI.md`, `AGENTS.md`, `README.md`, `.github/`, `scripts/`, `.opencode/INSTALL.md`, `.codex-plugin/INSTALL.md`, `lefthook.yml`. Any hit is either updated or surfaces a missed dependency. |
| Path defaults change (`SUPERPOWERS_ROOT` default) | Subagent runs at least one cheap drill scenario after the path changes (e.g., `triggering-test-driven-development`) and confirms it still passes. Real validation, not just code review. |
| Final pre-PR adversarial review | Two subagents in parallel, "5 points to whoever finds the most legitimate issues" framing — same protocol used on the cross-platform PR. Verify both source code and behavior. |
Each subagent task gets its own bullet in the implementation plan with explicit inputs and pass criteria. The subagent's output is summarized in the relevant commit message ("Subagent verification: …") so the trail is auditable.
## Concrete path/config edits
**Verified prior to writing this spec.** `drill/cli.py` defines `PROJECT_ROOT = Path(__file__).parent.parent`. After the move, `cli.py` lives at `evals/drill/cli.py`, so `PROJECT_ROOT` resolves to `evals/` and `PROJECT_ROOT.parent` resolves to the superpowers repo root. That's the value `SUPERPOWERS_ROOT` should take by default.
**YAML substitution audit.** Only the four `claude*.yaml` backend configs interpolate `${SUPERPOWERS_ROOT}` into `args` (for the `--plugin-dir` flag); `codex.yaml` and `gemini.yaml` only list `SUPERPOWERS_ROOT` in `required_env` (consumed by `engine.py:233` / `setup.py:25`'s `os.environ["SUPERPOWERS_ROOT"]` lookups in pre/post-run hooks). The helper's `os.environ` mutation covers both code paths.
| File | Current | After |
|------|---------|-------|
| `drill/cli.py` | `load_dotenv(PROJECT_ROOT / ".env")` at module import; nothing about `SUPERPOWERS_ROOT` | After `load_dotenv`, call new helper `_set_superpowers_root_default()` that sets `os.environ["SUPERPOWERS_ROOT"]` to `str(PROJECT_ROOT.parent)` if and only if not already set. Order: `load_dotenv` → set default → click group definitions. |
| `drill/engine.py:233`, `drill/setup.py:25` | Direct `os.environ["SUPERPOWERS_ROOT"]` access (KeyError if unset) | Unchanged. The CLI startup hook guarantees the env var is set by the time the engine/setup execute. |
| `backends/claude*.yaml` (5 files) | `${SUPERPOWERS_ROOT}` substituted in `args` for `--plugin-dir` | Unchanged. YAML substitution reads `os.environ` at backend-load time, which is after CLI startup. |
| `backends/codex.yaml`, `backends/gemini.yaml` | `SUPERPOWERS_ROOT` in `required_env` only | Drop from `required_env` (the helper supplies it). `claude*.yaml` keep `required_env` for backward compat (env var works as override). |
| `evals/tests/test_backend.py` | Tests assert `SUPERPOWERS_ROOT` is in `required_env` lists, plus path-resolution tests | Update tests to match the new contract: helper-supplied default, env override still works, `required_env` no longer required for codex/gemini. |
| `evals/README.md` | "export SUPERPOWERS_ROOT=/path/to/superpowers" | Drop the export line; note that the env var auto-defaults to the parent of `evals/`; mention the only required setup is `ANTHROPIC_API_KEY` (or `OPENAI_API_KEY` / Gemini auth). |
| `evals/CLAUDE.md` | Same | Same |
| `evals/.gitignore` | drill's existing patterns (`results/`, `.venv/`, `__pycache__/`, `.env`, `*.pyc`, `*.egg-info/`, `dist/`, `build/`, `.claude/`) | Copied verbatim. Patterns are relative to file location, so they apply correctly under `evals/`. |
| `evals/lefthook.yml` | drill ships `lefthook.yml` defining `pre-commit: uv run ruff check && uv run ty check` | Move to `evals/lefthook.yml`. Either (a) install lefthook at the superpowers root and have it federate to `evals/lefthook.yml`, or (b) document that contributors run `cd evals && lefthook run pre-commit` manually. **Decision in implementation: option (b) for simplicity** — superpowers' top-level workflow doesn't change. |
`.env` placement: keep `evals/.env` (gitignored). Contributors source it from there or set `ANTHROPIC_API_KEY` in their shell environment.
**Top-level superpowers files needing small additions:**
- `superpowers/.gitignore`: add `evals/results/`, `evals/.venv/`, `evals/.env` (belt-and-suspenders; evals/.gitignore already covers these locally).
- `superpowers/CLAUDE.md`: add a one-line pointer "Eval harness lives at `evals/` — see `evals/README.md`" so agents discover it.
- `superpowers/docs/testing.md`: split into "## Plugin tests" (existing tests/ content, with the deleted-test references trimmed) and "## Skill behavior evals" (one-paragraph summary + pointer to `evals/`).
- `superpowers/README.md`: add a single line in the Contributing section pointing at `evals/` for skill-behavior testing.
## Migration ordering
Each step is a separate commit (or small group of commits). Step 2 is the biggest single commit (the verbatim drill copy); subsequent steps are small and atomic.
```
1. Branch off `dev` (f/evals-lift)
2. Copy drill repo into evals/ (single commit, easy to revert)
├─ Record drill SHA at copy time → commit message
├─ Use `rsync -a --exclude=.git --exclude=.venv --exclude=results
│ --exclude=.env --exclude=__pycache__ --exclude='*.egg-info'
│ --exclude=.private-journal /path/to/drill/ evals/`
│ (rsync chosen over `cp -r` for explicit excludes; verify with
│ `find evals -name '.git' -type d` returns nothing)
├─ Subagent gate: per-file SHA-256 checksum matches drill repo for every
│ non-excluded file; excluded paths absent from evals/
└─ Smoke check: `cd evals && uv sync` succeeds (proves install only;
not a behavioral test)
3. Update path defaults
├─ Add _set_superpowers_root_default() helper to drill/cli.py
├─ Wire it after load_dotenv, before click group definition
├─ Update evals/README.md and evals/CLAUDE.md (drop SUPERPOWERS_ROOT install step)
├─ Drop SUPERPOWERS_ROOT from required_env in codex.yaml/gemini.yaml
│ (keep in claude*.yaml as override)
└─ Update evals/tests/test_backend.py to match new contract
4. Validate from new location (TWO checks)
├─ Run drill's own pytest: `cd evals && uv run pytest` — must pass
└─ Run cheap drill scenario: `cd evals && uv run drill run
triggering-test-driven-development -b claude` — must pass.
Real behavioral validation, not just code review.
5. Bash test deletion phase — per-file with subagent gate
For each file in the candidate-deletion list:
a. Subagent compares bash test assertions vs drill scenario verify block
b. Pass criterion: every bash assertion has a matching drill check
c. If pass → delete the bash test file (one commit per file or per
coherent group)
d. If fail → either extend drill scenario (separate commit + verify) or
keep the bash test (no commit)
6. Stale-reference scrub
├─ Subagent greps the superpowers tree (excluding node_modules/, .venv/,
│ evals/) for deleted file paths
├─ Search targets: docs/, docs/superpowers/plans/, RELEASE-NOTES.md,
│ CLAUDE.md, GEMINI.md, AGENTS.md, README.md, .github/, scripts/,
│ .opencode/INSTALL.md, .codex-plugin/INSTALL.md, lefthook.yml
├─ Update active references (e.g., docs/testing.md, README.md install)
└─ Historical references in docs/superpowers/plans/*.md and
RELEASE-NOTES.md are PRESERVED with a brief annotation
("(test removed; behavior covered by drill scenario X)") rather
than rewritten — these are dated artifacts, not living docs.
7. Top-level docs
├─ docs/testing.md split
├─ CLAUDE.md pointer
└─ README.md Contributing section
8. Re-run smoke checks (regression gate)
├─ `cd evals && uv run pytest`
└─ `cd evals && uv run drill run triggering-test-driven-development -b claude`
9. Final adversarial review
└─ Two parallel subagents, full diff, "5 points to whoever finds the
most legitimate issues" framing. Address findings before push.
10. Push branch + open PR against dev
└─ PR description includes: drill SHA pinned at copy, archival action
item ("after merge: archive obra/drill, add README pointer to
obra/superpowers/evals/"), per-deleted-file coverage receipts.
```
## Verification (post-implementation)
The implementation plan must show:
- All non-excluded drill source files present at `evals/` after step 2 (subagent **per-file SHA-256 checksum diff** vs `obra/drill@<recorded-sha>`).
- Excluded paths (`.git/`, `.venv/`, `results/`, `.env`, `__pycache__/`, `*.egg-info/`, `.private-journal/`) absent from `evals/`.
- The step-2 commit message records the drill source SHA.
- `cd evals && uv sync` succeeds without `SUPERPOWERS_ROOT` set.
- `cd evals && uv run pytest` passes (drill's own pytest suite).
- `cd evals && uv run drill list` returns the same scenario count as the standalone drill repo at the recorded SHA.
- `cd evals && uv run drill run triggering-test-driven-development -b claude` passes (proves path defaults work end-to-end).
- For each deleted bash test: subagent verification table in the commit message showing every assertion mapped to a drill check.
- Grep for deleted file paths returns zero hits across living superpowers docs (post step 6); historical refs in `docs/superpowers/plans/*.md` and `RELEASE-NOTES.md` are annotated, not rewritten.
- `docs/testing.md` has both "Plugin tests" and "Skill behavior evals" sections.
- The drill repo's history is untouched; `obra/drill` is unaffected by this PR.
- PR description names the action item to archive `obra/drill` after merge.
## Open questions
None. All clarifying decisions have been made:
| Question | Decision |
|----------|----------|
| Where does drill live in superpowers? | `evals/` (rename from drill); standalone repo archived as separate step |
| Fate of redundant bash tests? | Delete per-file with subagent verification of coverage; default keep |
| Scenarios layout? | Centralized at `evals/scenarios/` |
| Python toolchain placement? | Self-contained at `evals/` |
| CI integration? | Manual-only this PR; documented future path |
| Migration mechanics? | Plain copy; drill repo's history preserved in archived repo, not in-tree |
| Internal Python package name? | Keep as `drill` (directory is `evals/`) |
| Branching strategy? | Independent off `dev` (not stacked on `f/cross-platform`) |

View File

@@ -1,303 +1,34 @@
# Testing Superpowers Skills # Testing Superpowers
This document describes how to test Superpowers skills, particularly the integration tests for complex skills like `subagent-driven-development`. Superpowers has two distinct kinds of tests, each in its own directory:
## Overview - **`tests/`** — does the plugin's non-LLM code work? Bash + node + python integration tests for brainstorm-server JS, OpenCode plugin loading, codex-plugin sync, and analysis utilities.
- **`evals/`** — do agents behave correctly on real LLM sessions? Python harness driving real tmux sessions of Claude Code / Codex / Gemini CLI, with an LLM actor and verifier judging skill compliance.
Testing skills that involve subagents, workflows, and complex interactions requires running actual Claude Code sessions in headless mode and verifying their behavior through session transcripts. ## Plugin tests
## Test Structure Live in `tests/`. Currently:
``` - `tests/brainstorm-server/` — node test suite for the brainstorm server JS code.
tests/ - `tests/opencode/` — bash tests for OpenCode plugin loading, bootstrap caching, and tool registration.
├── claude-code/ - `tests/codex-plugin-sync/` — bash sync verification.
│ ├── test-helpers.sh # Shared test utilities - `tests/claude-code/test-helpers.sh`, `analyze-token-usage.py` — utilities used by remaining bash tests.
│ ├── test-subagent-driven-development-integration.sh - `tests/claude-code/test-subagent-driven-development.sh` — agent-can-describe-SDD test (no drill counterpart; tests description-recall, not behavior).
│ ├── analyze-token-usage.py # Token analysis tool - `tests/claude-code/test-subagent-driven-development-integration.sh` — extended SDD integration with token analysis (drill covers the YAGNI subset; bash adds commit-count, Claude Code task-tracking, and token telemetry assertions).
│ └── run-skill-tests.sh # Test runner (if exists) - `tests/claude-code/test-worktree-native-preference.sh` — RED-GREEN-REFACTOR validation for worktree skill (drill covers the PRESSURE phase; bash also covers RED/GREEN baselines).
``` - `tests/explicit-skill-requests/` — Haiku-specific, multi-turn, and skill-name-prompted tests not covered by drill.
## Running Tests Run plugin tests via the relevant directory's `run-*.sh` or `npm test`.
### Integration Tests ## Skill behavior evals
Integration tests execute real Claude Code sessions with actual skills: Live in `evals/`. Drill is the harness; scenarios live at `evals/scenarios/*.yaml`. See `evals/README.md` for setup. Quick start:
```bash ```bash
# Run the subagent-driven-development integration test cd evals
cd tests/claude-code uv sync --extra dev
./test-subagent-driven-development-integration.sh export ANTHROPIC_API_KEY=sk-...
uv run drill run triggering-test-driven-development -b claude
``` ```
**Note:** Integration tests can take 10-30 minutes as they execute real implementation plans with multiple subagents. Drill scenarios are slow (3-30+ minutes each) and run real LLM sessions. They are not part of CI today; the natural follow-up is a tiered model (fast subset on PR, full sweep nightly + on-demand).
### Requirements
- Must run from the **superpowers plugin directory** (not from temp directories)
- Claude Code must be installed and available as `claude` command
- Local dev marketplace must be enabled: `"superpowers@superpowers-dev": true` in `~/.claude/settings.json`
## Integration Test: subagent-driven-development
### What It Tests
The integration test verifies the `subagent-driven-development` skill correctly:
1. **Plan Loading**: Reads the plan once at the beginning
2. **Full Task Text**: Provides complete task descriptions to subagents (doesn't make them read files)
3. **Self-Review**: Ensures subagents perform self-review before reporting
4. **Review Order**: Runs spec compliance review before code quality review
5. **Review Loops**: Uses review loops when issues are found
6. **Independent Verification**: Spec reviewer reads code independently, doesn't trust implementer reports
### How It Works
1. **Setup**: Creates a temporary Node.js project with a minimal implementation plan
2. **Execution**: Runs Claude Code in headless mode with the skill
3. **Verification**: Parses the session transcript (`.jsonl` file) to verify:
- Skill tool was invoked
- Subagents were dispatched (Task tool)
- TodoWrite was used for tracking
- Implementation files were created
- Tests pass
- Git commits show proper workflow
4. **Token Analysis**: Shows token usage breakdown by subagent
### Test Output
```
========================================
Integration Test: subagent-driven-development
========================================
Test project: /tmp/tmp.xyz123
=== Verification Tests ===
Test 1: Skill tool invoked...
[PASS] subagent-driven-development skill was invoked
Test 2: Subagents dispatched...
[PASS] 7 subagents dispatched
Test 3: Task tracking...
[PASS] TodoWrite used 5 time(s)
Test 6: Implementation verification...
[PASS] src/math.js created
[PASS] add function exists
[PASS] multiply function exists
[PASS] test/math.test.js created
[PASS] Tests pass
Test 7: Git commit history...
[PASS] Multiple commits created (3 total)
Test 8: No extra features added...
[PASS] No extra features added
=========================================
Token Usage Analysis
=========================================
Usage Breakdown:
----------------------------------------------------------------------------------------------------
Agent Description Msgs Input Output Cache Cost
----------------------------------------------------------------------------------------------------
main Main session (coordinator) 34 27 3,996 1,213,703 $ 4.09
3380c209 implementing Task 1: Create Add Function 1 2 787 24,989 $ 0.09
34b00fde implementing Task 2: Create Multiply Function 1 4 644 25,114 $ 0.09
3801a732 reviewing whether an implementation matches... 1 5 703 25,742 $ 0.09
4c142934 doing a final code review... 1 6 854 25,319 $ 0.09
5f017a42 a code reviewer. Review Task 2... 1 6 504 22,949 $ 0.08
a6b7fbe4 a code reviewer. Review Task 1... 1 6 515 22,534 $ 0.08
f15837c0 reviewing whether an implementation matches... 1 6 416 22,485 $ 0.07
----------------------------------------------------------------------------------------------------
TOTALS:
Total messages: 41
Input tokens: 62
Output tokens: 8,419
Cache creation tokens: 132,742
Cache read tokens: 1,382,835
Total input (incl cache): 1,515,639
Total tokens: 1,524,058
Estimated cost: $4.67
(at $3/$15 per M tokens for input/output)
========================================
Test Summary
========================================
STATUS: PASSED
```
## Token Analysis Tool
### Usage
Analyze token usage from any Claude Code session:
```bash
python3 tests/claude-code/analyze-token-usage.py ~/.claude/projects/<project-dir>/<session-id>.jsonl
```
### Finding Session Files
Session transcripts are stored in `~/.claude/projects/` with the working directory path encoded:
```bash
# Example for /Users/jesse/Documents/GitHub/superpowers/superpowers
SESSION_DIR="$HOME/.claude/projects/-Users-jesse-Documents-GitHub-superpowers-superpowers"
# Find recent sessions
ls -lt "$SESSION_DIR"/*.jsonl | head -5
```
### What It Shows
- **Main session usage**: Token usage by the coordinator (you or main Claude instance)
- **Per-subagent breakdown**: Each Task invocation with:
- Agent ID
- Description (extracted from prompt)
- Message count
- Input/output tokens
- Cache usage
- Estimated cost
- **Totals**: Overall token usage and cost estimate
### Understanding the Output
- **High cache reads**: Good - means prompt caching is working
- **High input tokens on main**: Expected - coordinator has full context
- **Similar costs per subagent**: Expected - each gets similar task complexity
- **Cost per task**: Typical range is $0.05-$0.15 per subagent depending on task
## Troubleshooting
### Skills Not Loading
**Problem**: Skill not found when running headless tests
**Solutions**:
1. Ensure you're running FROM the superpowers directory: `cd /path/to/superpowers && tests/...`
2. Check `~/.claude/settings.json` has `"superpowers@superpowers-dev": true` in `enabledPlugins`
3. Verify skill exists in `skills/` directory
### Permission Errors
**Problem**: Claude blocked from writing files or accessing directories
**Solutions**:
1. Use `--permission-mode bypassPermissions` flag
2. Use `--add-dir /path/to/temp/dir` to grant access to test directories
3. Check file permissions on test directories
### Test Timeouts
**Problem**: Test takes too long and times out
**Solutions**:
1. Increase timeout: `timeout 1800 claude ...` (30 minutes)
2. Check for infinite loops in skill logic
3. Review subagent task complexity
### Session File Not Found
**Problem**: Can't find session transcript after test run
**Solutions**:
1. Check the correct project directory in `~/.claude/projects/`
2. Use `find ~/.claude/projects -name "*.jsonl" -mmin -60` to find recent sessions
3. Verify test actually ran (check for errors in test output)
## Writing New Integration Tests
### Template
```bash
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/test-helpers.sh"
# Create test project
TEST_PROJECT=$(create_test_project)
trap "cleanup_test_project $TEST_PROJECT" EXIT
# Set up test files...
cd "$TEST_PROJECT"
# Run Claude with skill
PROMPT="Your test prompt here"
cd "$SCRIPT_DIR/../.." && timeout 1800 claude -p "$PROMPT" \
--allowed-tools=all \
--add-dir "$TEST_PROJECT" \
--permission-mode bypassPermissions \
2>&1 | tee output.txt
# Find and analyze session
WORKING_DIR_ESCAPED=$(echo "$SCRIPT_DIR/../.." | sed 's/\\//-/g' | sed 's/^-//')
SESSION_DIR="$HOME/.claude/projects/$WORKING_DIR_ESCAPED"
SESSION_FILE=$(find "$SESSION_DIR" -name "*.jsonl" -type f -mmin -60 | sort -r | head -1)
# Verify behavior by parsing session transcript
if grep -q '"name":"Skill".*"skill":"your-skill-name"' "$SESSION_FILE"; then
echo "[PASS] Skill was invoked"
fi
# Show token analysis
python3 "$SCRIPT_DIR/analyze-token-usage.py" "$SESSION_FILE"
```
### Best Practices
1. **Always cleanup**: Use trap to cleanup temp directories
2. **Parse transcripts**: Don't grep user-facing output - parse the `.jsonl` session file
3. **Grant permissions**: Use `--permission-mode bypassPermissions` and `--add-dir`
4. **Run from plugin dir**: Skills only load when running from the superpowers directory
5. **Show token usage**: Always include token analysis for cost visibility
6. **Test real behavior**: Verify actual files created, tests passing, commits made
## Session Transcript Format
Session transcripts are JSONL (JSON Lines) files where each line is a JSON object representing a message or tool result.
### Key Fields
```json
{
"type": "assistant",
"message": {
"content": [...],
"usage": {
"input_tokens": 27,
"output_tokens": 3996,
"cache_read_input_tokens": 1213703
}
}
}
```
### Tool Results
```json
{
"type": "user",
"toolUseResult": {
"agentId": "3380c209",
"usage": {
"input_tokens": 2,
"output_tokens": 787,
"cache_read_input_tokens": 24989
},
"prompt": "You are implementing Task 1...",
"content": [{"type": "text", "text": "..."}]
}
}
```
The `agentId` field links to subagent sessions, and the `usage` field contains token usage for that specific subagent invocation.

1
evals Submodule

Submodule evals added at 29957de826

View File

@@ -1,6 +1,6 @@
{ {
"name": "superpowers", "name": "superpowers",
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques", "description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
"version": "5.0.0", "version": "5.1.0",
"contextFileName": "GEMINI.md" "contextFileName": "GEMINI.md"
} }

View File

@@ -3,7 +3,7 @@
"hooks": { "hooks": {
"sessionStart": [ "sessionStart": [
{ {
"command": "./hooks/session-start" "command": "./hooks/run-hook.cmd session-start"
} }
] ]
} }

View File

@@ -35,23 +35,23 @@ warning_escaped=$(escape_for_json "$warning_message")
session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>" session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
# Output context injection as JSON. # Output context injection as JSON.
# Cursor hooks expect additional_context. # Cursor hooks expect additional_context (snake_case).
# Claude Code hooks expect hookSpecificOutput.additionalContext. # Claude Code hooks expect hookSpecificOutput.additionalContext (nested).
# Claude Code reads BOTH fields without deduplication, so we must only # Copilot CLI (v1.0.11+) and others expect additionalContext (top-level, SDK standard).
# emit the field consumed by the current platform to avoid double injection. # Claude Code reads BOTH additional_context and hookSpecificOutput without
# deduplication, so we must emit only the field the current platform consumes.
# #
# Uses printf instead of heredoc (cat <<EOF) to work around a bash 5.3+ # Uses printf instead of heredoc to work around bash 5.3+ heredoc hang.
# bug where heredoc variable expansion hangs when content exceeds ~512 bytes.
# See: https://github.com/obra/superpowers/issues/571 # See: https://github.com/obra/superpowers/issues/571
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
# Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT) — emit additional_context # Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT)
printf '{\n "additional_context": "%s"\n}\n' "$session_context" printf '{\n "additional_context": "%s"\n}\n' "$session_context"
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ]; then elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
# Claude Code sets CLAUDE_PLUGIN_ROOT — emit only hookSpecificOutput # Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context" printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
else else
# Other platformsemit additional_context as fallback # Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format
printf '{\n "additional_context": "%s"\n}\n' "$session_context" printf '{\n "additionalContext": "%s"\n}\n' "$session_context"
fi fi
exit 0 exit 0

View File

@@ -1,6 +1,23 @@
{ {
"name": "superpowers", "name": "superpowers",
"version": "5.0.4", "version": "5.1.0",
"description": "Superpowers skills and runtime bootstrap for coding agents",
"type": "module", "type": "module",
"main": ".opencode/plugins/superpowers.js" "main": ".opencode/plugins/superpowers.js",
"keywords": [
"pi-package",
"skills",
"tdd",
"debugging",
"collaboration",
"workflow"
],
"pi": {
"extensions": [
"./.pi/extensions/superpowers.ts"
],
"skills": [
"./skills"
]
}
} }

220
scripts/bump-version.sh Executable file
View File

@@ -0,0 +1,220 @@
#!/usr/bin/env bash
#
# bump-version.sh — bump version numbers across all declared files,
# with drift detection and repo-wide audit for missed files.
#
# Usage:
# bump-version.sh <new-version> Bump all declared files to new version
# bump-version.sh --check Report current versions (detect drift)
# bump-version.sh --audit Check + grep repo for old version strings
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
CONFIG="$REPO_ROOT/.version-bump.json"
if [[ ! -f "$CONFIG" ]]; then
echo "error: .version-bump.json not found at $CONFIG" >&2
exit 1
fi
# --- helpers ---
# Read a dotted field path from a JSON file.
# Handles both simple ("version") and nested ("plugins.0.version") paths.
read_json_field() {
local file="$1" field="$2"
# Convert dot-path to jq path: "plugins.0.version" -> .plugins[0].version
local jq_path
jq_path=$(echo "$field" | sed -E 's/\.([0-9]+)/[\1]/g' | sed 's/^/./' | sed 's/\.\././g')
jq -r "$jq_path" "$file"
}
# Write a dotted field path in a JSON file, preserving formatting.
write_json_field() {
local file="$1" field="$2" value="$3"
local jq_path
jq_path=$(echo "$field" | sed -E 's/\.([0-9]+)/[\1]/g' | sed 's/^/./' | sed 's/\.\././g')
local tmp="${file}.tmp"
jq "$jq_path = \"$value\"" "$file" > "$tmp" && mv "$tmp" "$file"
}
# Read the list of declared files from config.
# Outputs lines of "path<TAB>field"
declared_files() {
jq -r '.files[] | "\(.path)\t\(.field)"' "$CONFIG"
}
# Read the audit exclude patterns from config.
audit_excludes() {
jq -r '.audit.exclude[]' "$CONFIG" 2>/dev/null
}
# --- commands ---
cmd_check() {
local has_drift=0
local versions=()
echo "Version check:"
echo ""
while IFS=$'\t' read -r path field; do
local fullpath="$REPO_ROOT/$path"
if [[ ! -f "$fullpath" ]]; then
printf " %-45s MISSING\n" "$path ($field)"
has_drift=1
continue
fi
local ver
ver=$(read_json_field "$fullpath" "$field")
printf " %-45s %s\n" "$path ($field)" "$ver"
versions+=("$ver")
done < <(declared_files)
echo ""
# Check if all versions match
local unique
unique=$(printf '%s\n' "${versions[@]}" | sort -u | wc -l | tr -d ' ')
if [[ "$unique" -gt 1 ]]; then
echo "DRIFT DETECTED — versions are not in sync:"
printf '%s\n' "${versions[@]}" | sort | uniq -c | sort -rn | while read -r count ver; do
echo " $ver ($count files)"
done
has_drift=1
else
echo "All declared files are in sync at ${versions[0]}"
fi
return $has_drift
}
cmd_audit() {
# First run check
cmd_check || true
echo ""
# Determine the current version (most common across declared files)
local current_version
current_version=$(
while IFS=$'\t' read -r path field; do
local fullpath="$REPO_ROOT/$path"
[[ -f "$fullpath" ]] && read_json_field "$fullpath" "$field"
done < <(declared_files) | sort | uniq -c | sort -rn | head -1 | awk '{print $2}'
)
if [[ -z "$current_version" ]]; then
echo "error: could not determine current version" >&2
return 1
fi
echo "Audit: scanning repo for version string '$current_version'..."
echo ""
# Build grep exclude args
local -a exclude_args=()
while IFS= read -r pattern; do
exclude_args+=("--exclude=$pattern" "--exclude-dir=$pattern")
done < <(audit_excludes)
# Also always exclude binary files and .git
exclude_args+=("--exclude-dir=.git" "--exclude-dir=node_modules" "--binary-files=without-match")
# Get list of declared paths for comparison
local -a declared_paths=()
while IFS=$'\t' read -r path _field; do
declared_paths+=("$path")
done < <(declared_files)
# Grep for the version string
local found_undeclared=0
while IFS= read -r match; do
local match_file
match_file=$(echo "$match" | cut -d: -f1)
# Make path relative to repo root
local rel_path="${match_file#$REPO_ROOT/}"
# Check if this file is in the declared list
local is_declared=0
for dp in "${declared_paths[@]}"; do
if [[ "$rel_path" == "$dp" ]]; then
is_declared=1
break
fi
done
if [[ "$is_declared" -eq 0 ]]; then
if [[ "$found_undeclared" -eq 0 ]]; then
echo "UNDECLARED files containing '$current_version':"
found_undeclared=1
fi
echo " $match"
fi
done < <(grep -rn "${exclude_args[@]}" -F "$current_version" "$REPO_ROOT" 2>/dev/null || true)
if [[ "$found_undeclared" -eq 0 ]]; then
echo "No undeclared files contain the version string. All clear."
else
echo ""
echo "Review the above files — if they should be bumped, add them to .version-bump.json"
echo "If they should be skipped, add them to the audit.exclude list."
fi
}
cmd_bump() {
local new_version="$1"
# Validate semver-ish format
if ! echo "$new_version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
echo "error: '$new_version' doesn't look like a version (expected X.Y.Z)" >&2
exit 1
fi
echo "Bumping all declared files to $new_version..."
echo ""
while IFS=$'\t' read -r path field; do
local fullpath="$REPO_ROOT/$path"
if [[ ! -f "$fullpath" ]]; then
echo " SKIP (missing): $path"
continue
fi
local old_ver
old_ver=$(read_json_field "$fullpath" "$field")
write_json_field "$fullpath" "$field" "$new_version"
printf " %-45s %s -> %s\n" "$path ($field)" "$old_ver" "$new_version"
done < <(declared_files)
echo ""
echo "Done. Running audit to check for missed files..."
echo ""
cmd_audit
}
# --- main ---
case "${1:-}" in
--check)
cmd_check
;;
--audit)
cmd_audit
;;
--help|-h|"")
echo "Usage: bump-version.sh <new-version> | --check | --audit"
echo ""
echo " <new-version> Bump all declared files to the given version"
echo " --check Show current versions, detect drift"
echo " --audit Check + scan repo for undeclared version references"
exit 0
;;
--*)
echo "error: unknown flag '$1'" >&2
exit 1
;;
*)
cmd_bump "$1"
;;
esac

463
scripts/sync-to-codex-plugin.sh Executable file
View File

@@ -0,0 +1,463 @@
#!/usr/bin/env bash
#
# sync-to-codex-plugin.sh
#
# Sync this superpowers checkout → prime-radiant-inc/openai-codex-plugins.
# Clones the fork fresh into a temp dir, rsyncs tracked upstream plugin content
# (including committed Codex files under .codex-plugin/ and assets/), preserves
# OpenAI-owned marketplace metadata already in the destination plugin, commits,
# pushes a sync branch, and opens a PR.
# Path/user agnostic — auto-detects upstream from script location.
#
# Deterministic: running twice against the same upstream SHA produces PRs with
# identical diffs, so two back-to-back runs can verify the tool itself.
#
# Usage:
# ./scripts/sync-to-codex-plugin.sh # full run
# ./scripts/sync-to-codex-plugin.sh -n # dry run
# ./scripts/sync-to-codex-plugin.sh -y # skip confirm
# ./scripts/sync-to-codex-plugin.sh --local PATH # existing checkout
# ./scripts/sync-to-codex-plugin.sh --base BRANCH # default: main
# ./scripts/sync-to-codex-plugin.sh --bootstrap # create plugin dir if missing
#
# Bootstrap mode: skips the "plugin must exist on base" requirement and creates
# plugins/superpowers/ when absent, then copies the tracked plugin files from
# upstream just like a normal sync.
#
# Requires: bash, rsync, git, gh (authenticated), python3.
set -euo pipefail
# =============================================================================
# Config — edit as upstream or canonical plugin shape evolves
# =============================================================================
FORK="prime-radiant-inc/openai-codex-plugins"
DEFAULT_BASE="main"
DEST_REL="plugins/superpowers"
# Paths in upstream that should NOT land in the embedded plugin.
# All patterns use a leading "/" to anchor them to the source root.
# Unanchored patterns like "scripts/" would match any directory named
# "scripts" at any depth — including legitimate nested dirs like
# skills/brainstorming/scripts/. Anchoring prevents that.
# (.DS_Store is intentionally unanchored — Finder creates them everywhere.)
EXCLUDES=(
# Dotfiles and infra — top-level only
"/.claude/"
"/.claude-plugin/"
"/.codex/"
"/.cursor-plugin/"
"/.git/"
"/.gitattributes"
"/.github/"
"/.gitignore"
"/.opencode/"
"/.version-bump.json"
"/.worktrees/"
".DS_Store"
# Root ceremony files
"/AGENTS.md"
"/CHANGELOG.md"
"/CLAUDE.md"
"/GEMINI.md"
"/RELEASE-NOTES.md"
"/gemini-extension.json"
"/package.json"
# Directories not shipped by canonical Codex plugins
"/commands/"
"/docs/"
"/evals/"
"/hooks/"
"/lib/"
"/scripts/"
"/tests/"
"/tmp/"
)
# =============================================================================
# Ignored-path helpers
# =============================================================================
IGNORED_DIR_EXCLUDES=()
path_has_directory_exclude() {
local path="$1"
local dir
if [[ ${#IGNORED_DIR_EXCLUDES[@]} -eq 0 ]]; then
return 1
fi
for dir in "${IGNORED_DIR_EXCLUDES[@]}"; do
[[ "$path" == "$dir"* ]] && return 0
done
return 1
}
ignored_directory_has_tracked_descendants() {
local path="$1"
[[ -n "$(git -C "$UPSTREAM" ls-files --cached -- "$path/")" ]]
}
append_git_ignored_directory_excludes() {
local path
local lookup_path
while IFS= read -r -d '' path; do
[[ "$path" == */ ]] || continue
lookup_path="${path%/}"
if ! ignored_directory_has_tracked_descendants "$lookup_path"; then
IGNORED_DIR_EXCLUDES+=("$path")
RSYNC_ARGS+=(--exclude="/$path")
fi
done < <(git -C "$UPSTREAM" ls-files --others --ignored --exclude-standard --directory -z)
}
append_git_ignored_file_excludes() {
local path
while IFS= read -r -d '' path; do
path_has_directory_exclude "$path" && continue
RSYNC_ARGS+=(--exclude="/$path")
done < <(git -C "$UPSTREAM" ls-files --others --ignored --exclude-standard -z)
}
# =============================================================================
# Args
# =============================================================================
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
UPSTREAM="$(cd "$SCRIPT_DIR/.." && pwd)"
BASE="$DEFAULT_BASE"
DRY_RUN=0
YES=0
LOCAL_CHECKOUT=""
BOOTSTRAP=0
usage() {
sed -n '/^# Usage:/,/^# Requires:/s/^# \{0,1\}//p' "$0"
exit "${1:-0}"
}
while [[ $# -gt 0 ]]; do
case "$1" in
-n|--dry-run) DRY_RUN=1; shift ;;
-y|--yes) YES=1; shift ;;
--local) LOCAL_CHECKOUT="$2"; shift 2 ;;
--base) BASE="$2"; shift 2 ;;
--bootstrap) BOOTSTRAP=1; shift ;;
-h|--help) usage 0 ;;
*) echo "Unknown arg: $1" >&2; usage 2 ;;
esac
done
# =============================================================================
# Preflight
# =============================================================================
die() { echo "ERROR: $*" >&2; exit 1; }
command -v rsync >/dev/null || die "rsync not found in PATH"
command -v git >/dev/null || die "git not found in PATH"
command -v gh >/dev/null || die "gh not found — install GitHub CLI"
command -v python3 >/dev/null || die "python3 not found in PATH"
gh auth status >/dev/null 2>&1 || die "gh not authenticated — run 'gh auth login'"
[[ -d "$UPSTREAM/.git" ]] || die "upstream '$UPSTREAM' is not a git checkout"
[[ -f "$UPSTREAM/.codex-plugin/plugin.json" ]] || die "committed Codex manifest missing at $UPSTREAM/.codex-plugin/plugin.json"
# Read the upstream version from the committed Codex manifest.
UPSTREAM_VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["version"])' "$UPSTREAM/.codex-plugin/plugin.json")"
[[ -n "$UPSTREAM_VERSION" ]] || die "could not read 'version' from committed Codex manifest"
UPSTREAM_BRANCH="$(cd "$UPSTREAM" && git branch --show-current)"
UPSTREAM_SHA="$(cd "$UPSTREAM" && git rev-parse HEAD)"
UPSTREAM_SHORT="$(cd "$UPSTREAM" && git rev-parse --short HEAD)"
confirm() {
[[ $YES -eq 1 ]] && return 0
read -rp "$1 [y/N] " ans
[[ "$ans" == "y" || "$ans" == "Y" ]]
}
if [[ "$UPSTREAM_BRANCH" != "main" ]]; then
echo "WARNING: upstream is on '$UPSTREAM_BRANCH', not 'main'"
confirm "Sync from '$UPSTREAM_BRANCH' anyway?" || exit 1
fi
UPSTREAM_STATUS="$(cd "$UPSTREAM" && git status --porcelain)"
if [[ -n "$UPSTREAM_STATUS" ]]; then
echo "WARNING: upstream has uncommitted changes:"
echo "$UPSTREAM_STATUS" | sed 's/^/ /'
echo "Sync will use working-tree state, not HEAD ($UPSTREAM_SHORT)."
confirm "Continue anyway?" || exit 1
fi
# =============================================================================
# Prepare destination (clone fork fresh, or use --local)
# =============================================================================
CLEANUP_DIR=""
cleanup() {
if [[ -n "$CLEANUP_DIR" ]]; then
rm -rf "$CLEANUP_DIR"
fi
}
trap cleanup EXIT
if [[ -n "$LOCAL_CHECKOUT" ]]; then
DEST_REPO="$(cd "$LOCAL_CHECKOUT" && pwd)"
[[ -d "$DEST_REPO/.git" ]] || die "--local path '$DEST_REPO' is not a git checkout"
else
echo "Cloning $FORK..."
CLEANUP_DIR="$(mktemp -d)"
DEST_REPO="$CLEANUP_DIR/openai-codex-plugins"
gh repo clone "$FORK" "$DEST_REPO" >/dev/null
fi
DEST="$DEST_REPO/$DEST_REL"
PREVIEW_REPO="$DEST_REPO"
PREVIEW_DEST="$DEST"
SYNC_SOURCE=""
overlay_destination_paths() {
local repo="$1"
local path
local source_path
local preview_path
while IFS= read -r -d '' path; do
source_path="$repo/$path"
preview_path="$PREVIEW_REPO/$path"
if [[ -e "$source_path" ]]; then
mkdir -p "$(dirname "$preview_path")"
cp -R "$source_path" "$preview_path"
else
rm -rf "$preview_path"
fi
done
}
copy_local_destination_overlay() {
overlay_destination_paths "$DEST_REPO" < <(
git -C "$DEST_REPO" diff --name-only -z -- "$DEST_REL"
)
overlay_destination_paths "$DEST_REPO" < <(
git -C "$DEST_REPO" diff --cached --name-only -z -- "$DEST_REL"
)
overlay_destination_paths "$DEST_REPO" < <(
git -C "$DEST_REPO" ls-files --others --exclude-standard -z -- "$DEST_REL"
)
overlay_destination_paths "$DEST_REPO" < <(
git -C "$DEST_REPO" ls-files --others --ignored --exclude-standard -z -- "$DEST_REL"
)
}
local_checkout_has_uncommitted_destination_changes() {
[[ -n "$(git -C "$DEST_REPO" status --porcelain=1 --untracked-files=all --ignored=matching -- "$DEST_REL")" ]]
}
prepare_preview_checkout() {
if [[ -n "$LOCAL_CHECKOUT" ]]; then
[[ -n "$CLEANUP_DIR" ]] || CLEANUP_DIR="$(mktemp -d)"
PREVIEW_REPO="$CLEANUP_DIR/preview"
git clone -q --no-local "$DEST_REPO" "$PREVIEW_REPO"
PREVIEW_DEST="$PREVIEW_REPO/$DEST_REL"
fi
git -C "$PREVIEW_REPO" checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
if [[ -n "$LOCAL_CHECKOUT" ]]; then
copy_local_destination_overlay
fi
if [[ $BOOTSTRAP -ne 1 ]]; then
[[ -d "$PREVIEW_DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap, or pass --base <branch>"
fi
}
prepare_apply_checkout() {
git -C "$DEST_REPO" checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
if [[ $BOOTSTRAP -ne 1 ]]; then
[[ -d "$DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap, or pass --base <branch>"
fi
}
apply_to_preview_checkout() {
if [[ $BOOTSTRAP -eq 1 ]]; then
mkdir -p "$PREVIEW_DEST"
fi
rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$PREVIEW_DEST/"
}
preview_checkout_has_changes() {
[[ -n "$(git -C "$PREVIEW_REPO" status --porcelain "$DEST_REL")" ]]
}
prepare_preview_checkout
TIMESTAMP="$(date -u +%Y%m%d-%H%M%S)"
if [[ $BOOTSTRAP -eq 1 ]]; then
SYNC_BRANCH="bootstrap/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
else
SYNC_BRANCH="sync/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
fi
# =============================================================================
# Build rsync args
# =============================================================================
RSYNC_ARGS=(-av --delete --delete-excluded)
for pat in "${EXCLUDES[@]}"; do RSYNC_ARGS+=(--exclude="$pat"); done
append_git_ignored_directory_excludes
append_git_ignored_file_excludes
copy_preserved_destination_metadata() {
local destination="$1"
local source="$2"
local path
local rel
[[ -d "$destination/skills" ]] || return 0
while IFS= read -r -d '' path; do
rel="${path#"$destination"/}"
mkdir -p "$source/$(dirname "$rel")"
cp -p "$path" "$source/$rel"
done < <(find "$destination/skills" -path '*/agents/openai.yaml' -type f -print0)
}
prepare_sync_source() {
local destination="$1"
[[ -n "$CLEANUP_DIR" ]] || CLEANUP_DIR="$(mktemp -d)"
SYNC_SOURCE="$CLEANUP_DIR/source-overlay"
rm -rf "$SYNC_SOURCE"
mkdir -p "$SYNC_SOURCE"
rsync "${RSYNC_ARGS[@]}" "$UPSTREAM/" "$SYNC_SOURCE/" >/dev/null
copy_preserved_destination_metadata "$destination" "$SYNC_SOURCE"
}
prepare_sync_source "$PREVIEW_DEST"
# =============================================================================
# Dry run preview (always shown)
# =============================================================================
echo ""
echo "Upstream: $UPSTREAM ($UPSTREAM_BRANCH @ $UPSTREAM_SHORT)"
echo "Version: $UPSTREAM_VERSION"
echo "Fork: $FORK"
echo "Base: $BASE"
echo "Branch: $SYNC_BRANCH"
if [[ $BOOTSTRAP -eq 1 ]]; then
echo "Mode: BOOTSTRAP (creating plugins/superpowers/ when absent)"
fi
echo ""
echo "=== Preview (rsync --dry-run) ==="
rsync "${RSYNC_ARGS[@]}" --dry-run --itemize-changes "$SYNC_SOURCE/" "$PREVIEW_DEST/"
echo "=== End preview ==="
echo ""
if [[ $DRY_RUN -eq 1 ]]; then
echo ""
echo "Dry run only. Nothing was changed or pushed."
exit 0
fi
# =============================================================================
# Apply
# =============================================================================
echo ""
confirm "Apply changes, push branch, and open PR?" || { echo "Aborted."; exit 1; }
echo ""
if [[ -n "$LOCAL_CHECKOUT" ]]; then
if local_checkout_has_uncommitted_destination_changes; then
die "local checkout has uncommitted changes under '$DEST_REL' — commit, stash, or discard them before syncing"
fi
apply_to_preview_checkout
if ! preview_checkout_has_changes; then
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
exit 0
fi
fi
prepare_apply_checkout
cd "$DEST_REPO"
git checkout -q -b "$SYNC_BRANCH"
echo "Syncing upstream content..."
if [[ $BOOTSTRAP -eq 1 ]]; then
mkdir -p "$DEST"
fi
rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$DEST/"
# Bail early if nothing actually changed
cd "$DEST_REPO"
if [[ -z "$(git status --porcelain "$DEST_REL")" ]]; then
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
exit 0
fi
# =============================================================================
# Commit, push, open PR
# =============================================================================
git add "$DEST_REL"
if [[ $BOOTSTRAP -eq 1 ]]; then
COMMIT_TITLE="bootstrap superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
PR_BODY="Initial bootstrap of the superpowers plugin from upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
Creates \`plugins/superpowers/\` by copying the tracked plugin files from upstream, including \`.codex-plugin/plugin.json\` and \`assets/\`.
Run via: \`scripts/sync-to-codex-plugin.sh --bootstrap\`
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
This is a one-time bootstrap. Subsequent syncs will be normal (non-bootstrap) runs using the same tracked upstream plugin files."
else
COMMIT_TITLE="sync superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
PR_BODY="Automated sync from superpowers upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
Copies the tracked plugin files from upstream, including the committed Codex manifest and assets.
Run via: \`scripts/sync-to-codex-plugin.sh\`
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
Running the sync tool again against the same upstream SHA should produce a PR with an identical diff — use that to verify the tool is behaving."
fi
git commit --quiet -m "$COMMIT_TITLE
Automated sync via scripts/sync-to-codex-plugin.sh
Upstream: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
Branch: $SYNC_BRANCH"
echo "Pushing $SYNC_BRANCH to $FORK..."
git push -u origin "$SYNC_BRANCH" --quiet
echo "Opening PR..."
PR_URL="$(gh pr create \
--repo "$FORK" \
--base "$BASE" \
--head "$SYNC_BRANCH" \
--title "$COMMIT_TITLE" \
--body "$PR_BODY")"
PR_NUM="${PR_URL##*/}"
DIFF_URL="https://github.com/$FORK/pull/$PR_NUM/files"
echo ""
echo "PR opened: $PR_URL"
echo "Diff view: $DIFF_URL"

View File

@@ -27,7 +27,7 @@ You MUST create a task for each of these items and complete them in order:
4. **Propose 2-3 approaches** — with trade-offs and your recommendation 4. **Propose 2-3 approaches** — with trade-offs and your recommendation
5. **Present design** — in sections scaled to their complexity, get user approval after each section 5. **Present design** — in sections scaled to their complexity, get user approval after each section
6. **Write design doc** — save to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` and commit 6. **Write design doc** — save to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` and commit
7. **Spec review loop**dispatch spec-document-reviewer subagent with precisely crafted review context (never your session history); fix issues and re-dispatch until approved (max 3 iterations, then surface to human) 7. **Spec self-review**quick inline check for placeholders, contradictions, ambiguity, scope (see below)
8. **User reviews written spec** — ask user to review the spec file before proceeding 8. **User reviews written spec** — ask user to review the spec file before proceeding
9. **Transition to implementation** — invoke writing-plans skill to create implementation plan 9. **Transition to implementation** — invoke writing-plans skill to create implementation plan
@@ -43,8 +43,7 @@ digraph brainstorming {
"Present design sections" [shape=box]; "Present design sections" [shape=box];
"User approves design?" [shape=diamond]; "User approves design?" [shape=diamond];
"Write design doc" [shape=box]; "Write design doc" [shape=box];
"Spec review loop" [shape=box]; "Spec self-review\n(fix inline)" [shape=box];
"Spec review passed?" [shape=diamond];
"User reviews spec?" [shape=diamond]; "User reviews spec?" [shape=diamond];
"Invoke writing-plans skill" [shape=doublecircle]; "Invoke writing-plans skill" [shape=doublecircle];
@@ -57,10 +56,8 @@ digraph brainstorming {
"Present design sections" -> "User approves design?"; "Present design sections" -> "User approves design?";
"User approves design?" -> "Present design sections" [label="no, revise"]; "User approves design?" -> "Present design sections" [label="no, revise"];
"User approves design?" -> "Write design doc" [label="yes"]; "User approves design?" -> "Write design doc" [label="yes"];
"Write design doc" -> "Spec review loop"; "Write design doc" -> "Spec self-review\n(fix inline)";
"Spec review loop" -> "Spec review passed?"; "Spec self-review\n(fix inline)" -> "User reviews spec?";
"Spec review passed?" -> "Spec review loop" [label="issues found,\nfix and re-dispatch"];
"Spec review passed?" -> "User reviews spec?" [label="approved"];
"User reviews spec?" -> "Write design doc" [label="changes requested"]; "User reviews spec?" -> "Write design doc" [label="changes requested"];
"User reviews spec?" -> "Invoke writing-plans skill" [label="approved"]; "User reviews spec?" -> "Invoke writing-plans skill" [label="approved"];
} }
@@ -116,12 +113,15 @@ digraph brainstorming {
- Use elements-of-style:writing-clearly-and-concisely skill if available - Use elements-of-style:writing-clearly-and-concisely skill if available
- Commit the design document to git - Commit the design document to git
**Spec Review Loop:** **Spec Self-Review:**
After writing the spec document: After writing the spec document, look at it with fresh eyes:
1. Dispatch spec-document-reviewer subagent (see spec-document-reviewer-prompt.md) 1. **Placeholder scan:** Any "TBD", "TODO", incomplete sections, or vague requirements? Fix them.
2. If Issues Found: fix, re-dispatch, repeat until Approved 2. **Internal consistency:** Do any sections contradict each other? Does the architecture match the feature descriptions?
3. If loop exceeds 3 iterations, surface to human for guidance 3. **Scope check:** Is this focused enough for a single implementation plan, or does it need decomposition?
4. **Ambiguity check:** Could any requirement be interpreted two different ways? If so, pick one and make it explicit.
Fix any issues inline. No need to re-review — just fix and move on.
**User Review Gate:** **User Review Gate:**
After the spec review loop passes, ask the user to review the written spec before proceeding: After the spec review loop passes, ask the user to review the written spec before proceeding:

View File

@@ -13,7 +13,7 @@
* - Scrollable main content area * - Scrollable main content area
* - CSS helpers for common UI patterns * - CSS helpers for common UI patterns
* *
* Content is injected via placeholder comment in #claude-content. * Content is injected via placeholder comment in #frame-content.
*/ */
* { box-sizing: border-box; margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; }
@@ -77,7 +77,7 @@
.header .status::before { content: ''; width: 6px; height: 6px; background: var(--success); border-radius: 50%; } .header .status::before { content: ''; width: 6px; height: 6px; background: var(--success); border-radius: 50%; }
.main { flex: 1; overflow-y: auto; } .main { flex: 1; overflow-y: auto; }
#claude-content { padding: 2rem; min-height: 100%; } #frame-content { padding: 2rem; min-height: 100%; }
.indicator-bar { .indicator-bar {
background: var(--bg-secondary); background: var(--bg-secondary);
@@ -201,7 +201,7 @@
</div> </div>
<div class="main"> <div class="main">
<div id="claude-content"> <div id="frame-content">
<!-- CONTENT --> <!-- CONTENT -->
</div> </div>
</div> </div>

View File

@@ -76,8 +76,10 @@ function decodeFrame(buffer) {
const PORT = process.env.BRAINSTORM_PORT || (49152 + Math.floor(Math.random() * 16383)); const PORT = process.env.BRAINSTORM_PORT || (49152 + Math.floor(Math.random() * 16383));
const HOST = process.env.BRAINSTORM_HOST || '127.0.0.1'; const HOST = process.env.BRAINSTORM_HOST || '127.0.0.1';
const URL_HOST = process.env.BRAINSTORM_URL_HOST || (HOST === '127.0.0.1' ? 'localhost' : HOST); const URL_HOST = process.env.BRAINSTORM_URL_HOST || (HOST === '127.0.0.1' ? 'localhost' : HOST);
const SCREEN_DIR = process.env.BRAINSTORM_DIR || '/tmp/brainstorm'; const SESSION_DIR = process.env.BRAINSTORM_DIR || '/tmp/brainstorm';
const OWNER_PID = process.env.BRAINSTORM_OWNER_PID ? Number(process.env.BRAINSTORM_OWNER_PID) : null; const CONTENT_DIR = path.join(SESSION_DIR, 'content');
const STATE_DIR = path.join(SESSION_DIR, 'state');
let ownerPid = process.env.BRAINSTORM_OWNER_PID ? Number(process.env.BRAINSTORM_OWNER_PID) : null;
const MIME_TYPES = { const MIME_TYPES = {
'.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript',
@@ -112,10 +114,10 @@ function wrapInFrame(content) {
} }
function getNewestScreen() { function getNewestScreen() {
const files = fs.readdirSync(SCREEN_DIR) const files = fs.readdirSync(CONTENT_DIR)
.filter(f => f.endsWith('.html')) .filter(f => f.endsWith('.html'))
.map(f => { .map(f => {
const fp = path.join(SCREEN_DIR, f); const fp = path.join(CONTENT_DIR, f);
return { path: fp, mtime: fs.statSync(fp).mtime.getTime() }; return { path: fp, mtime: fs.statSync(fp).mtime.getTime() };
}) })
.sort((a, b) => b.mtime - a.mtime); .sort((a, b) => b.mtime - a.mtime);
@@ -142,7 +144,7 @@ function handleRequest(req, res) {
res.end(html); res.end(html);
} else if (req.method === 'GET' && req.url.startsWith('/files/')) { } else if (req.method === 'GET' && req.url.startsWith('/files/')) {
const fileName = req.url.slice(7); const fileName = req.url.slice(7);
const filePath = path.join(SCREEN_DIR, path.basename(fileName)); const filePath = path.join(CONTENT_DIR, path.basename(fileName));
if (!fs.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
res.writeHead(404); res.writeHead(404);
res.end('Not found'); res.end('Not found');
@@ -230,7 +232,7 @@ function handleMessage(text) {
touchActivity(); touchActivity();
console.log(JSON.stringify({ source: 'user-event', ...event })); console.log(JSON.stringify({ source: 'user-event', ...event }));
if (event.choice) { if (event.choice) {
const eventsFile = path.join(SCREEN_DIR, '.events'); const eventsFile = path.join(STATE_DIR, 'events');
fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n'); fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n');
} }
} }
@@ -258,32 +260,33 @@ const debounceTimers = new Map();
// ========== Server Startup ========== // ========== Server Startup ==========
function startServer() { function startServer() {
if (!fs.existsSync(SCREEN_DIR)) fs.mkdirSync(SCREEN_DIR, { recursive: true }); if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true });
if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true });
// Track known files to distinguish new screens from updates. // Track known files to distinguish new screens from updates.
// macOS fs.watch reports 'rename' for both new files and overwrites, // macOS fs.watch reports 'rename' for both new files and overwrites,
// so we can't rely on eventType alone. // so we can't rely on eventType alone.
const knownFiles = new Set( const knownFiles = new Set(
fs.readdirSync(SCREEN_DIR).filter(f => f.endsWith('.html')) fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html'))
); );
const server = http.createServer(handleRequest); const server = http.createServer(handleRequest);
server.on('upgrade', handleUpgrade); server.on('upgrade', handleUpgrade);
const watcher = fs.watch(SCREEN_DIR, (eventType, filename) => { const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => {
if (!filename || !filename.endsWith('.html')) return; if (!filename || !filename.endsWith('.html')) return;
if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename)); if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename));
debounceTimers.set(filename, setTimeout(() => { debounceTimers.set(filename, setTimeout(() => {
debounceTimers.delete(filename); debounceTimers.delete(filename);
const filePath = path.join(SCREEN_DIR, filename); const filePath = path.join(CONTENT_DIR, filename);
if (!fs.existsSync(filePath)) return; // file was deleted if (!fs.existsSync(filePath)) return; // file was deleted
touchActivity(); touchActivity();
if (!knownFiles.has(filename)) { if (!knownFiles.has(filename)) {
knownFiles.add(filename); knownFiles.add(filename);
const eventsFile = path.join(SCREEN_DIR, '.events'); const eventsFile = path.join(STATE_DIR, 'events');
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
console.log(JSON.stringify({ type: 'screen-added', file: filePath })); console.log(JSON.stringify({ type: 'screen-added', file: filePath }));
} else { } else {
@@ -297,10 +300,10 @@ function startServer() {
function shutdown(reason) { function shutdown(reason) {
console.log(JSON.stringify({ type: 'server-stopped', reason })); console.log(JSON.stringify({ type: 'server-stopped', reason }));
const infoFile = path.join(SCREEN_DIR, '.server-info'); const infoFile = path.join(STATE_DIR, 'server-info');
if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile); if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile);
fs.writeFileSync( fs.writeFileSync(
path.join(SCREEN_DIR, '.server-stopped'), path.join(STATE_DIR, 'server-stopped'),
JSON.stringify({ reason, timestamp: Date.now() }) + '\n' JSON.stringify({ reason, timestamp: Date.now() }) + '\n'
); );
watcher.close(); watcher.close();
@@ -309,8 +312,8 @@ function startServer() {
} }
function ownerAlive() { function ownerAlive() {
if (!OWNER_PID) return true; if (!ownerPid) return true;
try { process.kill(OWNER_PID, 0); return true; } catch (e) { return false; } try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; }
} }
// Check every 60s: exit if owner process died or idle for 30 minutes // Check every 60s: exit if owner process died or idle for 30 minutes
@@ -320,14 +323,27 @@ function startServer() {
}, 60 * 1000); }, 60 * 1000);
lifecycleCheck.unref(); lifecycleCheck.unref();
// Validate owner PID at startup. If it's already dead, the PID resolution
// was wrong (common on WSL, Tailscale SSH, and cross-user scenarios).
// Disable monitoring and rely on the idle timeout instead.
if (ownerPid) {
try { process.kill(ownerPid, 0); }
catch (e) {
if (e.code !== 'EPERM') {
console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' }));
ownerPid = null;
}
}
}
server.listen(PORT, HOST, () => { server.listen(PORT, HOST, () => {
const info = JSON.stringify({ const info = JSON.stringify({
type: 'server-started', port: Number(PORT), host: HOST, type: 'server-started', port: Number(PORT), host: HOST,
url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT, url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT,
screen_dir: SCREEN_DIR screen_dir: CONTENT_DIR, state_dir: STATE_DIR
}); });
console.log(info); console.log(info);
fs.writeFileSync(path.join(SCREEN_DIR, '.server-info'), info + '\n'); fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n');
}); });
} }

View File

@@ -78,16 +78,17 @@ fi
SESSION_ID="$$-$(date +%s)" SESSION_ID="$$-$(date +%s)"
if [[ -n "$PROJECT_DIR" ]]; then if [[ -n "$PROJECT_DIR" ]]; then
SCREEN_DIR="${PROJECT_DIR}/.superpowers/brainstorm/${SESSION_ID}" SESSION_DIR="${PROJECT_DIR}/.superpowers/brainstorm/${SESSION_ID}"
else else
SCREEN_DIR="/tmp/brainstorm-${SESSION_ID}" SESSION_DIR="/tmp/brainstorm-${SESSION_ID}"
fi fi
PID_FILE="${SCREEN_DIR}/.server.pid" STATE_DIR="${SESSION_DIR}/state"
LOG_FILE="${SCREEN_DIR}/.server.log" PID_FILE="${STATE_DIR}/server.pid"
LOG_FILE="${STATE_DIR}/server.log"
# Create fresh session directory # Create fresh session directory with content and state peers
mkdir -p "$SCREEN_DIR" mkdir -p "${SESSION_DIR}/content" "$STATE_DIR"
# Kill any existing server # Kill any existing server
if [[ -f "$PID_FILE" ]]; then if [[ -f "$PID_FILE" ]]; then
@@ -106,22 +107,16 @@ if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then
OWNER_PID="$PPID" OWNER_PID="$PPID"
fi fi
# On Windows/MSYS2, the MSYS2 PID namespace is invisible to Node.js.
# Skip owner-PID monitoring — the 30-minute idle timeout prevents orphans.
case "${OSTYPE:-}" in
msys*|cygwin*|mingw*) OWNER_PID="" ;;
esac
# Foreground mode for environments that reap detached/background processes. # Foreground mode for environments that reap detached/background processes.
if [[ "$FOREGROUND" == "true" ]]; then if [[ "$FOREGROUND" == "true" ]]; then
echo "$$" > "$PID_FILE" echo "$$" > "$PID_FILE"
env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs env BRAINSTORM_DIR="$SESSION_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs
exit $? exit $?
fi fi
# Start server, capturing output to log file # Start server, capturing output to log file
# Use nohup to survive shell exit; disown to remove from job table # Use nohup to survive shell exit; disown to remove from job table
nohup env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 & nohup env BRAINSTORM_DIR="$SESSION_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 &
SERVER_PID=$! SERVER_PID=$!
disown "$SERVER_PID" 2>/dev/null disown "$SERVER_PID" 2>/dev/null
echo "$SERVER_PID" > "$PID_FILE" echo "$SERVER_PID" > "$PID_FILE"

View File

@@ -1,19 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Stop the brainstorm server and clean up # Stop the brainstorm server and clean up
# Usage: stop-server.sh <screen_dir> # Usage: stop-server.sh <session_dir>
# #
# Kills the server process. Only deletes session directory if it's # Kills the server process. Only deletes session directory if it's
# under /tmp (ephemeral). Persistent directories (.superpowers/) are # under /tmp (ephemeral). Persistent directories (.superpowers/) are
# kept so mockups can be reviewed later. # kept so mockups can be reviewed later.
SCREEN_DIR="$1" SESSION_DIR="$1"
if [[ -z "$SCREEN_DIR" ]]; then if [[ -z "$SESSION_DIR" ]]; then
echo '{"error": "Usage: stop-server.sh <screen_dir>"}' echo '{"error": "Usage: stop-server.sh <session_dir>"}'
exit 1 exit 1
fi fi
PID_FILE="${SCREEN_DIR}/.server.pid" STATE_DIR="${SESSION_DIR}/state"
PID_FILE="${STATE_DIR}/server.pid"
if [[ -f "$PID_FILE" ]]; then if [[ -f "$PID_FILE" ]]; then
pid=$(cat "$PID_FILE") pid=$(cat "$PID_FILE")
@@ -42,11 +43,11 @@ if [[ -f "$PID_FILE" ]]; then
exit 1 exit 1
fi fi
rm -f "$PID_FILE" "${SCREEN_DIR}/.server.log" rm -f "$PID_FILE" "${STATE_DIR}/server.log"
# Only delete ephemeral /tmp directories # Only delete ephemeral /tmp directories
if [[ "$SCREEN_DIR" == /tmp/* ]]; then if [[ "$SESSION_DIR" == /tmp/* ]]; then
rm -rf "$SCREEN_DIR" rm -rf "$SESSION_DIR"
fi fi
echo '{"status": "stopped"}' echo '{"status": "stopped"}'

View File

@@ -7,7 +7,7 @@ Use this template when dispatching a spec document reviewer subagent.
**Dispatch after:** Spec document is written to docs/superpowers/specs/ **Dispatch after:** Spec document is written to docs/superpowers/specs/
``` ```
Task tool (general-purpose): Subagent (general-purpose):
description: "Review spec document" description: "Review spec document"
prompt: | prompt: |
You are a spec document reviewer. Verify this spec is complete and ready for planning. You are a spec document reviewer. Verify this spec is complete and ready for planning.

View File

@@ -26,7 +26,7 @@ A question *about* a UI topic is not automatically a visual question. "What kind
## How It Works ## How It Works
The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content, the user sees it in their browser and can click to select options. Selections are recorded to a `.events` file that you read on your next turn. The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn.
**Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, selection indicator, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page. **Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, selection indicator, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page.
@@ -37,31 +37,25 @@ The server watches a directory for HTML files and serves the newest one to the b
scripts/start-server.sh --project-dir /path/to/project scripts/start-server.sh --project-dir /path/to/project
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341", # Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
# "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000"} # "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/content",
# "state_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/state"}
``` ```
Save `screen_dir` from the response. Tell user to open the URL. Save `screen_dir` and `state_dir` from the response. Tell user to open the URL.
**Finding connection info:** The server writes its startup JSON to `$SCREEN_DIR/.server-info`. If you launched the server in the background and didn't capture stdout, read that file to get the URL and port. When using `--project-dir`, check `<project>/.superpowers/brainstorm/` for the session directory. **Finding connection info:** The server writes its startup JSON to `$STATE_DIR/server-info`. If you launched the server in the background and didn't capture stdout, read that file to get the URL and port. When using `--project-dir`, check `<project>/.superpowers/brainstorm/` for the session directory.
**Note:** Pass the project root as `--project-dir` so mockups persist in `.superpowers/brainstorm/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. Remind the user to add `.superpowers/` to `.gitignore` if it's not already there. **Note:** Pass the project root as `--project-dir` so mockups persist in `.superpowers/brainstorm/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. Remind the user to add `.superpowers/` to `.gitignore` if it's not already there.
**Launching the server by platform:** **Launching the server by platform:**
**Claude Code (macOS / Linux):** **Claude Code:**
```bash ```bash
# Default mode works — the script backgrounds the server itself # Default mode works — the script backgrounds the server itself.
scripts/start-server.sh --project-dir /path/to/project scripts/start-server.sh --project-dir /path/to/project
``` ```
**Claude Code (Windows):** On Windows, the script auto-detects and switches to foreground mode (which blocks the tool call). Use `run_in_background: true` on the Bash tool call so the server survives across conversation turns, then read `$STATE_DIR/server-info` on the next turn to get the URL and port.
```bash
# Windows auto-detects and uses foreground mode, which blocks the tool call.
# Use run_in_background: true on the Bash tool call so the server survives
# across conversation turns.
scripts/start-server.sh --project-dir /path/to/project
```
When calling this via the Bash tool, set `run_in_background: true`. Then read `$SCREEN_DIR/.server-info` on the next turn to get the URL and port.
**Codex:** **Codex:**
```bash ```bash
@@ -77,6 +71,14 @@ scripts/start-server.sh --project-dir /path/to/project
scripts/start-server.sh --project-dir /path/to/project --foreground scripts/start-server.sh --project-dir /path/to/project --foreground
``` ```
**Copilot CLI:**
```bash
# Use --foreground and start the server via the bash tool with mode: "async"
# so the process survives across turns. Capture the returned shellId for
# read_bash / stop_bash if you need to interact with it later.
scripts/start-server.sh --project-dir /path/to/project --foreground
```
**Other environments:** The server must keep running in the background across conversation turns. If your environment reaps detached processes, use `--foreground` and launch the command with your platform's background execution mechanism. **Other environments:** The server must keep running in the background across conversation turns. If your environment reaps detached processes, use `--foreground` and launch the command with your platform's background execution mechanism.
If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host: If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host:
@@ -93,10 +95,10 @@ Use `--url-host` to control what hostname is printed in the returned URL JSON.
## The Loop ## The Loop
1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`: 1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`:
- Before each write, check that `$SCREEN_DIR/.server-info` exists. If it doesn't (or `.server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity. - Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity.
- Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html` - Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html`
- **Never reuse filenames** — each screen gets a fresh file - **Never reuse filenames** — each screen gets a fresh file
- Use Write tool — **never use cat/heredoc** (dumps noise into terminal) - Use your file-creation tool — **never use cat/heredoc** (dumps noise into terminal)
- Server automatically serves the newest file - Server automatically serves the newest file
2. **Tell user what to expect and end your turn:** 2. **Tell user what to expect and end your turn:**
@@ -105,9 +107,9 @@ Use `--url-host` to control what hostname is printed in the returned URL JSON.
- Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like." - Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like."
3. **On your next turn** — after the user responds in the terminal: 3. **On your next turn** — after the user responds in the terminal:
- Read `$SCREEN_DIR/.events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines - Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines
- Merge with the user's terminal text to get the full picture - Merge with the user's terminal text to get the full picture
- The terminal message is the primary feedback; `.events` provides structured interaction data - The terminal message is the primary feedback; `state_dir/events` provides structured interaction data
4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated. 4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated.
@@ -244,7 +246,7 @@ The frame template provides these CSS classes for your content:
## Browser Events Format ## Browser Events Format
When the user clicks options in the browser, their interactions are recorded to `$SCREEN_DIR/.events` (one JSON object per line). The file is cleared automatically when you push a new screen. When the user clicks options in the browser, their interactions are recorded to `$STATE_DIR/events` (one JSON object per line). The file is cleared automatically when you push a new screen.
```jsonl ```jsonl
{"type":"click","choice":"a","text":"Option A - Simple Layout","timestamp":1706000101} {"type":"click","choice":"a","text":"Option A - Simple Layout","timestamp":1706000101}
@@ -254,7 +256,7 @@ When the user clicks options in the browser, their interactions are recorded to
The full event stream shows the user's exploration path — they may click multiple options before settling. The last `choice` event is typically the final selection, but the pattern of clicks can reveal hesitation or preferences worth asking about. The full event stream shows the user's exploration path — they may click multiple options before settling. The last `choice` event is typically the final selection, but the pattern of clicks can reveal hesitation or preferences worth asking about.
If `.events` doesn't exist, the user didn't interact with the browser — use only their terminal text. If `$STATE_DIR/events` doesn't exist, the user didn't interact with the browser — use only their terminal text.
## Design Tips ## Design Tips
@@ -275,7 +277,7 @@ If `.events` doesn't exist, the user didn't interact with the browser — use on
## Cleaning Up ## Cleaning Up
```bash ```bash
scripts/stop-server.sh $SCREEN_DIR scripts/stop-server.sh $SESSION_DIR
``` ```
If the session used `--project-dir`, mockup files persist in `.superpowers/brainstorm/` for later reference. Only `/tmp` sessions get deleted on stop. If the session used `--project-dir`, mockup files persist in `.superpowers/brainstorm/` for later reference. Only `/tmp` sessions get deleted on stop.

View File

@@ -65,14 +65,17 @@ Each agent gets:
### 3. Dispatch in Parallel ### 3. Dispatch in Parallel
```typescript Issue all three subagent dispatches in the same response — they run in parallel:
// In Claude Code / AI environment
Task("Fix agent-tool-abort.test.ts failures") ```text
Task("Fix batch-completion-behavior.test.ts failures") Subagent (general-purpose): "Fix agent-tool-abort.test.ts failures"
Task("Fix tool-approval-race-conditions.test.ts failures") Subagent (general-purpose): "Fix batch-completion-behavior.test.ts failures"
// All three run concurrently Subagent (general-purpose): "Fix tool-approval-race-conditions.test.ts failures"
# All three run concurrently.
``` ```
Multiple dispatch calls in one response = parallel execution. One per response = sequential.
### 4. Review and Integrate ### 4. Review and Integrate
When agents return: When agents return:

View File

@@ -11,7 +11,7 @@ Load plan, review critically, execute all tasks, report when complete.
**Announce at start:** "I'm using the executing-plans skill to implement this plan." **Announce at start:** "I'm using the executing-plans skill to implement this plan."
**Note:** Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (such as Claude Code or Codex). If subagents are available, use superpowers:subagent-driven-development instead of this skill. **Note:** Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (Claude Code, Codex CLI, Codex App, Copilot CLI, and Gemini CLI all qualify; see the per-platform tool refs in `../using-superpowers/references/`). If subagents are available, use superpowers:subagent-driven-development instead of this skill.
## The Process ## The Process
@@ -19,7 +19,7 @@ Load plan, review critically, execute all tasks, report when complete.
1. Read plan file 1. Read plan file
2. Review critically - identify any questions or concerns about the plan 2. Review critically - identify any questions or concerns about the plan
3. If concerns: Raise them with your human partner before starting 3. If concerns: Raise them with your human partner before starting
4. If no concerns: Create TodoWrite and proceed 4. If no concerns: Create todos for the plan items and proceed
### Step 2: Execute Tasks ### Step 2: Execute Tasks
@@ -65,6 +65,6 @@ After all tasks complete and verified:
## Integration ## Integration
**Required workflow skills:** **Required workflow skills:**
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting - **superpowers:using-git-worktrees** - Ensures isolated workspace (creates one or verifies existing)
- **superpowers:writing-plans** - Creates the plan this skill executes - **superpowers:writing-plans** - Creates the plan this skill executes
- **superpowers:finishing-a-development-branch** - Complete development after all tasks - **superpowers:finishing-a-development-branch** - Complete development after all tasks

View File

@@ -9,7 +9,7 @@ description: Use when implementation is complete, all tests pass, and you need t
Guide completion of development work by presenting clear options and handling chosen workflow. Guide completion of development work by presenting clear options and handling chosen workflow.
**Core principle:** Verify tests → Present options → Execute choice → Clean up. **Core principle:** Verify tests → Detect environment → Present options → Execute choice → Clean up.
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work." **Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
@@ -37,7 +37,24 @@ Stop. Don't proceed to Step 2.
**If tests pass:** Continue to Step 2. **If tests pass:** Continue to Step 2.
### Step 2: Determine Base Branch ### Step 2: Detect Environment
**Determine workspace state before presenting options:**
```bash
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
```
This determines which menu to show and how cleanup works:
| State | Menu | Cleanup |
|-------|------|---------|
| `GIT_DIR == GIT_COMMON` (normal repo) | Standard 4 options | No worktree to clean up |
| `GIT_DIR != GIT_COMMON`, named branch | Standard 4 options | Provenance-based (see Step 6) |
| `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced 3 options (no merge) | No cleanup (externally managed) |
### Step 3: Determine Base Branch
```bash ```bash
# Try common base branches # Try common base branches
@@ -46,9 +63,9 @@ git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
Or ask: "This branch split from main - is that correct?" Or ask: "This branch split from main - is that correct?"
### Step 3: Present Options ### Step 4: Present Options
Present exactly these 4 options: **Normal repo and named-branch worktree — present exactly these 4 options:**
``` ```
Implementation complete. What would you like to do? Implementation complete. What would you like to do?
@@ -61,30 +78,45 @@ Implementation complete. What would you like to do?
Which option? Which option?
``` ```
**Detached HEAD — present exactly these 3 options:**
```
Implementation complete. You're on a detached HEAD (externally managed workspace).
1. Push as new branch and create a Pull Request
2. Keep as-is (I'll handle it later)
3. Discard this work
Which option?
```
**Don't add explanation** - keep options concise. **Don't add explanation** - keep options concise.
### Step 4: Execute Choice ### Step 5: Execute Choice
#### Option 1: Merge Locally #### Option 1: Merge Locally
```bash ```bash
# Switch to base branch # Get main repo root for CWD safety
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
# Merge first — verify success before removing anything
git checkout <base-branch> git checkout <base-branch>
# Pull latest
git pull git pull
# Merge feature branch
git merge <feature-branch> git merge <feature-branch>
# Verify tests on merged result # Verify tests on merged result
<test command> <test command>
# If tests pass # Only after merge succeeds: cleanup worktree (Step 6), then delete branch
git branch -d <feature-branch>
``` ```
Then: Cleanup worktree (Step 5) Then: Cleanup worktree (Step 6), then delete branch:
```bash
git branch -d <feature-branch>
```
#### Option 2: Push and Create PR #### Option 2: Push and Create PR
@@ -103,7 +135,7 @@ EOF
)" )"
``` ```
Then: Cleanup worktree (Step 5) **Do NOT clean up worktree** — user needs it alive to iterate on PR feedback.
#### Option 3: Keep As-Is #### Option 3: Keep As-Is
@@ -127,36 +159,46 @@ Wait for exact confirmation.
If confirmed: If confirmed:
```bash ```bash
git checkout <base-branch> MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
```
Then: Cleanup worktree (Step 6), then force-delete branch:
```bash
git branch -D <feature-branch> git branch -D <feature-branch>
``` ```
Then: Cleanup worktree (Step 5) ### Step 6: Cleanup Workspace
### Step 5: Cleanup Worktree **Only runs for Options 1 and 4.** Options 2 and 3 always preserve the worktree.
**For Options 1, 2, 4:**
Check if in worktree:
```bash ```bash
git worktree list | grep $(git branch --show-current) GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
WORKTREE_PATH=$(git rev-parse --show-toplevel)
``` ```
If yes: **If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
**If worktree path is under `.worktrees/` or `worktrees/`:** Superpowers created this worktree — we own cleanup.
```bash ```bash
git worktree remove <worktree-path> MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
cd "$MAIN_ROOT"
git worktree remove "$WORKTREE_PATH"
git worktree prune # Self-healing: clean up any stale registrations
``` ```
**For Option 3:** Keep worktree. **Otherwise:** The host environment (harness) owns this workspace. Do NOT remove it. If your platform provides a workspace-exit tool, use it. Otherwise, leave the workspace in place.
## Quick Reference ## Quick Reference
| Option | Merge | Push | Keep Worktree | Cleanup Branch | | Option | Merge | Push | Keep Worktree | Cleanup Branch |
|--------|-------|------|---------------|----------------| |--------|-------|------|---------------|----------------|
| 1. Merge locally | | - | - | | | 1. Merge locally | yes | - | - | yes |
| 2. Create PR | - | ✓ | ✓ | - | | 2. Create PR | - | yes | yes | - |
| 3. Keep as-is | - | - | | - | | 3. Keep as-is | - | - | yes | - |
| 4. Discard | - | - | - | (force) | | 4. Discard | - | - | - | yes (force) |
## Common Mistakes ## Common Mistakes
@@ -165,13 +207,25 @@ git worktree remove <worktree-path>
- **Fix:** Always verify tests before offering options - **Fix:** Always verify tests before offering options
**Open-ended questions** **Open-ended questions**
- **Problem:** "What should I do next?" ambiguous - **Problem:** "What should I do next?" is ambiguous
- **Fix:** Present exactly 4 structured options - **Fix:** Present exactly 4 structured options (or 3 for detached HEAD)
**Automatic worktree cleanup** **Cleaning up worktree for Option 2**
- **Problem:** Remove worktree when might need it (Option 2, 3) - **Problem:** Remove worktree user needs for PR iteration
- **Fix:** Only cleanup for Options 1 and 4 - **Fix:** Only cleanup for Options 1 and 4
**Deleting branch before removing worktree**
- **Problem:** `git branch -d` fails because worktree still references the branch
- **Fix:** Merge first, remove worktree, then delete branch
**Running git worktree remove from inside the worktree**
- **Problem:** Command fails silently when CWD is inside the worktree being removed
- **Fix:** Always `cd` to main repo root before `git worktree remove`
**Cleaning up harness-owned worktrees**
- **Problem:** Removing a worktree the harness created causes phantom state
- **Fix:** Only clean up worktrees under `.worktrees/` or `worktrees/`
**No confirmation for discard** **No confirmation for discard**
- **Problem:** Accidentally delete work - **Problem:** Accidentally delete work
- **Fix:** Require typed "discard" confirmation - **Fix:** Require typed "discard" confirmation
@@ -183,18 +237,15 @@ git worktree remove <worktree-path>
- Merge without verifying tests on result - Merge without verifying tests on result
- Delete work without confirmation - Delete work without confirmation
- Force-push without explicit request - Force-push without explicit request
- Remove a worktree before confirming merge success
- Clean up worktrees you didn't create (provenance check)
- Run `git worktree remove` from inside the worktree
**Always:** **Always:**
- Verify tests before offering options - Verify tests before offering options
- Present exactly 4 options - Detect environment before presenting menu
- Present exactly 4 options (or 3 for detached HEAD)
- Get typed confirmation for Option 4 - Get typed confirmation for Option 4
- Clean up worktree for Options 1 & 4 only - Clean up worktree for Options 1 & 4 only
- `cd` to main repo root before worktree removal
## Integration - Run `git worktree prune` after removal
**Called by:**
- **subagent-driven-development** (Step 7) - After all tasks complete
- **executing-plans** (Step 5) - After all batches complete
**Pairs with:**
- **using-git-worktrees** - Cleans up worktree created by that skill

View File

@@ -27,7 +27,7 @@ WHEN receiving code review feedback:
## Forbidden Responses ## Forbidden Responses
**NEVER:** **NEVER:**
- "You're absolutely right!" (explicit CLAUDE.md violation) - "You're absolutely right!" (explicit instruction-file violation)
- "Great point!" / "Excellent feedback!" (performative) - "Great point!" / "Excellent feedback!" (performative)
- "Let me implement that now" (before verification) - "Let me implement that now" (before verification)
@@ -126,7 +126,7 @@ Push back when:
- Reference working tests/code - Reference working tests/code
- Involve your human partner if architectural - Involve your human partner if architectural
**Signal if uncomfortable pushing back out loud:** "Strange things are afoot at the Circle K" **If you're uncomfortable pushing back out loud:** Name that tension, then tell your partner about the issue you've seen. They'll appreciate your honesty.
## Acknowledging Correct Feedback ## Acknowledging Correct Feedback

View File

@@ -5,7 +5,7 @@ description: Use when completing tasks, implementing major features, or before m
# Requesting Code Review # Requesting Code Review
Dispatch superpowers:code-reviewer subagent to catch issues before they cascade. The reviewer gets precisely crafted context for evaluation — never your session's history. This keeps the reviewer focused on the work product, not your thought process, and preserves your own context for continued work. Dispatch a code reviewer subagent to catch issues before they cascade. The reviewer gets precisely crafted context for evaluation — never your session's history. This keeps the reviewer focused on the work product, not your thought process, and preserves your own context for continued work.
**Core principle:** Review early, review often. **Core principle:** Review early, review often.
@@ -29,16 +29,15 @@ BASE_SHA=$(git rev-parse HEAD~1) # or origin/main
HEAD_SHA=$(git rev-parse HEAD) HEAD_SHA=$(git rev-parse HEAD)
``` ```
**2. Dispatch code-reviewer subagent:** **2. Dispatch code reviewer subagent:**
Use Task tool with superpowers:code-reviewer type, fill template at `code-reviewer.md` Dispatch a `general-purpose` subagent, filling the template at [code-reviewer.md](code-reviewer.md)
**Placeholders:** **Placeholders:**
- `{WHAT_WAS_IMPLEMENTED}` - What you just built - `{DESCRIPTION}` - Brief summary of what you built
- `{PLAN_OR_REQUIREMENTS}` - What it should do - `{PLAN_OR_REQUIREMENTS}` - What it should do
- `{BASE_SHA}` - Starting commit - `{BASE_SHA}` - Starting commit
- `{HEAD_SHA}` - Ending commit - `{HEAD_SHA}` - Ending commit
- `{DESCRIPTION}` - Brief summary
**3. Act on feedback:** **3. Act on feedback:**
- Fix Critical issues immediately - Fix Critical issues immediately
@@ -56,12 +55,11 @@ You: Let me request code review before proceeding.
BASE_SHA=$(git log --oneline | grep "Task 1" | head -1 | awk '{print $1}') BASE_SHA=$(git log --oneline | grep "Task 1" | head -1 | awk '{print $1}')
HEAD_SHA=$(git rev-parse HEAD) HEAD_SHA=$(git rev-parse HEAD)
[Dispatch superpowers:code-reviewer subagent] [Dispatch code reviewer subagent]
WHAT_WAS_IMPLEMENTED: Verification and repair functions for conversation index DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types
PLAN_OR_REQUIREMENTS: Task 2 from docs/superpowers/plans/deployment-plan.md PLAN_OR_REQUIREMENTS: Task 2 from docs/superpowers/plans/deployment-plan.md
BASE_SHA: a7981ec BASE_SHA: a7981ec
HEAD_SHA: 3df7661 HEAD_SHA: 3df7661
DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types
[Subagent returns]: [Subagent returns]:
Strengths: Clean architecture, real tests Strengths: Clean architecture, real tests
@@ -82,7 +80,7 @@ You: [Fix progress indicators]
- Fix before moving to next task - Fix before moving to next task
**Executing Plans:** **Executing Plans:**
- Review after each batch (3 tasks) - Review after each task or at natural checkpoints
- Get feedback, apply, continue - Get feedback, apply, continue
**Ad-Hoc Development:** **Ad-Hoc Development:**
@@ -102,4 +100,4 @@ You: [Fix progress indicators]
- Show code/tests that prove it works - Show code/tests that prove it works
- Request clarification - Request clarification
See template at: requesting-code-review/code-reviewer.md See template at: [code-reviewer.md](code-reviewer.md)

View File

@@ -1,111 +1,133 @@
# Code Review Agent # Code Reviewer Prompt Template
You are reviewing code changes for production readiness. Use this template when dispatching a code reviewer subagent.
**Your task:** **Purpose:** Review completed work against requirements and code quality standards before it cascades into more work.
1. Review {WHAT_WAS_IMPLEMENTED}
2. Compare against {PLAN_OR_REQUIREMENTS}
3. Check code quality, architecture, testing
4. Categorize issues by severity
5. Assess production readiness
## What Was Implemented ```
Subagent (general-purpose):
description: "Review code changes"
prompt: |
You are a Senior Code Reviewer with expertise in software architecture,
design patterns, and best practices. Your job is to review completed work
against its plan or requirements and identify issues before they cascade.
{DESCRIPTION} ## What Was Implemented
## Requirements/Plan {DESCRIPTION}
{PLAN_REFERENCE} ## Requirements / Plan
## Git Range to Review {PLAN_OR_REQUIREMENTS}
**Base:** {BASE_SHA} ## Git Range to Review
**Head:** {HEAD_SHA}
```bash **Base:** {BASE_SHA}
git diff --stat {BASE_SHA}..{HEAD_SHA} **Head:** {HEAD_SHA}
git diff {BASE_SHA}..{HEAD_SHA}
```bash
git diff --stat {BASE_SHA}..{HEAD_SHA}
git diff {BASE_SHA}..{HEAD_SHA}
```
## What to Check
**Plan alignment:**
- Does the implementation match the plan / requirements?
- Are deviations justified improvements, or problematic departures?
- Is all planned functionality present?
**Code quality:**
- Clean separation of concerns?
- Proper error handling?
- Type safety where applicable?
- DRY without premature abstraction?
- Edge cases handled?
**Architecture:**
- Sound design decisions?
- Reasonable scalability and performance?
- Security concerns?
- Integrates cleanly with surrounding code?
**Testing:**
- Tests verify real behavior, not mocks?
- Edge cases covered?
- Integration tests where they matter?
- All tests passing?
**Production readiness:**
- Migration strategy if schema changed?
- Backward compatibility considered?
- Documentation complete?
- No obvious bugs?
## Calibration
Categorize issues by actual severity. Not everything is Critical.
Acknowledge what was done well before listing issues — accurate praise
helps the implementer trust the rest of the feedback.
If you find significant deviations from the plan, flag them specifically
so the implementer can confirm whether the deviation was intentional.
If you find issues with the plan itself rather than the implementation,
say so.
## Output Format
### Strengths
[What's well done? Be specific.]
### Issues
#### Critical (Must Fix)
[Bugs, security issues, data loss risks, broken functionality]
#### Important (Should Fix)
[Architecture problems, missing features, poor error handling, test gaps]
#### Minor (Nice to Have)
[Code style, optimization opportunities, documentation polish]
For each issue:
- File:line reference
- What's wrong
- Why it matters
- How to fix (if not obvious)
### Recommendations
[Improvements for code quality, architecture, or process]
### Assessment
**Ready to merge?** [Yes | No | With fixes]
**Reasoning:** [1-2 sentence technical assessment]
## Critical Rules
**DO:**
- Categorize by actual severity
- Be specific (file:line, not vague)
- Explain WHY each issue matters
- Acknowledge strengths
- Give a clear verdict
**DON'T:**
- Say "looks good" without checking
- Mark nitpicks as Critical
- Give feedback on code you didn't actually read
- Be vague ("improve error handling")
- Avoid giving a clear verdict
``` ```
## Review Checklist **Placeholders:**
- `{DESCRIPTION}` — brief summary of what was built
- `{PLAN_OR_REQUIREMENTS}` — what it should do (plan file path, task text, or requirements)
- `{BASE_SHA}` — starting commit
- `{HEAD_SHA}` — ending commit
**Code Quality:** **Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment
- Clean separation of concerns?
- Proper error handling?
- Type safety (if applicable)?
- DRY principle followed?
- Edge cases handled?
**Architecture:**
- Sound design decisions?
- Scalability considerations?
- Performance implications?
- Security concerns?
**Testing:**
- Tests actually test logic (not mocks)?
- Edge cases covered?
- Integration tests where needed?
- All tests passing?
**Requirements:**
- All plan requirements met?
- Implementation matches spec?
- No scope creep?
- Breaking changes documented?
**Production Readiness:**
- Migration strategy (if schema changes)?
- Backward compatibility considered?
- Documentation complete?
- No obvious bugs?
## Output Format
### Strengths
[What's well done? Be specific.]
### Issues
#### Critical (Must Fix)
[Bugs, security issues, data loss risks, broken functionality]
#### Important (Should Fix)
[Architecture problems, missing features, poor error handling, test gaps]
#### Minor (Nice to Have)
[Code style, optimization opportunities, documentation improvements]
**For each issue:**
- File:line reference
- What's wrong
- Why it matters
- How to fix (if not obvious)
### Recommendations
[Improvements for code quality, architecture, or process]
### Assessment
**Ready to merge?** [Yes/No/With fixes]
**Reasoning:** [Technical assessment in 1-2 sentences]
## Critical Rules
**DO:**
- Categorize by actual severity (not everything is Critical)
- Be specific (file:line, not vague)
- Explain WHY issues matter
- Acknowledge strengths
- Give clear verdict
**DON'T:**
- Say "looks good" without checking
- Mark nitpicks as Critical
- Give feedback on code you didn't review
- Be vague ("improve error handling")
- Avoid giving a clear verdict
## Example Output ## Example Output

View File

@@ -11,6 +11,8 @@ Execute plan by dispatching fresh subagent per task, with two-stage review after
**Core principle:** Fresh subagent per task + two-stage review (spec then quality) = high quality, fast iteration **Core principle:** Fresh subagent per task + two-stage review (spec then quality) = high quality, fast iteration
**Continuous execution:** Do not pause to check in with your human partner between tasks. Execute all tasks from the plan without stopping. The only reasons to stop are: BLOCKED status you cannot resolve, ambiguity that genuinely prevents progress, or all tasks complete. "Should I continue?" prompts and progress summaries waste their time — they asked you to execute the plan, so execute it.
## When to Use ## When to Use
```dot ```dot
@@ -55,15 +57,15 @@ digraph process {
"Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [shape=box]; "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [shape=box];
"Code quality reviewer subagent approves?" [shape=diamond]; "Code quality reviewer subagent approves?" [shape=diamond];
"Implementer subagent fixes quality issues" [shape=box]; "Implementer subagent fixes quality issues" [shape=box];
"Mark task complete in TodoWrite" [shape=box]; "Mark task complete in todo list" [shape=box];
} }
"Read plan, extract all tasks with full text, note context, create TodoWrite" [shape=box]; "Read plan, extract all tasks with full text, note context, create todos" [shape=box];
"More tasks remain?" [shape=diamond]; "More tasks remain?" [shape=diamond];
"Dispatch final code reviewer subagent for entire implementation" [shape=box]; "Dispatch final code reviewer subagent for entire implementation" [shape=box];
"Use superpowers:finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen]; "Use superpowers:finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen];
"Read plan, extract all tasks with full text, note context, create TodoWrite" -> "Dispatch implementer subagent (./implementer-prompt.md)"; "Read plan, extract all tasks with full text, note context, create todos" -> "Dispatch implementer subagent (./implementer-prompt.md)";
"Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer subagent asks questions?"; "Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer subagent asks questions?";
"Implementer subagent asks questions?" -> "Answer questions, provide context" [label="yes"]; "Implementer subagent asks questions?" -> "Answer questions, provide context" [label="yes"];
"Answer questions, provide context" -> "Dispatch implementer subagent (./implementer-prompt.md)"; "Answer questions, provide context" -> "Dispatch implementer subagent (./implementer-prompt.md)";
@@ -76,8 +78,8 @@ digraph process {
"Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" -> "Code quality reviewer subagent approves?"; "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" -> "Code quality reviewer subagent approves?";
"Code quality reviewer subagent approves?" -> "Implementer subagent fixes quality issues" [label="no"]; "Code quality reviewer subagent approves?" -> "Implementer subagent fixes quality issues" [label="no"];
"Implementer subagent fixes quality issues" -> "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [label="re-review"]; "Implementer subagent fixes quality issues" -> "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [label="re-review"];
"Code quality reviewer subagent approves?" -> "Mark task complete in TodoWrite" [label="yes"]; "Code quality reviewer subagent approves?" -> "Mark task complete in todo list" [label="yes"];
"Mark task complete in TodoWrite" -> "More tasks remain?"; "Mark task complete in todo list" -> "More tasks remain?";
"More tasks remain?" -> "Dispatch implementer subagent (./implementer-prompt.md)" [label="yes"]; "More tasks remain?" -> "Dispatch implementer subagent (./implementer-prompt.md)" [label="yes"];
"More tasks remain?" -> "Dispatch final code reviewer subagent for entire implementation" [label="no"]; "More tasks remain?" -> "Dispatch final code reviewer subagent for entire implementation" [label="no"];
"Dispatch final code reviewer subagent for entire implementation" -> "Use superpowers:finishing-a-development-branch"; "Dispatch final code reviewer subagent for entire implementation" -> "Use superpowers:finishing-a-development-branch";
@@ -119,9 +121,9 @@ Implementer subagents report one of four statuses. Handle each appropriately:
## Prompt Templates ## Prompt Templates
- `./implementer-prompt.md` - Dispatch implementer subagent - [implementer-prompt.md](implementer-prompt.md) - Dispatch implementer subagent
- `./spec-reviewer-prompt.md` - Dispatch spec compliance reviewer subagent - [spec-reviewer-prompt.md](spec-reviewer-prompt.md) - Dispatch spec compliance reviewer subagent
- `./code-quality-reviewer-prompt.md` - Dispatch code quality reviewer subagent - [code-quality-reviewer-prompt.md](code-quality-reviewer-prompt.md) - Dispatch code quality reviewer subagent
## Example Workflow ## Example Workflow
@@ -130,7 +132,7 @@ You: I'm using Subagent-Driven Development to execute this plan.
[Read plan file once: docs/superpowers/plans/feature-plan.md] [Read plan file once: docs/superpowers/plans/feature-plan.md]
[Extract all 5 tasks with full text and context] [Extract all 5 tasks with full text and context]
[Create TodoWrite with all tasks] [Create todos for all tasks]
Task 1: Hook installation script Task 1: Hook installation script
@@ -265,7 +267,7 @@ Done!
## Integration ## Integration
**Required workflow skills:** **Required workflow skills:**
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting - **superpowers:using-git-worktrees** - Ensures isolated workspace (creates one or verifies existing)
- **superpowers:writing-plans** - Creates the plan this skill executes - **superpowers:writing-plans** - Creates the plan this skill executes
- **superpowers:requesting-code-review** - Code review template for reviewer subagents - **superpowers:requesting-code-review** - Code review template for reviewer subagents
- **superpowers:finishing-a-development-branch** - Complete development after all tasks - **superpowers:finishing-a-development-branch** - Complete development after all tasks

View File

@@ -7,14 +7,13 @@ Use this template when dispatching a code quality reviewer subagent.
**Only dispatch after spec compliance review passes.** **Only dispatch after spec compliance review passes.**
``` ```
Task tool (superpowers:code-reviewer): Subagent (general-purpose):
Use template at requesting-code-review/code-reviewer.md Use template at ../requesting-code-review/code-reviewer.md
WHAT_WAS_IMPLEMENTED: [from implementer's report] DESCRIPTION: [task summary, from implementer's report]
PLAN_OR_REQUIREMENTS: Task N from [plan-file] PLAN_OR_REQUIREMENTS: Task N from [plan-file]
BASE_SHA: [commit before task] BASE_SHA: [commit before task]
HEAD_SHA: [current commit] HEAD_SHA: [current commit]
DESCRIPTION: [task summary]
``` ```
**In addition to standard code quality concerns, the reviewer should check:** **In addition to standard code quality concerns, the reviewer should check:**

View File

@@ -3,7 +3,7 @@
Use this template when dispatching an implementer subagent. Use this template when dispatching an implementer subagent.
``` ```
Task tool (general-purpose): Subagent (general-purpose):
description: "Implement Task N: [task name]" description: "Implement Task N: [task name]"
prompt: | prompt: |
You are implementing Task N: [task name] You are implementing Task N: [task name]

View File

@@ -5,7 +5,7 @@ Use this template when dispatching a spec compliance reviewer subagent.
**Purpose:** Verify implementer built what was requested (nothing more, nothing less) **Purpose:** Verify implementer built what was requested (nothing more, nothing less)
``` ```
Task tool (general-purpose): Subagent (general-purpose):
description: "Review spec compliance for Task N" description: "Review spec compliance for Task N"
prompt: | prompt: |
You are reviewing whether an implementation matches its specification. You are reviewing whether an implementation matches its specification.

View File

@@ -4,7 +4,7 @@ Reference example of extracting, structuring, and bulletproofing a critical skil
## Source Material ## Source Material
Extracted debugging framework from `/Users/jesse/.claude/CLAUDE.md`: Extracted debugging framework from `~/.claude/CLAUDE.md`:
- 4-phase systematic process (Investigation → Pattern Analysis → Hypothesis → Implementation) - 4-phase systematic process (Investigation → Pattern Analysis → Hypothesis → Implementation)
- Core mandate: ALWAYS find root cause, NEVER fix symptoms - Core mandate: ALWAYS find root cause, NEVER fix symptoms
- Rules designed to resist time pressure and rationalization - Rules designed to resist time pressure and rationalization

View File

@@ -33,7 +33,7 @@ digraph when_to_use {
### 1. Observe the Symptom ### 1. Observe the Symptom
``` ```
Error: git init failed in /Users/jesse/project/packages/core Error: git init failed in ~/project/packages/core
``` ```
### 2. Find Immediate Cause ### 2. Find Immediate Cause

View File

@@ -356,7 +356,7 @@ Never fix bugs without a test.
## Testing Anti-Patterns ## Testing Anti-Patterns
When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls: When adding mocks or test utilities, read [testing-anti-patterns.md](testing-anti-patterns.md) to avoid common pitfalls:
- Testing mock behavior instead of real behavior - Testing mock behavior instead of real behavior
- Adding test-only methods to production classes - Adding test-only methods to production classes
- Mocking without understanding dependencies - Mocking without understanding dependencies

View File

@@ -1,104 +1,105 @@
--- ---
name: using-git-worktrees name: using-git-worktrees
description: Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification description: Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback
--- ---
# Using Git Worktrees # Using Git Worktrees
## Overview ## Overview
Git worktrees create isolated workspaces sharing the same repository, allowing work on multiple branches simultaneously without switching. Ensure work happens in an isolated workspace. Prefer your platform's native worktree tools. Fall back to manual git worktrees only when no native tool is available.
**Core principle:** Systematic directory selection + safety verification = reliable isolation. **Core principle:** Detect existing isolation first. Then use native tools. Then fall back to git. Never fight the harness.
**Announce at start:** "I'm using the using-git-worktrees skill to set up an isolated workspace." **Announce at start:** "I'm using the using-git-worktrees skill to set up an isolated workspace."
## Directory Selection Process ## Step 0: Detect Existing Isolation
Follow this priority order: **Before creating anything, check if you are already in an isolated workspace.**
### 1. Check Existing Directories
```bash ```bash
# Check in priority order GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
ls -d .worktrees 2>/dev/null # Preferred (hidden) GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
ls -d worktrees 2>/dev/null # Alternative BRANCH=$(git branch --show-current)
``` ```
**If found:** Use that directory. If both exist, `.worktrees` wins. **Submodule guard:** `GIT_DIR != GIT_COMMON` is also true inside git submodules. Before concluding "already in a worktree," verify you are not in a submodule:
### 2. Check CLAUDE.md
```bash ```bash
grep -i "worktree.*director" CLAUDE.md 2>/dev/null # If this returns a path, you're in a submodule, not a worktree — treat as normal repo
git rev-parse --show-superproject-working-tree 2>/dev/null
``` ```
**If preference specified:** Use it without asking. **If `GIT_DIR != GIT_COMMON` (and not a submodule):** You are already in a linked worktree. Skip to Step 2 (Project Setup). Do NOT create another worktree.
### 3. Ask User Report with branch state:
- On a branch: "Already in isolated workspace at `<path>` on branch `<name>`."
- Detached HEAD: "Already in isolated workspace at `<path>` (detached HEAD, externally managed). Branch creation needed at finish time."
If no directory exists and no CLAUDE.md preference: **If `GIT_DIR == GIT_COMMON` (or in a submodule):** You are in a normal repo checkout.
``` Has the user already indicated their worktree preference in your instructions? If not, ask for consent before creating a worktree:
No worktree directory found. Where should I create worktrees?
1. .worktrees/ (project-local, hidden) > "Would you like me to set up an isolated worktree? It protects your current branch from changes."
2. ~/.config/superpowers/worktrees/<project-name>/ (global location)
Which would you prefer? Honor any existing declared preference without asking. If the user declines consent, work in place and skip to Step 2.
```
## Safety Verification ## Step 1: Create Isolated Workspace
### For Project-Local Directories (.worktrees or worktrees) **You have two mechanisms. Try them in this order.**
### 1a. Native Worktree Tools (preferred)
The user has asked for an isolated workspace (Step 0 consent). Do you already have a way to create a worktree? It might be a tool with a name like `EnterWorktree`, `WorktreeCreate`, a `/worktree` command, or a `--worktree` flag. If you do, use it and skip to Step 2.
Native tools handle directory placement, branch creation, and cleanup automatically. Using `git worktree add` when you have a native tool creates phantom state your harness can't see or manage.
Only proceed to Step 1b if you have no native worktree tool available.
### 1b. Git Worktree Fallback
**Only use this if Step 1a does not apply** — you have no native worktree tool available. Create a worktree manually using git.
#### Directory Selection
Follow this priority order. Explicit user preference always beats observed filesystem state.
1. **Check your instructions for a declared worktree directory preference.** If the user has already specified one, use it without asking.
2. **Check for an existing project-local worktree directory:**
```bash
ls -d .worktrees 2>/dev/null # Preferred (hidden)
ls -d worktrees 2>/dev/null # Alternative
```
If found, use it. If both exist, `.worktrees` wins.
3. **If there is no other guidance available**, default to `.worktrees/` at the project root.
#### Safety Verification (project-local directories only)
**MUST verify directory is ignored before creating worktree:** **MUST verify directory is ignored before creating worktree:**
```bash ```bash
# Check if directory is ignored (respects local, global, and system gitignore)
git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/dev/null git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/dev/null
``` ```
**If NOT ignored:** **If NOT ignored:** Add to .gitignore, commit the change, then proceed.
Per Jesse's rule "Fix broken things immediately":
1. Add appropriate line to .gitignore
2. Commit the change
3. Proceed with worktree creation
**Why critical:** Prevents accidentally committing worktree contents to repository. **Why critical:** Prevents accidentally committing worktree contents to repository.
### For Global Directory (~/.config/superpowers/worktrees) #### Create the Worktree
No .gitignore verification needed - outside project entirely.
## Creation Steps
### 1. Detect Project Name
```bash ```bash
project=$(basename "$(git rev-parse --show-toplevel)") # Determine path based on chosen location
``` path="$LOCATION/$BRANCH_NAME"
### 2. Create Worktree
```bash
# Determine full path
case $LOCATION in
.worktrees|worktrees)
path="$LOCATION/$BRANCH_NAME"
;;
~/.config/superpowers/worktrees/*)
path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME"
;;
esac
# Create worktree with new branch
git worktree add "$path" -b "$BRANCH_NAME" git worktree add "$path" -b "$BRANCH_NAME"
cd "$path" cd "$path"
``` ```
### 3. Run Project Setup **Sandbox fallback:** If `git worktree add` fails with a permission error (sandbox denial), tell the user the sandbox blocked worktree creation and you're working in the current directory instead. Then run setup and baseline tests in place.
## Step 2: Project Setup
Auto-detect and run appropriate setup: Auto-detect and run appropriate setup:
@@ -117,23 +118,20 @@ if [ -f pyproject.toml ]; then poetry install; fi
if [ -f go.mod ]; then go mod download; fi if [ -f go.mod ]; then go mod download; fi
``` ```
### 4. Verify Clean Baseline ## Step 3: Verify Clean Baseline
Run tests to ensure worktree starts clean: Run tests to ensure workspace starts clean:
```bash ```bash
# Examples - use project-appropriate command # Use project-appropriate command
npm test npm test / cargo test / pytest / go test ./...
cargo test
pytest
go test ./...
``` ```
**If tests fail:** Report failures, ask whether to proceed or investigate. **If tests fail:** Report failures, ask whether to proceed or investigate.
**If tests pass:** Report ready. **If tests pass:** Report ready.
### 5. Report Location ### Report
``` ```
Worktree ready at <full-path> Worktree ready at <full-path>
@@ -145,16 +143,31 @@ Ready to implement <feature-name>
| Situation | Action | | Situation | Action |
|-----------|--------| |-----------|--------|
| Already in linked worktree | Skip creation (Step 0) |
| In a submodule | Treat as normal repo (Step 0 guard) |
| Native worktree tool available | Use it (Step 1a) |
| No native tool | Git worktree fallback (Step 1b) |
| `.worktrees/` exists | Use it (verify ignored) | | `.worktrees/` exists | Use it (verify ignored) |
| `worktrees/` exists | Use it (verify ignored) | | `worktrees/` exists | Use it (verify ignored) |
| Both exist | Use `.worktrees/` | | Both exist | Use `.worktrees/` |
| Neither exists | Check CLAUDE.md → Ask user | | Neither exists | Check instruction file, then default `.worktrees/` |
| Directory not ignored | Add to .gitignore + commit | | Directory not ignored | Add to .gitignore + commit |
| Permission error on create | Sandbox fallback, work in place |
| Tests fail during baseline | Report failures + ask | | Tests fail during baseline | Report failures + ask |
| No package.json/Cargo.toml | Skip dependency install | | No package.json/Cargo.toml | Skip dependency install |
## Common Mistakes ## Common Mistakes
### Fighting the harness
- **Problem:** Using `git worktree add` when the platform already provides isolation
- **Fix:** Step 0 detects existing isolation. Step 1a defers to native tools.
### Skipping detection
- **Problem:** Creating a nested worktree inside an existing one
- **Fix:** Always run Step 0 before creating anything
### Skipping ignore verification ### Skipping ignore verification
- **Problem:** Worktree contents get tracked, pollute git status - **Problem:** Worktree contents get tracked, pollute git status
@@ -163,56 +176,27 @@ Ready to implement <feature-name>
### Assuming directory location ### Assuming directory location
- **Problem:** Creates inconsistency, violates project conventions - **Problem:** Creates inconsistency, violates project conventions
- **Fix:** Follow priority: existing > CLAUDE.md > ask - **Fix:** Follow priority: explicit instructions > existing project-local directory > default
### Proceeding with failing tests ### Proceeding with failing tests
- **Problem:** Can't distinguish new bugs from pre-existing issues - **Problem:** Can't distinguish new bugs from pre-existing issues
- **Fix:** Report failures, get explicit permission to proceed - **Fix:** Report failures, get explicit permission to proceed
### Hardcoding setup commands
- **Problem:** Breaks on projects using different tools
- **Fix:** Auto-detect from project files (package.json, etc.)
## Example Workflow
```
You: I'm using the using-git-worktrees skill to set up an isolated workspace.
[Check .worktrees/ - exists]
[Verify ignored - git check-ignore confirms .worktrees/ is ignored]
[Create worktree: git worktree add .worktrees/auth -b feature/auth]
[Run npm install]
[Run npm test - 47 passing]
Worktree ready at /Users/jesse/myproject/.worktrees/auth
Tests passing (47 tests, 0 failures)
Ready to implement auth feature
```
## Red Flags ## Red Flags
**Never:** **Never:**
- Create a worktree when Step 0 detects existing isolation
- Use `git worktree add` when you have a native worktree tool (e.g., `EnterWorktree`). This is the #1 mistake — if you have it, use it.
- Skip Step 1a by jumping straight to Step 1b's git commands
- Create worktree without verifying it's ignored (project-local) - Create worktree without verifying it's ignored (project-local)
- Skip baseline test verification - Skip baseline test verification
- Proceed with failing tests without asking - Proceed with failing tests without asking
- Assume directory location when ambiguous
- Skip CLAUDE.md check
**Always:** **Always:**
- Follow directory priority: existing > CLAUDE.md > ask - Run Step 0 detection first
- Prefer native tools over git fallback
- Follow directory priority: explicit instructions > existing project-local directory > default
- Verify directory is ignored for project-local - Verify directory is ignored for project-local
- Auto-detect and run project setup - Auto-detect and run project setup
- Verify clean test baseline - Verify clean test baseline
## Integration
**Called by:**
- **brainstorming** (Phase 4) - REQUIRED when design is approved and implementation follows
- **subagent-driven-development** - REQUIRED before executing any tasks
- **executing-plans** - REQUIRED before executing any tasks
- Any skill needing isolated workspace
**Pairs with:**
- **finishing-a-development-branch** - REQUIRED for cleanup after work complete

View File

@@ -1,6 +1,6 @@
--- ---
name: using-superpowers name: using-superpowers
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions description: Use when starting any conversation - establishes how to find and use skills, requiring skill invocation before ANY response including clarifying questions
--- ---
<SUBAGENT-STOP> <SUBAGENT-STOP>
@@ -27,7 +27,13 @@ If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "alw
## How to Access Skills ## How to Access Skills
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files. **Never read skill files manually with file tools** — always use your platform's skill-loading mechanism so the skill is properly activated.
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you — follow it directly.
**In Codex:** Skills load natively. Follow the instructions presented when a skill activates.
**In Copilot CLI:** Use the `skill` tool. Skills are auto-discovered from installed plugins.
**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand. **In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.
@@ -35,7 +41,7 @@ If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "alw
## Platform Adaptation ## Platform Adaptation
Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools.md` (Codex) for tool equivalents. Gemini CLI users get the tool mapping loaded automatically via GEMINI.md. Skills speak in actions ("dispatch a subagent", "create a todo", "read a file") rather than naming any one runtime's tools. For per-platform tool equivalents and instructions-file conventions, see [claude-code-tools.md](references/claude-code-tools.md), [codex-tools.md](references/codex-tools.md), [copilot-tools.md](references/copilot-tools.md), [gemini-tools.md](references/gemini-tools.md), and [pi-tools.md](references/pi-tools.md). Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
# Using Skills # Using Skills
@@ -46,30 +52,30 @@ Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools
```dot ```dot
digraph skill_flow { digraph skill_flow {
"User message received" [shape=doublecircle]; "User message received" [shape=doublecircle];
"About to EnterPlanMode?" [shape=doublecircle]; "About to enter plan mode?" [shape=doublecircle];
"Already brainstormed?" [shape=diamond]; "Already brainstormed?" [shape=diamond];
"Invoke brainstorming skill" [shape=box]; "Invoke brainstorming skill" [shape=box];
"Might any skill apply?" [shape=diamond]; "Might any skill apply?" [shape=diamond];
"Invoke Skill tool" [shape=box]; "Invoke the skill" [shape=box];
"Announce: 'Using [skill] to [purpose]'" [shape=box]; "Announce: 'Using [skill] to [purpose]'" [shape=box];
"Has checklist?" [shape=diamond]; "Has checklist?" [shape=diamond];
"Create TodoWrite todo per item" [shape=box]; "Create a todo per item" [shape=box];
"Follow skill exactly" [shape=box]; "Follow skill exactly" [shape=box];
"Respond (including clarifications)" [shape=doublecircle]; "Respond (including clarifications)" [shape=doublecircle];
"About to EnterPlanMode?" -> "Already brainstormed?"; "About to enter plan mode?" -> "Already brainstormed?";
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"]; "Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
"Already brainstormed?" -> "Might any skill apply?" [label="yes"]; "Already brainstormed?" -> "Might any skill apply?" [label="yes"];
"Invoke brainstorming skill" -> "Might any skill apply?"; "Invoke brainstorming skill" -> "Might any skill apply?";
"User message received" -> "Might any skill apply?"; "User message received" -> "Might any skill apply?";
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"]; "Might any skill apply?" -> "Invoke the skill" [label="yes, even 1%"];
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"]; "Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
"Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'"; "Invoke the skill" -> "Announce: 'Using [skill] to [purpose]'";
"Announce: 'Using [skill] to [purpose]'" -> "Has checklist?"; "Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
"Has checklist?" -> "Create TodoWrite todo per item" [label="yes"]; "Has checklist?" -> "Create a todo per item" [label="yes"];
"Has checklist?" -> "Follow skill exactly" [label="no"]; "Has checklist?" -> "Follow skill exactly" [label="no"];
"Create TodoWrite todo per item" -> "Follow skill exactly"; "Create a todo per item" -> "Follow skill exactly";
} }
``` ```
@@ -96,15 +102,15 @@ These thoughts mean STOP—you're rationalizing:
When multiple skills could apply, use this order: When multiple skills could apply, use this order:
1. **Process skills first** (brainstorming, debugging) - these determine HOW to approach the task 1. **Process skills first** (brainstorming, systematic-debugging) - these determine HOW to approach the task
2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution 2. **Implementation skills second** (frontend-design, mcp-builder) - these guide execution
"Let's build X" → brainstorming first, then implementation skills. "Let's build X" → brainstorming first, then implementation skills.
"Fix this bug" → debugging first, then domain-specific skills. "Fix this bug" → systematic-debugging first, then domain-specific skills.
## Skill Types ## Skill Types
**Rigid** (TDD, debugging): Follow exactly. Don't adapt away discipline. **Rigid** (TDD, systematic-debugging): Follow exactly. Don't adapt away discipline.
**Flexible** (patterns): Adapt principles to context. **Flexible** (patterns): Adapt principles to context.

View File

@@ -0,0 +1,50 @@
# Claude Code Tool Mapping
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Claude Code these resolve to the tools below.
## Tools
| Action skills request | Claude Code tool |
|----------------------|------------------|
| Read a file | `Read` |
| Create a new file | `Write` |
| Edit a file | `Edit` |
| Run a shell command | `Bash` |
| Search file contents | `Grep` |
| Find files by name | `Glob` |
| Fetch a URL | `WebFetch` |
| Search the web | `WebSearch` |
| Invoke a skill | `Skill` |
| Dispatch a subagent (`Subagent (general-purpose):` template) | `Agent` (older releases named this `Task`) |
| Multiple parallel dispatches | Multiple `Agent` calls in one response |
| Task tracking ("create a todo", "mark complete") | `TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`; `TodoWrite` in `claude -p` / Agent SDK unless `CLAUDE_CODE_ENABLE_TASKS=1` is set |
| Background-process / subagent lifecycle (read output, cancel) | `TaskOutput`, `TaskStop` — these are distinct from the todo tools above and apply to running shells, agents, and remote sessions |
## Instructions file
When a skill mentions "your instructions file", on Claude Code this is **`CLAUDE.md`**. Claude Code walks up the directory tree from the current working directory and concatenates every `CLAUDE.md` and `CLAUDE.local.md` it finds along the way. Standard locations:
| Scope | Location |
|-------|----------|
| Project (team-shared) | `./CLAUDE.md` or `./.claude/CLAUDE.md` |
| User global | `~/.claude/CLAUDE.md` |
| Local-private (gitignored) | `./CLAUDE.local.md` |
| Managed policy (org-wide) | `/Library/Application Support/ClaudeCode/CLAUDE.md` (macOS), `/etc/claude-code/CLAUDE.md` (Linux/WSL), `C:\Program Files\ClaudeCode\CLAUDE.md` (Windows) |
CLAUDE.md files can pull in additional content with `@path/to/file` imports (relative or absolute, max five hops deep). Subdirectory `CLAUDE.md` files are also discovered automatically and loaded on-demand when Claude Code reads files in those subdirectories.
Claude Code does **not** read `AGENTS.md` directly. If a project already maintains `AGENTS.md` for other agents, import it from `CLAUDE.md` so both runtimes share the same instructions:
```markdown
@AGENTS.md
## Claude Code
(Claude-Code-specific instructions go here.)
```
For path-scoped rules and larger-project organization, see `.claude/rules/` (rules can be scoped to specific files via `paths` frontmatter and load on demand).
## Personal skills directory
User-level skills live at **`~/.claude/skills/`**. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter) plus any supporting files. Claude Code does not currently recognize the cross-runtime `~/.agents/skills/` path that Codex, Copilot CLI, and Gemini CLI read; if you're relying on cross-runtime support in the future, verify against the [official skills docs](https://code.claude.com/docs/en/skills).

View File

@@ -1,17 +1,30 @@
# Codex Tool Mapping # Codex Tool Mapping
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent: Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Codex these resolve to the tools below.
| Skill references | Codex equivalent | | Action skills request | Codex equivalent |
|-----------------|------------------| |----------------------|------------------|
| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) | | Read a file | `shell` (e.g., `cat`, `head`, `tail`) — Codex reads files via shell |
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls | | Create / edit / delete a file | `apply_patch` (structured diff for create, update, delete) |
| Task returns result | `wait` | | Run a shell command | `shell` |
| Task completes automatically | `close_agent` to free slot | | Search file contents | `shell` (e.g., `grep`, `rg`) |
| `TodoWrite` (task tracking) | `update_plan` | | Find files by name | `shell` (e.g., `find`, `ls`) |
| `Skill` tool (invoke a skill) | Skills load natively — just follow the instructions | | Fetch a URL | `shell` with `curl` / `wget` — Codex has no native fetch tool |
| `Read`, `Write`, `Edit` (files) | Use your native file tools | | Search the web | `web_search` (enabled by default; configurable in `config.toml` via the top-level `web_search` setting — `live`, `cached`, or `disabled`) |
| `Bash` (run commands) | Use your native shell tools | | Invoke a skill | Skills load natively — just follow the instructions |
| Dispatch a subagent (`Subagent (general-purpose):` template) | `spawn_agent` (see [Subagent dispatch requires multi-agent support](#subagent-dispatch-requires-multi-agent-support)) |
| Multiple parallel dispatches | Multiple `spawn_agent` calls in one response |
| Wait for subagent result | `wait_agent` |
| Free up subagent slot when done | `close_agent` |
| Task tracking ("create a todo", "mark complete") | `update_plan` |
## Instructions file
When a skill mentions "your instructions file", on Codex this is **`AGENTS.md`** at the project root. Codex also reads `~/.codex/AGENTS.md` for global context, and an `AGENTS.override.md` (in the project tree or `~/.codex/`) takes precedence when present. Codex walks from the project root down to the current working directory, concatenating `AGENTS.md` files it finds along the way, up to `project_doc_max_bytes` (32 KiB by default).
## Personal skills directory
User-level skills live at **`$CODEX_HOME/skills/`** (default `~/.codex/skills/`). Codex also reads the cross-runtime path **`~/.agents/skills/`** (shared with Copilot CLI and Gemini CLI). When both directories exist at the same scope, Codex loads them both as separate skill catalogs — Codex's docs don't currently document a precedence between them. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
## Subagent dispatch requires multi-agent support ## Subagent dispatch requires multi-agent support
@@ -22,53 +35,12 @@ Add to your Codex config (`~/.codex/config.toml`):
multi_agent = true multi_agent = true
``` ```
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`. This enables `spawn_agent`, `wait_agent`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
## Named agent dispatch Legacy note: Codex builds before `rust-v0.115.0` exposed spawned-agent
waiting as `wait`. Current Codex uses `wait_agent` for spawned agents. The
Claude Code skills reference named agent types like `superpowers:code-reviewer`. `wait` name now belongs to code-mode `exec/wait`, which resumes a yielded exec
Codex does not have a named agent registry — `spawn_agent` creates generic agents cell by `cell_id`; it is not the spawned-agent result tool.
from built-in roles (`default`, `explorer`, `worker`).
When a skill says to dispatch a named agent type:
1. Find the agent's prompt file (e.g., `agents/code-reviewer.md` or the skill's
local prompt template like `code-quality-reviewer-prompt.md`)
2. Read the prompt content
3. Fill any template placeholders (`{BASE_SHA}`, `{WHAT_WAS_IMPLEMENTED}`, etc.)
4. Spawn a `worker` agent with the filled content as the `message`
| Skill instruction | Codex equivalent |
|-------------------|------------------|
| `Task tool (superpowers:code-reviewer)` | `spawn_agent(agent_type="worker", message=...)` with `code-reviewer.md` content |
| `Task tool (general-purpose)` with inline prompt | `spawn_agent(message=...)` with the same prompt |
### Message framing
The `message` parameter is user-level input, not a system prompt. Structure it
for maximum instruction adherence:
```
Your task is to perform the following. Follow the instructions below exactly.
<agent-instructions>
[filled prompt content from the agent's .md file]
</agent-instructions>
Execute this now. Output ONLY the structured response following the format
specified in the instructions above.
```
- Use task-delegation framing ("Your task is...") rather than persona framing ("You are...")
- Wrap instructions in XML tags — the model treats tagged blocks as authoritative
- End with an explicit execution directive to prevent summarization of the instructions
### When this workaround can be removed
This approach compensates for Codex's plugin system not yet supporting an `agents`
field in `plugin.json`. When `RawPluginManifest` gains an `agents` field, the
plugin can symlink to `agents/` (mirroring the existing `skills/` symlink) and
skills can dispatch named agent types directly.
## Environment Detection ## Environment Detection

View File

@@ -0,0 +1,49 @@
# Copilot CLI Tool Mapping
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Copilot CLI these resolve to the tools below.
| Action skills request | Copilot CLI equivalent |
|----------------------|----------------------|
| Read a file | `view` |
| Create / edit / delete a file | `apply_patch` (Copilot CLI has no separate create/edit/write tools) |
| Run a shell command | `bash` |
| Search file contents | `rg` (ripgrep; Copilot CLI does not expose a `grep` tool) |
| Find files by name | `glob` |
| Fetch a URL | `web_fetch` |
| Search the web | `web_search` |
| Invoke a skill | `skill` |
| Dispatch a subagent (`Subagent (general-purpose):` template) | `task` with `agent_type: "general-purpose"` (other accepted types: `explore`, `task`, `code-review`, `research`, `configure-copilot`) |
| Multiple parallel dispatches | Multiple `task` calls in one response |
| Subagent status/output/control | `read_agent`, `list_agents`, `write_agent` |
| Task tracking ("create a todo", "mark complete") | `update_todo` |
| Enter / exit plan mode | No equivalent — stay in the main session |
## Instructions file
When a skill mentions "your instructions file", on Copilot CLI this is **`AGENTS.md`** at the repository root. If both `AGENTS.md` and `.github/copilot-instructions.md` are present, Copilot reads both.
## Personal skills directory
User-level skills live at **`~/.copilot/skills/`**. Copilot CLI also recognizes the cross-runtime alias **`~/.agents/skills/`**, which is shared with Codex and Gemini CLI. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
## Async shell sessions
Copilot CLI supports persistent async shell sessions:
| Tool | Purpose |
|------|---------|
| `bash` with `mode: "async"` (and optionally `detach: true`) | Start a long-running command in the background; returns a `shellId` |
| `write_bash` | Send input to a running async session |
| `read_bash` | Read output from an async session |
| `stop_bash` | Terminate an async session |
| `list_bash` | List all active shell sessions |
## Additional Copilot CLI tools
| Tool | Purpose |
|------|---------|
| `store_memory` | Persist facts about the codebase for future sessions |
| `report_intent` | Update the UI status line with current intent |
| `sql` | Query the session's SQLite database (todos, metadata) |
| `fetch_copilot_cli_documentation` | Look up Copilot CLI documentation |
| GitHub MCP tools (`github-mcp-server-*`) | Native GitHub API access (issues, PRs, code search) |

View File

@@ -1,33 +1,63 @@
# Gemini CLI Tool Mapping # Gemini CLI Tool Mapping
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent: Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Gemini CLI these resolve to the tools below.
| Skill references | Gemini CLI equivalent | | Action skills request | Gemini CLI equivalent |
|-----------------|----------------------| |----------------------|----------------------|
| `Read` (file reading) | `read_file` | | Read a file | `read_file` |
| `Write` (file creation) | `write_file` | | Read multiple files at once | `read_many_files` |
| `Edit` (file editing) | `replace` | | Create a new file | `write_file` |
| `Bash` (run commands) | `run_shell_command` | | Edit a file | `replace` |
| `Grep` (search file content) | `grep_search` | | Run a shell command | `run_shell_command` |
| `Glob` (search files by name) | `glob` | | Search file contents | `grep_search` |
| `TodoWrite` (task tracking) | `write_todos` | | Find files by name | `glob` |
| `Skill` tool (invoke a skill) | `activate_skill` | | List files and subdirectories | `list_directory` |
| `WebSearch` | `google_web_search` | | Fetch a URL | `web_fetch` |
| `WebFetch` | `web_fetch` | | Search the web | `google_web_search` |
| `Task` tool (dispatch subagent) | No equivalent — Gemini CLI does not support subagents | | Invoke a skill | `activate_skill` |
| Dispatch a subagent (`Subagent (general-purpose):` template) | `invoke_agent` with `agent_name: "generalist"` (invocable via `@generalist` chat syntax — see [Subagent support](#subagent-support)) |
| Multiple parallel dispatches | Multiple `invoke_agent` calls in the same response |
| Task tracking ("create a todo", "mark complete") | `write_todos` (statuses: pending, in_progress, completed, cancelled, blocked) |
## No subagent support ## Instructions file
Gemini CLI has no equivalent to Claude Code's `Task` tool. Skills that rely on subagent dispatch (`subagent-driven-development`, `dispatching-parallel-agents`) will fall back to single-session execution via `executing-plans`. When a skill mentions "your instructions file", on Gemini CLI this is **`GEMINI.md`**. Gemini CLI loads `GEMINI.md` hierarchically: global at `~/.gemini/GEMINI.md`, project-level files in workspace directories and their ancestors, and sub-directory `GEMINI.md` files when a tool accesses files in those directories.
## Personal skills directory
User-level skills live at **`~/.gemini/skills/`**, with **`~/.agents/skills/`** as a cross-runtime alias (shared with Codex and Copilot CLI). When both directories exist at the same scope, `.agents/skills/` takes precedence. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
## Subagent support
Gemini CLI dispatches subagents through the `invoke_agent` tool, which takes `agent_name` and `prompt` parameters. The same dispatch is also surfaced as a chat-syntax shortcut: typing `@generalist <prompt>` is equivalent to calling `invoke_agent` with `agent_name: "generalist"`. Built-in agent names include `generalist`, `cli_help`, `codebase_investigator`, and (with browser tooling enabled) `browser_agent`.
Skills dispatch with `Subagent (general-purpose):` and either reference a prompt-template file (e.g., `superpowers:subagent-driven-development`'s `./implementer-prompt.md`) or supply an inline prompt. On Gemini CLI:
| Skill dispatch form | Gemini CLI equivalent |
|---------------------|----------------------|
| References a `*-prompt.md` template (implementer, spec-reviewer, code-quality-reviewer, code-reviewer, etc.) | Fill the template, then `invoke_agent` with `agent_name: "generalist"` and the filled prompt |
| References `superpowers:requesting-code-review`'s `./code-reviewer.md` | `invoke_agent` with `agent_name: "generalist"` and the filled review template |
| Inline prompt (no template referenced) | `invoke_agent` with `agent_name: "generalist"` and your inline prompt |
### Prompt filling
Skills provide prompt templates with placeholders like `{WHAT_WAS_IMPLEMENTED}` or `[FULL TEXT of task]`. Fill all placeholders before passing the complete prompt to `invoke_agent`. The prompt template itself contains the agent's role, review criteria, and expected output format — the subagent will follow it.
### Parallel dispatch
Gemini CLI supports parallel subagent dispatch. Issue multiple `invoke_agent` calls in the same response (or multiple `@generalist` invocations in one prompt) to run independent subagent work in parallel. Keep dependent tasks sequential, but do not serialize independent subagent tasks just to preserve a simpler history.
## Additional Gemini CLI tools ## Additional Gemini CLI tools
These tools are available in Gemini CLI but have no Claude Code equivalent: These tools are unique to Gemini CLI:
| Tool | Purpose | | Tool | Purpose |
|------|---------| |------|---------|
| `list_directory` | List files and subdirectories | | `save_memory` (legacy) | Persist facts across sessions when `experimental.memoryV2 = false` |
| `save_memory` | Persist facts to GEMINI.md across sessions | | `get_internal_docs` | Look up Gemini CLI's bundled documentation |
| `ask_user` | Request structured input from the user | | `ask_user` | Pose structured questions to the user (text / single-select / multi-select) |
| `tracker_create_task` | Rich task management (create, update, list, visualize) | | `enter_plan_mode` / `exit_plan_mode` | Switch into and out of read-only plan mode |
| `enter_plan_mode` / `exit_plan_mode` | Switch to read-only research mode before making changes | | `update_topic` | Update the current conversation's topic / strategic-intent metadata |
| `complete_task` | Signal that a Gemini subagent has completed and return its result to the parent agent |
| `tracker_create_task`, `tracker_update_task`, `tracker_get_task`, `tracker_list_tasks`, `tracker_add_dependency`, `tracker_visualize` | Rich task tracker with dependency and visualization support |
| `read_mcp_resource`, `list_mcp_resources` | MCP resource access |

View File

@@ -0,0 +1,28 @@
# Pi Tool Mapping
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Pi these resolve to the tools below.
| Action skills request | Pi equivalent |
| --- | --- |
| Invoke a skill | Pi native skills: load the relevant `SKILL.md` with `read`, or let the human use `/skill:name` |
| Read a file | `read` |
| Create a file | `write` |
| Edit a file | `edit` |
| Run a shell command | `bash` |
| Search file contents | `grep` when active; otherwise `bash` with `rg`/`grep` |
| Find files by name | `find` or `bash` with shell globs |
| List files and subdirectories | `ls` when active; otherwise `bash` with `ls` |
| Dispatch a subagent (`Subagent (general-purpose):` template) | Use an installed subagent tool such as `subagent` from `pi-subagents` if available |
| Task tracking ("create a todo", "mark complete") | Use an installed todo/task tool if available, otherwise track tasks in the plan or `TODO.md` |
## Skills
Pi discovers skills from configured skill directories and installed Pi packages. A Superpowers Pi package should expose `skills/` through its `pi.skills` manifest entry. Pi does not expose Claude Code's `Skill` tool, but the agent should still follow the Superpowers rule: when a skill applies, load and follow it before responding.
## Subagents
Pi core does not ship a standard subagent tool. The `pi-subagents` package is a strong optional companion and provides a `subagent` tool with single-agent, chain, parallel, async, forked-context, and resume/status workflows. If no subagent tool is available, do not fabricate `Task` calls; execute sequentially in the current session or explain that the optional subagent capability is not installed.
## Task lists
Pi core does not ship a standard task-list tool. If a todo/task extension is installed, use its documented tool. Otherwise use Superpowers plan files, checklists in Markdown, or a repo-local `TODO.md` for task tracking. Older Superpowers docs may refer to `TodoWrite`; treat that as the task-tracking action above.

View File

@@ -13,7 +13,7 @@ Assume they are a skilled developer, but know almost nothing about our toolset o
**Announce at start:** "I'm using the writing-plans skill to create the implementation plan." **Announce at start:** "I'm using the writing-plans skill to create the implementation plan."
**Context:** This should be run in a dedicated worktree (created by brainstorming skill). **Context:** If working in an isolated worktree, it should have been created via the `superpowers:using-git-worktrees` skill at execution time.
**Save plans to:** `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md` **Save plans to:** `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md`
- (User preferences for plan location override this default) - (User preferences for plan location override this default)
@@ -103,26 +103,33 @@ git commit -m "feat: add specific feature"
``` ```
```` ````
## No Placeholders
Every step must contain the actual content an engineer needs. These are **plan failures** — never write them:
- "TBD", "TODO", "implement later", "fill in details"
- "Add appropriate error handling" / "add validation" / "handle edge cases"
- "Write tests for the above" (without actual test code)
- "Similar to Task N" (repeat the code — the engineer may be reading tasks out of order)
- Steps that describe what to do without showing how (code blocks required for code steps)
- References to types, functions, or methods not defined in any task
## Remember ## Remember
- Exact file paths always - Exact file paths always
- Complete code in plan (not "add validation") - Complete code in every step — if a step changes code, show the code
- Exact commands with expected output - Exact commands with expected output
- Reference relevant skills with @ syntax
- DRY, YAGNI, TDD, frequent commits - DRY, YAGNI, TDD, frequent commits
## Plan Review Loop ## Self-Review
After writing the complete plan: After writing the complete plan, look at the spec with fresh eyes and check the plan against it. This is a checklist you run yourself — not a subagent dispatch.
1. Dispatch a single plan-document-reviewer subagent (see plan-document-reviewer-prompt.md) with precisely crafted review context — never your session history. This keeps the reviewer focused on the plan, not your thought process. **1. Spec coverage:** Skim each section/requirement in the spec. Can you point to a task that implements it? List any gaps.
- Provide: path to the plan document, path to spec document
2. If ❌ Issues Found: fix the issues, re-dispatch reviewer for the whole plan
3. If ✅ Approved: proceed to execution handoff
**Review loop guidance:** **2. Placeholder scan:** Search your plan for red flags — any of the patterns from the "No Placeholders" section above. Fix them.
- Same agent that wrote the plan fixes it (preserves context)
- If loop exceeds 3 iterations, surface to human for guidance **3. Type consistency:** Do the types, method signatures, and property names you used in later tasks match what you defined in earlier tasks? A function called `clearLayers()` in Task 3 but `clearFullLayers()` in Task 7 is a bug.
- Reviewers are advisory — explain disagreements if you believe feedback is incorrect
If you find issues, fix them inline. No need to re-review — just fix and move on. If you find a spec requirement with no task, add the task.
## Execution Handoff ## Execution Handoff

View File

@@ -7,7 +7,7 @@ Use this template when dispatching a plan document reviewer subagent.
**Dispatch after:** The complete plan is written. **Dispatch after:** The complete plan is written.
``` ```
Task tool (general-purpose): Subagent (general-purpose):
description: "Review plan document" description: "Review plan document"
prompt: | prompt: |
You are a plan document reviewer. Verify this plan is complete and ready for implementation. You are a plan document reviewer. Verify this plan is complete and ready for implementation.

View File

@@ -9,7 +9,7 @@ description: Use when creating new skills, editing existing skills, or verifying
**Writing skills IS Test-Driven Development applied to process documentation.** **Writing skills IS Test-Driven Development applied to process documentation.**
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.agents/skills/` for Codex)** **Personal skills live in your runtime's skills directory** — see [claude-code-tools.md](../using-superpowers/references/claude-code-tools.md), [codex-tools.md](../using-superpowers/references/codex-tools.md), [copilot-tools.md](../using-superpowers/references/copilot-tools.md), or [gemini-tools.md](../using-superpowers/references/gemini-tools.md) for the path on your runtime. Codex, Copilot CLI, and Gemini CLI all also recognize `~/.agents/skills/` as a cross-runtime alias.
You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes). You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).
@@ -21,7 +21,7 @@ You write test cases (pressure scenarios with subagents), watch them fail (basel
## What is a Skill? ## What is a Skill?
A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future Claude instances find and apply effective approaches. A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future agents find and apply effective approaches.
**Skills are:** Reusable techniques, patterns, tools, reference guides **Skills are:** Reusable techniques, patterns, tools, reference guides
@@ -55,7 +55,7 @@ The entire skill creation process follows RED-GREEN-REFACTOR.
**Don't create for:** **Don't create for:**
- One-off solutions - One-off solutions
- Standard practices well-documented elsewhere - Standard practices well-documented elsewhere
- Project-specific conventions (put in CLAUDE.md) - Project-specific conventions (put in your instructions file)
- Mechanical constraints (if it's enforceable with regex/validation, automate it—save documentation for judgment calls) - Mechanical constraints (if it's enforceable with regex/validation, automate it—save documentation for judgment calls)
## Skill Types ## Skill Types
@@ -99,7 +99,7 @@ skills/
- `description`: Third-person, describes ONLY when to use (NOT what it does) - `description`: Third-person, describes ONLY when to use (NOT what it does)
- Start with "Use when..." to focus on triggering conditions - Start with "Use when..." to focus on triggering conditions
- Include specific symptoms, situations, and contexts - Include specific symptoms, situations, and contexts
- **NEVER summarize the skill's process or workflow** (see CSO section for why) - **NEVER summarize the skill's process or workflow** (see SDO section for why)
- Keep under 500 characters if possible - Keep under 500 characters if possible
```markdown ```markdown
@@ -137,13 +137,13 @@ Concrete results
``` ```
## Claude Search Optimization (CSO) ## Skill Discovery Optimization (SDO)
**Critical for discovery:** Future Claude needs to FIND your skill **Critical for discovery:** Future agents need to FIND your skill
### 1. Rich Description Field ### 1. Rich Description Field
**Purpose:** Claude reads description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?" **Purpose:** Your agent reads the description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?"
**Format:** Start with "Use when..." to focus on triggering conditions **Format:** Start with "Use when..." to focus on triggering conditions
@@ -151,14 +151,14 @@ Concrete results
The description should ONLY describe triggering conditions. Do NOT summarize the skill's process or workflow in the description. The description should ONLY describe triggering conditions. Do NOT summarize the skill's process or workflow in the description.
**Why this matters:** Testing revealed that when a description summarizes the skill's workflow, Claude may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused Claude to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality). **Why this matters:** Testing revealed that when a description summarizes the skill's workflow, an agent may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused an agent to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality).
When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), Claude correctly read the flowchart and followed the two-stage review process. When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), the agent correctly read the flowchart and followed the two-stage review process.
**The trap:** Descriptions that summarize workflow create a shortcut Claude will take. The skill body becomes documentation Claude skips. **The trap:** Descriptions that summarize workflow create a shortcut agents will take. The skill body becomes documentation agents skip.
```yaml ```yaml
# ❌ BAD: Summarizes workflow - Claude may follow this instead of reading skill # ❌ BAD: Summarizes workflow - agents may follow this instead of reading skill
description: Use when executing plans - dispatches subagent per task with code review between tasks description: Use when executing plans - dispatches subagent per task with code review between tasks
# ❌ BAD: Too much process detail # ❌ BAD: Too much process detail
@@ -198,7 +198,7 @@ description: Use when using React Router and handling authentication redirects
### 2. Keyword Coverage ### 2. Keyword Coverage
Use words Claude would search for: Use words an agent would search for:
- Error messages: "Hook timed out", "ENOTEMPTY", "race condition" - Error messages: "Hook timed out", "ENOTEMPTY", "race condition"
- Symptoms: "flaky", "hanging", "zombie", "pollution" - Symptoms: "flaky", "hanging", "zombie", "pollution"
- Synonyms: "timeout/hang/freeze", "cleanup/teardown/afterEach" - Synonyms: "timeout/hang/freeze", "cleanup/teardown/afterEach"
@@ -275,7 +275,7 @@ wc -w skills/path/SKILL.md
- `creating-skills`, `testing-skills`, `debugging-with-logs` - `creating-skills`, `testing-skills`, `debugging-with-logs`
- Active, describes the action you're taking - Active, describes the action you're taking
### 4. Cross-Referencing Other Skills ### 5. Cross-Referencing Other Skills
**When writing documentation that references other skills:** **When writing documentation that references other skills:**
@@ -313,7 +313,7 @@ digraph when_flowchart {
- Linear instructions → Numbered lists - Linear instructions → Numbered lists
- Labels without semantic meaning (step1, helper2) - Labels without semantic meaning (step1, helper2)
See @graphviz-conventions.dot for graphviz style rules. See `graphviz-conventions.dot` in this directory for graphviz style rules.
**Visualizing for your human partner:** Use `render-graphs.js` in this directory to render a skill's flowcharts to SVG: **Visualizing for your human partner:** Use `render-graphs.js` in this directory to render a skill's flowcharts to SVG:
```bash ```bash
@@ -522,7 +522,7 @@ Make it easy for agents to self-check when rationalizing:
**All of these mean: Delete code. Start over with TDD.** **All of these mean: Delete code. Start over with TDD.**
``` ```
### Update CSO for Violation Symptoms ### Update SDO for Violation Symptoms
Add to description: symptoms of when you're ABOUT to violate the rule: Add to description: symptoms of when you're ABOUT to violate the rule:
@@ -553,7 +553,7 @@ Run same scenarios WITH skill. Agent should now comply.
Agent found new rationalization? Add explicit counter. Re-test until bulletproof. Agent found new rationalization? Add explicit counter. Re-test until bulletproof.
**Testing methodology:** See @testing-skills-with-subagents.md for the complete testing methodology: **Testing methodology:** See [testing-skills-with-subagents.md](testing-skills-with-subagents.md) for the complete testing methodology:
- How to write pressure scenarios - How to write pressure scenarios
- Pressure types (time, sunk cost, authority, exhaustion) - Pressure types (time, sunk cost, authority, exhaustion)
- Plugging holes systematically - Plugging holes systematically
@@ -595,7 +595,7 @@ Deploying untested skills = deploying untested code. It's a violation of quality
## Skill Creation Checklist (TDD Adapted) ## Skill Creation Checklist (TDD Adapted)
**IMPORTANT: Use TodoWrite to create todos for EACH checklist item below.** **IMPORTANT: Create a todo for EACH checklist item below.**
**RED Phase - Write Failing Test:** **RED Phase - Write Failing Test:**
- [ ] Create pressure scenarios (3+ combined pressures for discipline skills) - [ ] Create pressure scenarios (3+ combined pressures for discipline skills)
@@ -634,9 +634,10 @@ Deploying untested skills = deploying untested code. It's a violation of quality
## Discovery Workflow ## Discovery Workflow
How future Claude finds your skill: How future agents find your skill:
1. **Encounters problem** ("tests are flaky") 1. **Encounters problem** ("tests are flaky")
2. **Searches skills** (greps descriptions, browses categories)
3. **Finds SKILL** (description matches) 3. **Finds SKILL** (description matches)
4. **Scans overview** (is this relevant?) 4. **Scans overview** (is this relevant?)
5. **Reads patterns** (quick reference table) 5. **Reads patterns** (quick reference table)

View File

@@ -1,30 +1,30 @@
# Skill authoring best practices # Skill authoring best practices
> Learn how to write effective Skills that Claude can discover and use successfully. > Learn how to write effective Skills that agents can discover and use successfully.
Good Skills are concise, well-structured, and tested with real usage. This guide provides practical authoring decisions to help you write Skills that Claude can discover and use effectively. Good Skills are concise, well-structured, and tested with real usage. This guide provides practical authoring decisions to help you write Skills that agents can discover and use effectively.
For conceptual background on how Skills work, see the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview). For conceptual background on how Skills work, see the [Skills overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview).
## Core principles ## Core principles
### Concise is key ### Concise is key
The [context window](https://platform.claude.com/docs/en/build-with-claude/context-windows) is a public good. Your Skill shares the context window with everything else Claude needs to know, including: The [context window](https://platform.claude.com/docs/en/build-with-claude/context-windows) is a public good. Your Skill shares the context window with everything else your agent needs to know, including:
* The system prompt * The system prompt
* Conversation history * Conversation history
* Other Skills' metadata * Other Skills' metadata
* Your actual request * Your actual request
Not every token in your Skill has an immediate cost. At startup, only the metadata (name and description) from all Skills is pre-loaded. Claude reads SKILL.md only when the Skill becomes relevant, and reads additional files only as needed. However, being concise in SKILL.md still matters: once Claude loads it, every token competes with conversation history and other context. Not every token in your Skill has an immediate cost. At startup, only the metadata (name and description) from all Skills is pre-loaded. Agents read SKILL.md only when the Skill becomes relevant, and read additional files only as needed. However, being concise in SKILL.md still matters: once an agent loads it, every token competes with conversation history and other context.
**Default assumption**: Claude is already very smart **Default assumption**: Agents are already very smart
Only add context Claude doesn't already have. Challenge each piece of information: Only add context agents don't already have. Challenge each piece of information:
* "Does Claude really need this explanation?" * "Does the agent really need this explanation?"
* "Can I assume Claude knows this?" * "Can I assume the agent knows this?"
* "Does this paragraph justify its token cost?" * "Does this paragraph justify its token cost?"
**Good example: Concise** (approximately 50 tokens): **Good example: Concise** (approximately 50 tokens):
@@ -54,7 +54,7 @@ recommend pdfplumber because it's easy to use and handles most cases well.
First, you'll need to install it using pip. Then you can use the code below... First, you'll need to install it using pip. Then you can use the code below...
``` ```
The concise version assumes Claude knows what PDFs are and how libraries work. The concise version assumes the agent knows what PDFs are and how libraries work.
### Set appropriate degrees of freedom ### Set appropriate degrees of freedom
@@ -124,10 +124,10 @@ python scripts/migrate.py --verify --backup
Do not modify the command or add additional flags. Do not modify the command or add additional flags.
```` ````
**Analogy**: Think of Claude as a robot exploring a path: **Analogy**: Think of the agent as a robot exploring a path:
* **Narrow bridge with cliffs on both sides**: There's only one safe way forward. Provide specific guardrails and exact instructions (low freedom). Example: database migrations that must run in exact sequence. * **Narrow bridge with cliffs on both sides**: There's only one safe way forward. Provide specific guardrails and exact instructions (low freedom). Example: database migrations that must run in exact sequence.
* **Open field with no hazards**: Many paths lead to success. Give general direction and trust Claude to find the best route (high freedom). Example: code reviews where context determines the best approach. * **Open field with no hazards**: Many paths lead to success. Give general direction and trust the agent to find the best route (high freedom). Example: code reviews where context determines the best approach.
### Test with all models you plan to use ### Test with all models you plan to use
@@ -149,7 +149,7 @@ What works perfectly for Opus might need more detail for Haiku. If you plan to u
* `name` - Human-readable name of the Skill (64 characters maximum) * `name` - Human-readable name of the Skill (64 characters maximum)
* `description` - One-line description of what the Skill does and when to use it (1024 characters maximum) * `description` - One-line description of what the Skill does and when to use it (1024 characters maximum)
For complete Skill structure details, see the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview#skill-structure). For complete Skill structure details, see the [Skills overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview#skill-structure).
</Note> </Note>
### Naming conventions ### Naming conventions
@@ -196,7 +196,7 @@ The `description` field enables Skill discovery and should include both what the
**Be specific and include key terms**. Include both what the Skill does and specific triggers/contexts for when to use it. **Be specific and include key terms**. Include both what the Skill does and specific triggers/contexts for when to use it.
Each Skill has exactly one description field. The description is critical for skill selection: Claude uses it to choose the right Skill from potentially 100+ available Skills. Your description must provide enough detail for Claude to know when to select this Skill, while the rest of SKILL.md provides the implementation details. Each Skill has exactly one description field. The description is critical for skill selection: agents use it to choose the right Skill from potentially 100+ available Skills. Your description must provide enough detail for an agent to know when to select this Skill, while the rest of SKILL.md provides the implementation details.
Effective examples: Effective examples:
@@ -234,7 +234,7 @@ description: Does stuff with files
### Progressive disclosure patterns ### Progressive disclosure patterns
SKILL.md serves as an overview that points Claude to detailed materials as needed, like a table of contents in an onboarding guide. For an explanation of how progressive disclosure works, see [How Skills work](/en/docs/agents-and-tools/agent-skills/overview#how-skills-work) in the overview. SKILL.md serves as an overview that points agents to detailed materials as needed, like a table of contents in an onboarding guide. For an explanation of how progressive disclosure works, see [How Skills work](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview#how-skills-work) in the overview.
**Practical guidance:** **Practical guidance:**
@@ -248,7 +248,7 @@ A basic Skill starts with just a SKILL.md file containing metadata and instructi
<img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=87782ff239b297d9a9e8e1b72ed72db9" alt="Simple SKILL.md file showing YAML frontmatter and markdown body" data-og-width="2048" width="2048" data-og-height="1153" height="1153" data-path="images/agent-skills-simple-file.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=c61cc33b6f5855809907f7fda94cd80e 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=90d2c0c1c76b36e8d485f49e0810dbfd 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=ad17d231ac7b0bea7e5b4d58fb4aeabb 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=f5d0a7a3c668435bb0aee9a3a8f8c329 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=0e927c1af9de5799cfe557d12249f6e6 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=46bbb1a51dd4c8202a470ac8c80a893d 2500w" /> <img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=87782ff239b297d9a9e8e1b72ed72db9" alt="Simple SKILL.md file showing YAML frontmatter and markdown body" data-og-width="2048" width="2048" data-og-height="1153" height="1153" data-path="images/agent-skills-simple-file.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=c61cc33b6f5855809907f7fda94cd80e 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=90d2c0c1c76b36e8d485f49e0810dbfd 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=ad17d231ac7b0bea7e5b4d58fb4aeabb 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=f5d0a7a3c668435bb0aee9a3a8f8c329 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=0e927c1af9de5799cfe557d12249f6e6 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-simple-file.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=46bbb1a51dd4c8202a470ac8c80a893d 2500w" />
As your Skill grows, you can bundle additional content that Claude loads only when needed: As your Skill grows, you can bundle additional content that agents load only when needed:
<img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=a5e0aa41e3d53985a7e3e43668a33ea3" alt="Bundling additional reference files like reference.md and forms.md." data-og-width="2048" width="2048" data-og-height="1327" height="1327" data-path="images/agent-skills-bundling-content.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=f8a0e73783e99b4a643d79eac86b70a2 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=dc510a2a9d3f14359416b706f067904a 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=82cd6286c966303f7dd914c28170e385 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=56f3be36c77e4fe4b523df209a6824c6 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=d22b5161b2075656417d56f41a74f3dd 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=3dd4bdd6850ffcc96c6c45fcb0acd6eb 2500w" /> <img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=a5e0aa41e3d53985a7e3e43668a33ea3" alt="Bundling additional reference files like reference.md and forms.md." data-og-width="2048" width="2048" data-og-height="1327" height="1327" data-path="images/agent-skills-bundling-content.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=f8a0e73783e99b4a643d79eac86b70a2 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=dc510a2a9d3f14359416b706f067904a 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=82cd6286c966303f7dd914c28170e385 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=56f3be36c77e4fe4b523df209a6824c6 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=d22b5161b2075656417d56f41a74f3dd 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-bundling-content.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=3dd4bdd6850ffcc96c6c45fcb0acd6eb 2500w" />
@@ -292,11 +292,11 @@ with pdfplumber.open("file.pdf") as pdf:
**Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns
```` ````
Claude loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed. Agents load FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.
#### Pattern 2: Domain-specific organization #### Pattern 2: Domain-specific organization
For Skills with multiple domains, organize content by domain to avoid loading irrelevant context. When a user asks about sales metrics, Claude only needs to read sales-related schemas, not finance or marketing data. This keeps token usage low and context focused. For Skills with multiple domains, organize content by domain to avoid loading irrelevant context. When a user asks about sales metrics, the agent only needs to read sales-related schemas, not finance or marketing data. This keeps token usage low and context focused.
``` ```
bigquery-skill/ bigquery-skill/
@@ -348,13 +348,13 @@ For simple edits, modify the XML directly.
**For OOXML details**: See [OOXML.md](OOXML.md) **For OOXML details**: See [OOXML.md](OOXML.md)
``` ```
Claude reads REDLINING.md or OOXML.md only when the user needs those features. Agents read REDLINING.md or OOXML.md only when the user needs those features.
### Avoid deeply nested references ### Avoid deeply nested references
Claude may partially read files when they're referenced from other referenced files. When encountering nested references, Claude might use commands like `head -100` to preview content rather than reading entire files, resulting in incomplete information. Agents may partially read files when they're referenced from other referenced files. When encountering nested references, an agent might use commands like `head -100` to preview content rather than reading entire files, resulting in incomplete information.
**Keep references one level deep from SKILL.md**. All reference files should link directly from SKILL.md to ensure Claude reads complete files when needed. **Keep references one level deep from SKILL.md**. All reference files should link directly from SKILL.md to ensure agents read complete files when needed.
**Bad example: Too deep**: **Bad example: Too deep**:
@@ -382,7 +382,7 @@ Here's the actual information...
### Structure longer reference files with table of contents ### Structure longer reference files with table of contents
For reference files longer than 100 lines, include a table of contents at the top. This ensures Claude can see the full scope of available information even when previewing with partial reads. For reference files longer than 100 lines, include a table of contents at the top. This ensures agents can see the full scope of available information even when previewing with partial reads.
**Example**: **Example**:
@@ -403,7 +403,7 @@ For reference files longer than 100 lines, include a table of contents at the to
... ...
``` ```
Claude can then read the complete file or jump to specific sections as needed. Agents can then read the complete file or jump to specific sections as needed.
For details on how this filesystem-based architecture enables progressive disclosure, see the [Runtime environment](#runtime-environment) section in the Advanced section below. For details on how this filesystem-based architecture enables progressive disclosure, see the [Runtime environment](#runtime-environment) section in the Advanced section below.
@@ -411,7 +411,7 @@ For details on how this filesystem-based architecture enables progressive disclo
### Use workflows for complex tasks ### Use workflows for complex tasks
Break complex operations into clear, sequential steps. For particularly complex workflows, provide a checklist that Claude can copy into its response and check off as it progresses. Break complex operations into clear, sequential steps. For particularly complex workflows, provide a checklist that the agent can copy into its response and check off as it progresses.
**Example 1: Research synthesis workflow** (for Skills without code): **Example 1: Research synthesis workflow** (for Skills without code):
@@ -498,7 +498,7 @@ Run: `python scripts/verify_output.py output.pdf`
If verification fails, return to Step 2. If verification fails, return to Step 2.
```` ````
Clear steps prevent Claude from skipping critical validation. The checklist helps both Claude and you track progress through multi-step workflows. Clear steps prevent agents from skipping critical validation. The checklist helps both you and the agent track progress through multi-step workflows.
### Implement feedback loops ### Implement feedback loops
@@ -524,7 +524,7 @@ This pattern greatly improves output quality.
5. Finalize and save the document 5. Finalize and save the document
``` ```
This shows the validation loop pattern using reference documents instead of scripts. The "validator" is STYLE\_GUIDE.md, and Claude performs the check by reading and comparing. This shows the validation loop pattern using reference documents instead of scripts. The "validator" is STYLE\_GUIDE.md, and the agent performs the check by reading and comparing.
**Example 2: Document editing process** (for Skills with code): **Example 2: Document editing process** (for Skills with code):
@@ -593,7 +593,7 @@ Choose one term and use it throughout the Skill:
* Mix "field", "box", "element", "control" * Mix "field", "box", "element", "control"
* Mix "extract", "pull", "get", "retrieve" * Mix "extract", "pull", "get", "retrieve"
Consistency helps Claude understand and follow instructions. Consistency helps agents understand and follow instructions.
## Common patterns ## Common patterns
@@ -688,11 +688,11 @@ chore: update dependencies and refactor error handling
Follow this style: type(scope): brief description, then detailed explanation. Follow this style: type(scope): brief description, then detailed explanation.
```` ````
Examples help Claude understand the desired style and level of detail more clearly than descriptions alone. Examples help agents understand the desired style and level of detail more clearly than descriptions alone.
### Conditional workflow pattern ### Conditional workflow pattern
Guide Claude through decision points: Guide agents through decision points:
```markdown theme={null} ```markdown theme={null}
## Document modification workflow ## Document modification workflow
@@ -715,7 +715,7 @@ Guide Claude through decision points:
``` ```
<Tip> <Tip>
If workflows become large or complicated with many steps, consider pushing them into separate files and tell Claude to read the appropriate file based on the task at hand. If workflows become large or complicated with many steps, consider pushing them into separate files and tell the agent to read the appropriate file based on the task at hand.
</Tip> </Tip>
## Evaluation and iteration ## Evaluation and iteration
@@ -726,9 +726,9 @@ Guide Claude through decision points:
**Evaluation-driven development:** **Evaluation-driven development:**
1. **Identify gaps**: Run Claude on representative tasks without a Skill. Document specific failures or missing context 1. **Identify gaps**: Run your agent on representative tasks without a Skill. Document specific failures or missing context
2. **Create evaluations**: Build three scenarios that test these gaps 2. **Create evaluations**: Build three scenarios that test these gaps
3. **Establish baseline**: Measure Claude's performance without the Skill 3. **Establish baseline**: Measure the agent's performance without the Skill
4. **Write minimal instructions**: Create just enough content to address the gaps and pass evaluations 4. **Write minimal instructions**: Create just enough content to address the gaps and pass evaluations
5. **Iterate**: Execute evaluations, compare against baseline, and refine 5. **Iterate**: Execute evaluations, compare against baseline, and refine
@@ -753,51 +753,51 @@ This approach ensures you're solving actual problems rather than anticipating re
This example demonstrates a data-driven evaluation with a simple testing rubric. We do not currently provide a built-in way to run these evaluations. Users can create their own evaluation system. Evaluations are your source of truth for measuring Skill effectiveness. This example demonstrates a data-driven evaluation with a simple testing rubric. We do not currently provide a built-in way to run these evaluations. Users can create their own evaluation system. Evaluations are your source of truth for measuring Skill effectiveness.
</Note> </Note>
### Develop Skills iteratively with Claude ### Develop Skills iteratively with the agent
The most effective Skill development process involves Claude itself. Work with one instance of Claude ("Claude A") to create a Skill that will be used by other instances ("Claude B"). Claude A helps you design and refine instructions, while Claude B tests them in real tasks. This works because Claude models understand both how to write effective agent instructions and what information agents need. The most effective Skill development process involves the agent itself. Work with one instance ("Agent A") to create a Skill that will be used by other instances ("Agent B"). Agent A helps you design and refine instructions, while Agent B tests them in real tasks. This works because the underlying models understand both how to write effective agent instructions and what information agents need.
**Creating a new Skill:** **Creating a new Skill:**
1. **Complete a task without a Skill**: Work through a problem with Claude A using normal prompting. As you work, you'll naturally provide context, explain preferences, and share procedural knowledge. Notice what information you repeatedly provide. 1. **Complete a task without a Skill**: Work through a problem with Agent A using normal prompting. As you work, you'll naturally provide context, explain preferences, and share procedural knowledge. Notice what information you repeatedly provide.
2. **Identify the reusable pattern**: After completing the task, identify what context you provided that would be useful for similar future tasks. 2. **Identify the reusable pattern**: After completing the task, identify what context you provided that would be useful for similar future tasks.
**Example**: If you worked through a BigQuery analysis, you might have provided table names, field definitions, filtering rules (like "always exclude test accounts"), and common query patterns. **Example**: If you worked through a BigQuery analysis, you might have provided table names, field definitions, filtering rules (like "always exclude test accounts"), and common query patterns.
3. **Ask Claude A to create a Skill**: "Create a Skill that captures this BigQuery analysis pattern we just used. Include the table schemas, naming conventions, and the rule about filtering test accounts." 3. **Ask Agent A to create a Skill**: "Create a Skill that captures this BigQuery analysis pattern we just used. Include the table schemas, naming conventions, and the rule about filtering test accounts."
<Tip> <Tip>
Claude models understand the Skill format and structure natively. You don't need special system prompts or a "writing skills" skill to get Claude to help create Skills. Simply ask Claude to create a Skill and it will generate properly structured SKILL.md content with appropriate frontmatter and body content. Modern agents understand the Skill format and structure natively. You don't need special system prompts or a "writing skills" skill to get help creating Skills. Simply ask the agent to create a Skill and it will generate properly structured SKILL.md content with appropriate frontmatter and body content.
</Tip> </Tip>
4. **Review for conciseness**: Check that Claude A hasn't added unnecessary explanations. Ask: "Remove the explanation about what win rate means - Claude already knows that." 4. **Review for conciseness**: Check that Agent A hasn't added unnecessary explanations. Ask: "Remove the explanation about what win rate means - the agent already knows that."
5. **Improve information architecture**: Ask Claude A to organize the content more effectively. For example: "Organize this so the table schema is in a separate reference file. We might add more tables later." 5. **Improve information architecture**: Ask Agent A to organize the content more effectively. For example: "Organize this so the table schema is in a separate reference file. We might add more tables later."
6. **Test on similar tasks**: Use the Skill with Claude B (a fresh instance with the Skill loaded) on related use cases. Observe whether Claude B finds the right information, applies rules correctly, and handles the task successfully. 6. **Test on similar tasks**: Use the Skill with Agent B (a fresh instance with the Skill loaded) on related use cases. Observe whether Agent B finds the right information, applies rules correctly, and handles the task successfully.
7. **Iterate based on observation**: If Claude B struggles or misses something, return to Claude A with specifics: "When Claude used this Skill, it forgot to filter by date for Q4. Should we add a section about date filtering patterns?" 7. **Iterate based on observation**: If Agent B struggles or misses something, return to Agent A with specifics: "When the agent used this Skill, it forgot to filter by date for Q4. Should we add a section about date filtering patterns?"
**Iterating on existing Skills:** **Iterating on existing Skills:**
The same hierarchical pattern continues when improving Skills. You alternate between: The same hierarchical pattern continues when improving Skills. You alternate between:
* **Working with Claude A** (the expert who helps refine the Skill) * **Working with Agent A** (the expert who helps refine the Skill)
* **Testing with Claude B** (the agent using the Skill to perform real work) * **Testing with Agent B** (the agent using the Skill to perform real work)
* **Observing Claude B's behavior** and bringing insights back to Claude A * **Observing Agent B's behavior** and bringing insights back to Agent A
1. **Use the Skill in real workflows**: Give Claude B (with the Skill loaded) actual tasks, not test scenarios 1. **Use the Skill in real workflows**: Give Agent B (with the Skill loaded) actual tasks, not test scenarios
2. **Observe Claude B's behavior**: Note where it struggles, succeeds, or makes unexpected choices 2. **Observe Agent B's behavior**: Note where it struggles, succeeds, or makes unexpected choices
**Example observation**: "When I asked Claude B for a regional sales report, it wrote the query but forgot to filter out test accounts, even though the Skill mentions this rule." **Example observation**: "When I asked Agent B for a regional sales report, it wrote the query but forgot to filter out test accounts, even though the Skill mentions this rule."
3. **Return to Claude A for improvements**: Share the current SKILL.md and describe what you observed. Ask: "I noticed Claude B forgot to filter test accounts when I asked for a regional report. The Skill mentions filtering, but maybe it's not prominent enough?" 3. **Return to Agent A for improvements**: Share the current SKILL.md and describe what you observed. Ask: "I noticed Agent B forgot to filter test accounts when I asked for a regional report. The Skill mentions filtering, but maybe it's not prominent enough?"
4. **Review Claude A's suggestions**: Claude A might suggest reorganizing to make rules more prominent, using stronger language like "MUST filter" instead of "always filter", or restructuring the workflow section. 4. **Review Agent A's suggestions**: Agent A might suggest reorganizing to make rules more prominent, using stronger language like "MUST filter" instead of "always filter", or restructuring the workflow section.
5. **Apply and test changes**: Update the Skill with Claude A's refinements, then test again with Claude B on similar requests 5. **Apply and test changes**: Update the Skill with Agent A's refinements, then test again with Agent B on similar requests
6. **Repeat based on usage**: Continue this observe-refine-test cycle as you encounter new scenarios. Each iteration improves the Skill based on real agent behavior, not assumptions. 6. **Repeat based on usage**: Continue this observe-refine-test cycle as you encounter new scenarios. Each iteration improves the Skill based on real agent behavior, not assumptions.
@@ -807,18 +807,18 @@ The same hierarchical pattern continues when improving Skills. You alternate bet
2. Ask: Does the Skill activate when expected? Are instructions clear? What's missing? 2. Ask: Does the Skill activate when expected? Are instructions clear? What's missing?
3. Incorporate feedback to address blind spots in your own usage patterns 3. Incorporate feedback to address blind spots in your own usage patterns
**Why this approach works**: Claude A understands agent needs, you provide domain expertise, Claude B reveals gaps through real usage, and iterative refinement improves Skills based on observed behavior rather than assumptions. **Why this approach works**: Agent A understands agent needs, you provide domain expertise, Agent B reveals gaps through real usage, and iterative refinement improves Skills based on observed behavior rather than assumptions.
### Observe how Claude navigates Skills ### Observe how agents navigate Skills
As you iterate on Skills, pay attention to how Claude actually uses them in practice. Watch for: As you iterate on Skills, pay attention to how agents actually use them in practice. Watch for:
* **Unexpected exploration paths**: Does Claude read files in an order you didn't anticipate? This might indicate your structure isn't as intuitive as you thought * **Unexpected exploration paths**: Does the agent read files in an order you didn't anticipate? This might indicate your structure isn't as intuitive as you thought
* **Missed connections**: Does Claude fail to follow references to important files? Your links might need to be more explicit or prominent * **Missed connections**: Does the agent fail to follow references to important files? Your links might need to be more explicit or prominent
* **Overreliance on certain sections**: If Claude repeatedly reads the same file, consider whether that content should be in the main SKILL.md instead * **Overreliance on certain sections**: If the agent repeatedly reads the same file, consider whether that content should be in the main SKILL.md instead
* **Ignored content**: If Claude never accesses a bundled file, it might be unnecessary or poorly signaled in the main instructions * **Ignored content**: If the agent never accesses a bundled file, it might be unnecessary or poorly signaled in the main instructions
Iterate based on these observations rather than assumptions. The 'name' and 'description' in your Skill's metadata are particularly critical. Claude uses these when deciding whether to trigger the Skill in response to the current task. Make sure they clearly describe what the Skill does and when it should be used. Iterate based on these observations rather than assumptions. The 'name' and 'description' in your Skill's metadata are particularly critical. Agents use these when deciding whether to trigger the Skill in response to the current task. Make sure they clearly describe what the Skill does and when it should be used.
## Anti-patterns to avoid ## Anti-patterns to avoid
@@ -854,7 +854,7 @@ The sections below focus on Skills that include executable scripts. If your Skil
### Solve, don't punt ### Solve, don't punt
When writing scripts for Skills, handle error conditions rather than punting to Claude. When writing scripts for Skills, handle error conditions rather than punting to the agent.
**Good example: Handle errors explicitly**: **Good example: Handle errors explicitly**:
@@ -876,15 +876,15 @@ def process_file(path):
return '' return ''
``` ```
**Bad example: Punt to Claude**: **Bad example: Punt to the agent**:
```python theme={null} ```python theme={null}
def process_file(path): def process_file(path):
# Just fail and let Claude figure it out # Just fail and let the agent figure it out
return open(path).read() return open(path).read()
``` ```
Configuration parameters should also be justified and documented to avoid "voodoo constants" (Ousterhout's law). If you don't know the right value, how will Claude determine it? Configuration parameters should also be justified and documented to avoid "voodoo constants" (Ousterhout's law). If you don't know the right value, how will the agent determine it?
**Good example: Self-documenting**: **Good example: Self-documenting**:
@@ -907,7 +907,7 @@ RETRIES = 5 # Why 5?
### Provide utility scripts ### Provide utility scripts
Even if Claude could write a script, pre-made scripts offer advantages: Even if your agent could write a script, pre-made scripts offer advantages:
**Benefits of utility scripts**: **Benefits of utility scripts**:
@@ -918,9 +918,9 @@ Even if Claude could write a script, pre-made scripts offer advantages:
<img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=4bbc45f2c2e0bee9f2f0d5da669bad00" alt="Bundling executable scripts alongside instruction files" data-og-width="2048" width="2048" data-og-height="1154" height="1154" data-path="images/agent-skills-executable-scripts.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=9a04e6535a8467bfeea492e517de389f 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=e49333ad90141af17c0d7651cca7216b 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=954265a5df52223d6572b6214168c428 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=2ff7a2d8f2a83ee8af132b29f10150fd 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=48ab96245e04077f4d15e9170e081cfb 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=0301a6c8b3ee879497cc5b5483177c90 2500w" /> <img src="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=4bbc45f2c2e0bee9f2f0d5da669bad00" alt="Bundling executable scripts alongside instruction files" data-og-width="2048" width="2048" data-og-height="1154" height="1154" data-path="images/agent-skills-executable-scripts.png" data-optimize="true" data-opv="3" srcset="https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=280&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=9a04e6535a8467bfeea492e517de389f 280w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=560&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=e49333ad90141af17c0d7651cca7216b 560w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=840&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=954265a5df52223d6572b6214168c428 840w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=1100&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=2ff7a2d8f2a83ee8af132b29f10150fd 1100w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=1650&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=48ab96245e04077f4d15e9170e081cfb 1650w, https://mintcdn.com/anthropic-claude-docs/4Bny2bjzuGBK7o00/images/agent-skills-executable-scripts.png?w=2500&fit=max&auto=format&n=4Bny2bjzuGBK7o00&q=85&s=0301a6c8b3ee879497cc5b5483177c90 2500w" />
The diagram above shows how executable scripts work alongside instruction files. The instruction file (forms.md) references the script, and Claude can execute it without loading its contents into context. The diagram above shows how executable scripts work alongside instruction files. The instruction file (forms.md) references the script, and the agent can execute it without loading its contents into context.
**Important distinction**: Make clear in your instructions whether Claude should: **Important distinction**: Make clear in your instructions whether the agent should:
* **Execute the script** (most common): "Run `analyze_form.py` to extract fields" * **Execute the script** (most common): "Run `analyze_form.py` to extract fields"
* **Read it as reference** (for complex logic): "See `analyze_form.py` for the field extraction algorithm" * **Read it as reference** (for complex logic): "See `analyze_form.py` for the field extraction algorithm"
@@ -962,7 +962,7 @@ python scripts/fill_form.py input.pdf fields.json output.pdf
### Use visual analysis ### Use visual analysis
When inputs can be rendered as images, have Claude analyze them: When inputs can be rendered as images, have the agent analyze them:
````markdown theme={null} ````markdown theme={null}
## Form layout analysis ## Form layout analysis
@@ -973,20 +973,20 @@ When inputs can be rendered as images, have Claude analyze them:
``` ```
2. Analyze each page image to identify form fields 2. Analyze each page image to identify form fields
3. Claude can see field locations and types visually 3. The agent can see field locations and types visually
```` ````
<Note> <Note>
In this example, you'd need to write the `pdf_to_images.py` script. In this example, you'd need to write the `pdf_to_images.py` script.
</Note> </Note>
Claude's vision capabilities help understand layouts and structures. Agent vision capabilities help understand layouts and structures.
### Create verifiable intermediate outputs ### Create verifiable intermediate outputs
When Claude performs complex, open-ended tasks, it can make mistakes. The "plan-validate-execute" pattern catches errors early by having Claude first create a plan in a structured format, then validate that plan with a script before executing it. When agents perform complex, open-ended tasks, they can make mistakes. The "plan-validate-execute" pattern catches errors early by having the agent first create a plan in a structured format, then validate that plan with a script before executing it.
**Example**: Imagine asking Claude to update 50 form fields in a PDF based on a spreadsheet. Without validation, Claude might reference non-existent fields, create conflicting values, miss required fields, or apply updates incorrectly. **Example**: Imagine asking the agent to update 50 form fields in a PDF based on a spreadsheet. Without validation, it might reference non-existent fields, create conflicting values, miss required fields, or apply updates incorrectly.
**Solution**: Use the workflow pattern shown above (PDF form filling), but add an intermediate `changes.json` file that gets validated before applying changes. The workflow becomes: analyze → **create plan file** → **validate plan** → execute → verify. **Solution**: Use the workflow pattern shown above (PDF form filling), but add an intermediate `changes.json` file that gets validated before applying changes. The workflow becomes: analyze → **create plan file** → **validate plan** → execute → verify.
@@ -994,12 +994,12 @@ When Claude performs complex, open-ended tasks, it can make mistakes. The "plan-
* **Catches errors early**: Validation finds problems before changes are applied * **Catches errors early**: Validation finds problems before changes are applied
* **Machine-verifiable**: Scripts provide objective verification * **Machine-verifiable**: Scripts provide objective verification
* **Reversible planning**: Claude can iterate on the plan without touching originals * **Reversible planning**: The agent can iterate on the plan without touching originals
* **Clear debugging**: Error messages point to specific problems * **Clear debugging**: Error messages point to specific problems
**When to use**: Batch operations, destructive changes, complex validation rules, high-stakes operations. **When to use**: Batch operations, destructive changes, complex validation rules, high-stakes operations.
**Implementation tip**: Make validation scripts verbose with specific error messages like "Field 'signature\_date' not found. Available fields: customer\_name, order\_total, signature\_date\_signed" to help Claude fix issues. **Implementation tip**: Make validation scripts verbose with specific error messages like "Field 'signature\_date' not found. Available fields: customer\_name, order\_total, signature\_date\_signed" to help the agent fix issues.
### Package dependencies ### Package dependencies
@@ -1008,32 +1008,32 @@ Skills run in the code execution environment with platform-specific limitations:
* **claude.ai**: Can install packages from npm and PyPI and pull from GitHub repositories * **claude.ai**: Can install packages from npm and PyPI and pull from GitHub repositories
* **Anthropic API**: Has no network access and no runtime package installation * **Anthropic API**: Has no network access and no runtime package installation
List required packages in your SKILL.md and verify they're available in the [code execution tool documentation](/en/docs/agents-and-tools/tool-use/code-execution-tool). List required packages in your SKILL.md and verify they're available in the [code execution tool documentation](https://platform.claude.com/docs/en/agents-and-tools/tool-use/code-execution-tool).
### Runtime environment ### Runtime environment
Skills run in a code execution environment with filesystem access, bash commands, and code execution capabilities. For the conceptual explanation of this architecture, see [The Skills architecture](/en/docs/agents-and-tools/agent-skills/overview#the-skills-architecture) in the overview. Skills run in a code execution environment with filesystem access, bash commands, and code execution capabilities. For the conceptual explanation of this architecture, see [The Skills architecture](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview#the-skills-architecture) in the overview.
**How this affects your authoring:** **How this affects your authoring:**
**How Claude accesses Skills:** **How agents access Skills:**
1. **Metadata pre-loaded**: At startup, the name and description from all Skills' YAML frontmatter are loaded into the system prompt 1. **Metadata pre-loaded**: At startup, the name and description from all Skills' YAML frontmatter are loaded into the system prompt
2. **Files read on-demand**: Claude uses bash Read tools to access SKILL.md and other files from the filesystem when needed 2. **Files read on-demand**: Agents use their file-reading tools to access SKILL.md and other files from the filesystem when needed
3. **Scripts executed efficiently**: Utility scripts can be executed via bash without loading their full contents into context. Only the script's output consumes tokens 3. **Scripts executed efficiently**: Utility scripts can be executed via bash without loading their full contents into context. Only the script's output consumes tokens
4. **No context penalty for large files**: Reference files, data, or documentation don't consume context tokens until actually read 4. **No context penalty for large files**: Reference files, data, or documentation don't consume context tokens until actually read
* **File paths matter**: Claude navigates your skill directory like a filesystem. Use forward slashes (`reference/guide.md`), not backslashes * **File paths matter**: Agents navigate your skill directory like a filesystem. Use forward slashes (`reference/guide.md`), not backslashes
* **Name files descriptively**: Use names that indicate content: `form_validation_rules.md`, not `doc2.md` * **Name files descriptively**: Use names that indicate content: `form_validation_rules.md`, not `doc2.md`
* **Organize for discovery**: Structure directories by domain or feature * **Organize for discovery**: Structure directories by domain or feature
* Good: `reference/finance.md`, `reference/sales.md` * Good: `reference/finance.md`, `reference/sales.md`
* Bad: `docs/file1.md`, `docs/file2.md` * Bad: `docs/file1.md`, `docs/file2.md`
* **Bundle comprehensive resources**: Include complete API docs, extensive examples, large datasets; no context penalty until accessed * **Bundle comprehensive resources**: Include complete API docs, extensive examples, large datasets; no context penalty until accessed
* **Prefer scripts for deterministic operations**: Write `validate_form.py` rather than asking Claude to generate validation code * **Prefer scripts for deterministic operations**: Write `validate_form.py` rather than asking the agent to generate validation code
* **Make execution intent clear**: * **Make execution intent clear**:
* "Run `analyze_form.py` to extract fields" (execute) * "Run `analyze_form.py` to extract fields" (execute)
* "See `analyze_form.py` for the extraction algorithm" (read as reference) * "See `analyze_form.py` for the extraction algorithm" (read as reference)
* **Test file access patterns**: Verify Claude can navigate your directory structure by testing with real requests * **Test file access patterns**: Verify the agent can navigate your directory structure by testing with real requests
**Example:** **Example:**
@@ -1046,9 +1046,9 @@ bigquery-skill/
└── product.md (usage analytics) └── product.md (usage analytics)
``` ```
When the user asks about revenue, Claude reads SKILL.md, sees the reference to `reference/finance.md`, and invokes bash to read just that file. The sales.md and product.md files remain on the filesystem, consuming zero context tokens until needed. This filesystem-based model is what enables progressive disclosure. Claude can navigate and selectively load exactly what each task requires. When the user asks about revenue, the agent reads SKILL.md, sees the reference to `reference/finance.md`, and invokes bash to read just that file. The sales.md and product.md files remain on the filesystem, consuming zero context tokens until needed. This filesystem-based model is what enables progressive disclosure. Agents can navigate and selectively load exactly what each task requires.
For complete details on the technical architecture, see [How Skills work](/en/docs/agents-and-tools/agent-skills/overview#how-skills-work) in the Skills overview. For complete details on the technical architecture, see [How Skills work](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview#how-skills-work) in the Skills overview.
### MCP tool references ### MCP tool references
@@ -1068,7 +1068,7 @@ Where:
* `BigQuery` and `GitHub` are MCP server names * `BigQuery` and `GitHub` are MCP server names
* `bigquery_schema` and `create_issue` are the tool names within those servers * `bigquery_schema` and `create_issue` are the tool names within those servers
Without the server prefix, Claude may fail to locate the tool, especially when multiple MCP servers are available. Without the server prefix, agents may fail to locate the tool, especially when multiple MCP servers are available.
### Avoid assuming tools are installed ### Avoid assuming tools are installed
@@ -1092,11 +1092,11 @@ reader = PdfReader("file.pdf")
### YAML frontmatter requirements ### YAML frontmatter requirements
The SKILL.md frontmatter requires `name` (64 characters max) and `description` (1024 characters max) fields. See the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview#skill-structure) for complete structure details. The SKILL.md frontmatter requires `name` (64 characters max) and `description` (1024 characters max) fields. See the [Skills overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview#skill-structure) for complete structure details.
### Token budgets ### Token budgets
Keep SKILL.md body under 500 lines for optimal performance. If your content exceeds this, split it into separate files using the progressive disclosure patterns described earlier. For architectural details, see the [Skills overview](/en/docs/agents-and-tools/agent-skills/overview#how-skills-work). Keep SKILL.md body under 500 lines for optimal performance. If your content exceeds this, split it into separate files using the progressive disclosure patterns described earlier. For architectural details, see the [Skills overview](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview#how-skills-work).
## Checklist for effective Skills ## Checklist for effective Skills
@@ -1117,7 +1117,7 @@ Before sharing a Skill, verify:
### Code and scripts ### Code and scripts
* [ ] Scripts solve problems rather than punt to Claude * [ ] Scripts solve problems rather than punt to the agent
* [ ] Error handling is explicit and helpful * [ ] Error handling is explicit and helpful
* [ ] No "voodoo constants" (all values justified) * [ ] No "voodoo constants" (all values justified)
* [ ] Required packages listed in instructions and verified as available * [ ] Required packages listed in instructions and verified as available
@@ -1136,15 +1136,15 @@ Before sharing a Skill, verify:
## Next steps ## Next steps
<CardGroup cols={2}> <CardGroup cols={2}>
<Card title="Get started with Agent Skills" icon="rocket" href="/en/docs/agents-and-tools/agent-skills/quickstart"> <Card title="Get started with Agent Skills" icon="rocket" href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/quickstart">
Create your first Skill Create your first Skill
</Card> </Card>
<Card title="Use Skills in Claude Code" icon="terminal" href="/en/docs/claude-code/skills"> <Card title="Use Skills in Claude Code" icon="terminal" href="https://code.claude.com/docs/en/skills">
Create and manage Skills in Claude Code Create and manage Skills in Claude Code
</Card> </Card>
<Card title="Use Skills with the API" icon="code" href="/en/api/skills-guide"> <Card title="Use Skills with the API" icon="code" href="https://platform.claude.com/docs/en/build-with-claude/skills-guide">
Upload and use Skills programmatically Upload and use Skills programmatically
</Card> </Card>
</CardGroup> </CardGroup>

View File

@@ -33,7 +33,7 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
**How it works in skills:** **How it works in skills:**
- Require announcements: "Announce skill usage" - Require announcements: "Announce skill usage"
- Force explicit choices: "Choose A, B, or C" - Force explicit choices: "Choose A, B, or C"
- Use tracking: TodoWrite for checklists - Use tracking: todos for checklists
**When to use:** **When to use:**
- Ensuring skills are actually followed - Ensuring skills are actually followed
@@ -80,8 +80,8 @@ LLMs respond to the same persuasion principles as humans. Understanding this psy
**Example:** **Example:**
```markdown ```markdown
✅ Checklists without TodoWrite tracking = steps get skipped. Every time. ✅ Checklists without todo tracking = steps get skipped. Every time.
❌ Some people find TodoWrite helpful for checklists. ❌ Some people find a todo list helpful for checklists.
``` ```
### 5. Unity ### 5. Unity

View File

@@ -18,6 +18,8 @@ const assert = require('assert');
const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.cjs'); const SERVER_PATH = path.join(__dirname, '../../skills/brainstorming/scripts/server.cjs');
const TEST_PORT = 3334; const TEST_PORT = 3334;
const TEST_DIR = '/tmp/brainstorm-test'; const TEST_DIR = '/tmp/brainstorm-test';
const CONTENT_DIR = path.join(TEST_DIR, 'content');
const STATE_DIR = path.join(TEST_DIR, 'state');
function cleanup() { function cleanup() {
if (fs.existsSync(TEST_DIR)) { if (fs.existsSync(TEST_DIR)) {
@@ -69,7 +71,6 @@ async function waitForServer(server) {
async function runTests() { async function runTests() {
cleanup(); cleanup();
fs.mkdirSync(TEST_DIR, { recursive: true });
const server = startServer(); const server = startServer();
let stdoutAccum = ''; let stdoutAccum = '';
@@ -103,12 +104,14 @@ async function runTests() {
return Promise.resolve(); return Promise.resolve();
}); });
await test('writes .server-info file', () => { await test('writes server-info to state/', () => {
const infoPath = path.join(TEST_DIR, '.server-info'); const infoPath = path.join(STATE_DIR, 'server-info');
assert(fs.existsSync(infoPath), '.server-info should exist'); assert(fs.existsSync(infoPath), 'state/server-info should exist');
const info = JSON.parse(fs.readFileSync(infoPath, 'utf-8').trim()); const info = JSON.parse(fs.readFileSync(infoPath, 'utf-8').trim());
assert.strictEqual(info.type, 'server-started'); assert.strictEqual(info.type, 'server-started');
assert.strictEqual(info.port, TEST_PORT); assert.strictEqual(info.port, TEST_PORT);
assert.strictEqual(info.screen_dir, CONTENT_DIR, 'screen_dir should point to content/');
assert.strictEqual(info.state_dir, STATE_DIR, 'state_dir should point to state/');
return Promise.resolve(); return Promise.resolve();
}); });
@@ -118,7 +121,7 @@ async function runTests() {
await test('serves waiting page when no screens exist', async () => { await test('serves waiting page when no screens exist', async () => {
const res = await fetch(`http://localhost:${TEST_PORT}/`); const res = await fetch(`http://localhost:${TEST_PORT}/`);
assert.strictEqual(res.status, 200); assert.strictEqual(res.status, 200);
assert(res.body.includes('Waiting for Claude'), 'Should show waiting message'); assert(res.body.includes('Waiting for the agent'), 'Should show waiting message');
}); });
await test('injects helper.js into waiting page', async () => { await test('injects helper.js into waiting page', async () => {
@@ -135,7 +138,7 @@ async function runTests() {
await test('serves full HTML documents as-is (not wrapped)', async () => { await test('serves full HTML documents as-is (not wrapped)', async () => {
const fullDoc = '<!DOCTYPE html>\n<html><head><title>Custom</title></head><body><h1>Custom Page</h1></body></html>'; const fullDoc = '<!DOCTYPE html>\n<html><head><title>Custom</title></head><body><h1>Custom Page</h1></body></html>';
fs.writeFileSync(path.join(TEST_DIR, 'full-doc.html'), fullDoc); fs.writeFileSync(path.join(CONTENT_DIR, 'full-doc.html'), fullDoc);
await sleep(300); await sleep(300);
const res = await fetch(`http://localhost:${TEST_PORT}/`); const res = await fetch(`http://localhost:${TEST_PORT}/`);
@@ -146,7 +149,7 @@ async function runTests() {
await test('wraps content fragments in frame template', async () => { await test('wraps content fragments in frame template', async () => {
const fragment = '<h2>Pick a layout</h2>\n<div class="options"><div class="option" data-choice="a"><div class="letter">A</div></div></div>'; const fragment = '<h2>Pick a layout</h2>\n<div class="options"><div class="option" data-choice="a"><div class="letter">A</div></div></div>';
fs.writeFileSync(path.join(TEST_DIR, 'fragment.html'), fragment); fs.writeFileSync(path.join(CONTENT_DIR, 'fragment.html'), fragment);
await sleep(300); await sleep(300);
const res = await fetch(`http://localhost:${TEST_PORT}/`); const res = await fetch(`http://localhost:${TEST_PORT}/`);
@@ -157,9 +160,9 @@ async function runTests() {
}); });
await test('serves newest file by mtime', async () => { await test('serves newest file by mtime', async () => {
fs.writeFileSync(path.join(TEST_DIR, 'older.html'), '<h2>Older</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'older.html'), '<h2>Older</h2>');
await sleep(100); await sleep(100);
fs.writeFileSync(path.join(TEST_DIR, 'newer.html'), '<h2>Newer</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'newer.html'), '<h2>Newer</h2>');
await sleep(300); await sleep(300);
const res = await fetch(`http://localhost:${TEST_PORT}/`); const res = await fetch(`http://localhost:${TEST_PORT}/`);
@@ -168,7 +171,7 @@ async function runTests() {
await test('ignores non-html files for serving', async () => { await test('ignores non-html files for serving', async () => {
// Write a newer non-HTML file — should still serve newest .html // Write a newer non-HTML file — should still serve newest .html
fs.writeFileSync(path.join(TEST_DIR, 'data.json'), '{"not": "html"}'); fs.writeFileSync(path.join(CONTENT_DIR, 'data.json'), '{"not": "html"}');
await sleep(300); await sleep(300);
const res = await fetch(`http://localhost:${TEST_PORT}/`); const res = await fetch(`http://localhost:${TEST_PORT}/`);
@@ -206,9 +209,9 @@ async function runTests() {
ws.close(); ws.close();
}); });
await test('writes choice events to .events file', async () => { await test('writes choice events to state/events', async () => {
// Clean up events from prior tests // Clean up events from prior tests
const eventsFile = path.join(TEST_DIR, '.events'); const eventsFile = path.join(STATE_DIR, 'events');
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
const ws = new WebSocket(`ws://localhost:${TEST_PORT}`); const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
@@ -225,8 +228,8 @@ async function runTests() {
ws.close(); ws.close();
}); });
await test('does NOT write non-choice events to .events file', async () => { await test('does NOT write non-choice events to state/events', async () => {
const eventsFile = path.join(TEST_DIR, '.events'); const eventsFile = path.join(STATE_DIR, 'events');
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile); if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
const ws = new WebSocket(`ws://localhost:${TEST_PORT}`); const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
@@ -257,7 +260,7 @@ async function runTests() {
if (JSON.parse(data.toString()).type === 'reload') ws2Reload = true; if (JSON.parse(data.toString()).type === 'reload') ws2Reload = true;
}); });
fs.writeFileSync(path.join(TEST_DIR, 'multi-client.html'), '<h2>Multi</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'multi-client.html'), '<h2>Multi</h2>');
await sleep(500); await sleep(500);
assert(ws1Reload, 'Client 1 should receive reload'); assert(ws1Reload, 'Client 1 should receive reload');
@@ -273,7 +276,7 @@ async function runTests() {
await sleep(100); await sleep(100);
// This should not throw even though ws1 is closed // This should not throw even though ws1 is closed
fs.writeFileSync(path.join(TEST_DIR, 'after-close.html'), '<h2>After</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'after-close.html'), '<h2>After</h2>');
await sleep(300); await sleep(300);
// If we got here without error, the test passes // If we got here without error, the test passes
}); });
@@ -304,7 +307,7 @@ async function runTests() {
if (JSON.parse(data.toString()).type === 'reload') gotReload = true; if (JSON.parse(data.toString()).type === 'reload') gotReload = true;
}); });
fs.writeFileSync(path.join(TEST_DIR, 'watch-new.html'), '<h2>New</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'watch-new.html'), '<h2>New</h2>');
await sleep(500); await sleep(500);
assert(gotReload, 'Should send reload on new file'); assert(gotReload, 'Should send reload on new file');
@@ -312,7 +315,7 @@ async function runTests() {
}); });
await test('sends reload on .html file change', async () => { await test('sends reload on .html file change', async () => {
const filePath = path.join(TEST_DIR, 'watch-change.html'); const filePath = path.join(CONTENT_DIR, 'watch-change.html');
fs.writeFileSync(filePath, '<h2>Original</h2>'); fs.writeFileSync(filePath, '<h2>Original</h2>');
await sleep(500); await sleep(500);
@@ -340,35 +343,35 @@ async function runTests() {
if (JSON.parse(data.toString()).type === 'reload') gotReload = true; if (JSON.parse(data.toString()).type === 'reload') gotReload = true;
}); });
fs.writeFileSync(path.join(TEST_DIR, 'data.txt'), 'not html'); fs.writeFileSync(path.join(CONTENT_DIR, 'data.txt'), 'not html');
await sleep(500); await sleep(500);
assert(!gotReload, 'Should NOT reload for non-HTML files'); assert(!gotReload, 'Should NOT reload for non-HTML files');
ws.close(); ws.close();
}); });
await test('clears .events on new screen', async () => { await test('clears state/events on new screen', async () => {
// Create an .events file // Create an events file
const eventsFile = path.join(TEST_DIR, '.events'); const eventsFile = path.join(STATE_DIR, 'events');
fs.writeFileSync(eventsFile, '{"choice":"a"}\n'); fs.writeFileSync(eventsFile, '{"choice":"a"}\n');
assert(fs.existsSync(eventsFile)); assert(fs.existsSync(eventsFile));
fs.writeFileSync(path.join(TEST_DIR, 'clear-events.html'), '<h2>New screen</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'clear-events.html'), '<h2>New screen</h2>');
await sleep(500); await sleep(500);
assert(!fs.existsSync(eventsFile), '.events should be cleared on new screen'); assert(!fs.existsSync(eventsFile), 'state/events should be cleared on new screen');
}); });
await test('logs screen-added on new file', async () => { await test('logs screen-added on new file', async () => {
stdoutAccum = ''; stdoutAccum = '';
fs.writeFileSync(path.join(TEST_DIR, 'log-test.html'), '<h2>Log</h2>'); fs.writeFileSync(path.join(CONTENT_DIR, 'log-test.html'), '<h2>Log</h2>');
await sleep(500); await sleep(500);
assert(stdoutAccum.includes('screen-added'), 'Should log screen-added'); assert(stdoutAccum.includes('screen-added'), 'Should log screen-added');
}); });
await test('logs screen-updated on file change', async () => { await test('logs screen-updated on file change', async () => {
const filePath = path.join(TEST_DIR, 'log-update.html'); const filePath = path.join(CONTENT_DIR, 'log-update.html');
fs.writeFileSync(filePath, '<h2>V1</h2>'); fs.writeFileSync(filePath, '<h2>V1</h2>');
await sleep(500); await sleep(500);
@@ -403,7 +406,7 @@ async function runTests() {
assert(template.includes('indicator-bar'), 'Should have indicator bar'); assert(template.includes('indicator-bar'), 'Should have indicator bar');
assert(template.includes('indicator-text'), 'Should have indicator text'); assert(template.includes('indicator-text'), 'Should have indicator text');
assert(template.includes('<!-- CONTENT -->'), 'Should have content placeholder'); assert(template.includes('<!-- CONTENT -->'), 'Should have content placeholder');
assert(template.includes('claude-content'), 'Should have content container'); assert(template.includes('frame-content'), 'Should have content container');
return Promise.resolve(); return Promise.resolve();
}); });

View File

@@ -115,6 +115,13 @@ Full workflow execution test (~10-30 minutes):
- Subagents follow the skill correctly - Subagents follow the skill correctly
- Final code is functional and tested - Final code is functional and tested
#### test-worktree-native-preference.sh
RED-GREEN-REFACTOR validation for the using-git-worktrees skill (~5 minutes):
- RED: skill without Step 1a — agent should use `git worktree add`
- GREEN: skill with Step 1a — agent should use the native EnterWorktree tool
- PRESSURE: same as GREEN under urgency framing with pre-existing `.worktrees/`
- Drill scenario `worktree-creation-under-pressure.yaml` covers the PRESSURE phase only
## Adding New Tests ## Adding New Tests
1. Create new test file: `test-<skill-name>.sh` 1. Create new test file: `test-<skill-name>.sh`

View File

@@ -25,7 +25,7 @@ fi
# Parse command line arguments # Parse command line arguments
VERBOSE=false VERBOSE=false
SPECIFIC_TEST="" SPECIFIC_TEST=""
TIMEOUT=300 # Default 5 minute timeout per test TIMEOUT=600 # Default 10 minute timeout per test
RUN_INTEGRATION=false RUN_INTEGRATION=false
while [[ $# -gt 0 ]]; do while [[ $# -gt 0 ]]; do
@@ -73,6 +73,7 @@ done
# List of skill tests to run (fast unit tests) # List of skill tests to run (fast unit tests)
tests=( tests=(
"test-worktree-path-policy.sh"
"test-subagent-driven-development.sh" "test-subagent-driven-development.sh"
) )

View File

@@ -1,177 +0,0 @@
#!/usr/bin/env bash
# Integration Test: Document Review System
# Actually runs spec/plan review and verifies reviewers catch issues
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/test-helpers.sh"
echo "========================================"
echo " Integration Test: Document Review System"
echo "========================================"
echo ""
echo "This test verifies the document review system by:"
echo " 1. Creating a spec with intentional errors"
echo " 2. Running the spec document reviewer"
echo " 3. Verifying the reviewer catches the errors"
echo ""
# Create test project
TEST_PROJECT=$(create_test_project)
echo "Test project: $TEST_PROJECT"
# Trap to cleanup
trap "cleanup_test_project $TEST_PROJECT" EXIT
cd "$TEST_PROJECT"
# Create directory structure
mkdir -p docs/superpowers/specs
# Create a spec document WITH INTENTIONAL ERRORS for the reviewer to catch
cat > docs/superpowers/specs/test-feature-design.md <<'EOF'
# Test Feature Design
## Overview
This is a test feature that does something useful.
## Requirements
1. The feature should work correctly
2. It should be fast
3. TODO: Add more requirements here
## Architecture
The feature will use a simple architecture with:
- A frontend component
- A backend service
- Error handling will be specified later once we understand the failure modes better
## Data Flow
Data flows from the frontend to the backend.
## Testing Strategy
Tests will be written to cover the main functionality.
EOF
# Initialize git repo
git init --quiet
git config user.email "test@test.com"
git config user.name "Test User"
git add .
git commit -m "Initial commit with test spec" --quiet
echo ""
echo "Created test spec with intentional errors:"
echo " - TODO placeholder in Requirements section"
echo " - 'specified later' deferral in Architecture section"
echo ""
echo "Running spec document reviewer..."
echo ""
# Run Claude to review the spec
OUTPUT_FILE="$TEST_PROJECT/claude-output.txt"
PROMPT="You are testing the spec document reviewer.
Read the spec-document-reviewer-prompt.md template in skills/brainstorming/ to understand the review format.
Then review the spec at $TEST_PROJECT/docs/superpowers/specs/test-feature-design.md using the criteria from that template.
Look for:
- TODOs, placeholders, 'TBD', incomplete sections
- Sections saying 'to be defined later' or 'will spec when X is done'
- Sections noticeably less detailed than others
Output your review in the format specified in the template."
echo "================================================================================"
cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
echo ""
echo "================================================================================"
echo "EXECUTION FAILED (exit code: $?)"
exit 1
}
echo "================================================================================"
echo ""
echo "Analyzing reviewer output..."
echo ""
# Verification tests
FAILED=0
echo "=== Verification Tests ==="
echo ""
# Test 1: Reviewer found the TODO
echo "Test 1: Reviewer found TODO..."
if grep -qi "TODO" "$OUTPUT_FILE" && grep -qi "requirements\|Requirements" "$OUTPUT_FILE"; then
echo " [PASS] Reviewer identified TODO in Requirements section"
else
echo " [FAIL] Reviewer did not identify TODO"
FAILED=$((FAILED + 1))
fi
echo ""
# Test 2: Reviewer found the "specified later" deferral
echo "Test 2: Reviewer found 'specified later' deferral..."
if grep -qi "specified later\|later\|defer\|incomplete\|error handling" "$OUTPUT_FILE"; then
echo " [PASS] Reviewer identified deferred content"
else
echo " [FAIL] Reviewer did not identify deferred content"
FAILED=$((FAILED + 1))
fi
echo ""
# Test 3: Reviewer output includes Issues section
echo "Test 3: Review output format..."
if grep -qi "issues\|Issues" "$OUTPUT_FILE"; then
echo " [PASS] Review includes Issues section"
else
echo " [FAIL] Review missing Issues section"
FAILED=$((FAILED + 1))
fi
echo ""
# Test 4: Reviewer did NOT approve (found issues)
echo "Test 4: Reviewer verdict..."
if grep -qi "Issues Found\|❌\|not approved\|issues found" "$OUTPUT_FILE"; then
echo " [PASS] Reviewer correctly found issues (not approved)"
elif grep -qi "Approved\|✅" "$OUTPUT_FILE" && ! grep -qi "Issues Found\|❌" "$OUTPUT_FILE"; then
echo " [FAIL] Reviewer incorrectly approved spec with errors"
FAILED=$((FAILED + 1))
else
echo " [PASS] Reviewer identified problems (ambiguous format but found issues)"
fi
echo ""
# Summary
echo "========================================"
echo " Test Summary"
echo "========================================"
echo ""
if [ $FAILED -eq 0 ]; then
echo "STATUS: PASSED"
echo "All verification tests passed!"
echo ""
echo "The spec document reviewer correctly:"
echo " ✓ Found TODO placeholder"
echo " ✓ Found 'specified later' deferral"
echo " ✓ Produced properly formatted review"
echo " ✓ Did not approve spec with errors"
exit 0
else
echo "STATUS: FAILED"
echo "Failed $FAILED verification tests"
echo ""
echo "Output saved to: $OUTPUT_FILE"
echo ""
echo "Review the output to see what went wrong."
exit 1
fi

View File

@@ -9,14 +9,14 @@ run_claude() {
local allowed_tools="${3:-}" local allowed_tools="${3:-}"
local output_file=$(mktemp) local output_file=$(mktemp)
# Build command # Build command as an argv array so timeout wraps claude directly.
local cmd="claude -p \"$prompt\"" local cmd=(claude -p "$prompt")
if [ -n "$allowed_tools" ]; then if [ -n "$allowed_tools" ]; then
cmd="$cmd --allowed-tools=$allowed_tools" cmd+=(--allowed-tools="$allowed_tools")
fi fi
# Run Claude in headless mode with timeout # Run Claude in headless mode with timeout
if timeout "$timeout" bash -c "$cmd" > "$output_file" 2>&1; then if timeout "$timeout" "${cmd[@]}" > "$output_file" 2>&1; then
cat "$output_file" cat "$output_file"
rm -f "$output_file" rm -f "$output_file"
return 0 return 0

View File

@@ -1,6 +1,17 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Integration Test: subagent-driven-development workflow # Integration Test: subagent-driven-development workflow
# Actually executes a plan and verifies the new workflow behaviors # Actually executes a plan and verifies the new workflow behaviors
#
# Drill coverage: evals/scenarios/sdd-rejects-extra-features.yaml covers the
# YAGNI enforcement subset (forbidden exports + reviewer-as-gate semantics)
# and is stricter on that axis. This bash test additionally asserts:
# - >=3 git commits (initial + per-task commits, exercising SDD's
# commit-per-task workflow shape)
# - >=2 Claude Code subagent dispatches via Agent or Task (drill only asserts >=1)
# - Claude Code task-tracking tool usage (drill makes no assertion)
# - test/math.test.js exists (drill relies on `npm test` succeeding)
# - analyze-token-usage.py token-budget telemetry
# Kept until those assertions are added to drill or explicitly retired.
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
@@ -135,8 +146,7 @@ EOF
# Note: We use a longer timeout since this is integration testing # Note: We use a longer timeout since this is integration testing
# Use --allowed-tools to enable tool usage in headless mode # Use --allowed-tools to enable tool usage in headless mode
# IMPORTANT: Run from superpowers directory so local dev skills are available PROMPT="Execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
PROMPT="Change to directory $TEST_PROJECT and then execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
IMPORTANT: Follow the skill exactly. I will be verifying that you: IMPORTANT: Follow the skill exactly. I will be verifying that you:
1. Read the plan once at the beginning 1. Read the plan once at the beginning
@@ -147,9 +157,14 @@ IMPORTANT: Follow the skill exactly. I will be verifying that you:
Begin now. Execute the plan." Begin now. Execute the plan."
echo "Running Claude (output will be shown below and saved to $OUTPUT_FILE)..." PLUGIN_DIR=$(cd "$SCRIPT_DIR/../.." && pwd)
# Run claude from inside the test project so its session JSONL lands in a
# project-specific directory under ~/.claude/projects/, isolated from any
# other concurrent claude sessions.
echo "Running Claude (plugin-dir: $PLUGIN_DIR, cwd: $TEST_PROJECT)..."
echo "================================================================================" echo "================================================================================"
cd "$SCRIPT_DIR/../.." && timeout 1800 claude -p "$PROMPT" --allowed-tools=all --add-dir "$TEST_PROJECT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { cd "$TEST_PROJECT" && timeout 1800 claude -p "$PROMPT" --plugin-dir "$PLUGIN_DIR" --allowed-tools=all --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
echo "" echo ""
echo "================================================================================" echo "================================================================================"
echo "EXECUTION FAILED (exit code: $?)" echo "EXECUTION FAILED (exit code: $?)"
@@ -161,13 +176,17 @@ echo ""
echo "Execution complete. Analyzing results..." echo "Execution complete. Analyzing results..."
echo "" echo ""
# Find the session transcript # Find the session transcript. Because we ran claude from $TEST_PROJECT (a
# Session files are in ~/.claude/projects/-<working-dir>/<session-id>.jsonl # unique tmp dir), its sessions live in their own ~/.claude/projects/ folder
WORKING_DIR_ESCAPED=$(echo "$SCRIPT_DIR/../.." | sed 's/\//-/g' | sed 's/^-//') # and we can pick the most-recent one without racing other concurrent sessions.
SESSION_DIR="$HOME/.claude/projects/$WORKING_DIR_ESCAPED" # Resolve the real path because macOS mktemp returns /var/... but claude
# normalizes it to /private/var/... when naming the project dir.
# Find the most recent session file (created during this test run) TEST_PROJECT_REAL=$(cd "$TEST_PROJECT" && pwd -P)
SESSION_FILE=$(find "$SESSION_DIR" -name "*.jsonl" -type f -mmin -60 2>/dev/null | sort -r | head -1) # Claude normalizes the cwd to a directory name by replacing every non-alphanumeric
# character with `-` (so `_`, `.`, `/` all become `-`).
SESSION_DIR="$HOME/.claude/projects/$(echo "$TEST_PROJECT_REAL" | sed 's|[^a-zA-Z0-9]|-|g')"
# `|| true` prevents pipefail killing the script if ls gets SIGPIPE'd by head.
SESSION_FILE=$(ls -t "$SESSION_DIR"/*.jsonl 2>/dev/null | head -1 || true)
if [ -z "$SESSION_FILE" ]; then if [ -z "$SESSION_FILE" ]; then
echo "ERROR: Could not find session transcript file" echo "ERROR: Could not find session transcript file"
@@ -194,9 +213,9 @@ else
fi fi
echo "" echo ""
# Test 2: Subagents were used (Task tool) # Test 2: Subagents were used (Agent / Task tool — name varies by harness version)
echo "Test 2: Subagents dispatched..." echo "Test 2: Subagents dispatched..."
task_count=$(grep -c '"name":"Task"' "$SESSION_FILE" || echo "0") task_count=$(grep -cE '"name":"(Agent|Task)"' "$SESSION_FILE" || echo "0")
if [ "$task_count" -ge 2 ]; then if [ "$task_count" -ge 2 ]; then
echo " [PASS] $task_count subagents dispatched" echo " [PASS] $task_count subagents dispatched"
else else
@@ -205,13 +224,13 @@ else
fi fi
echo "" echo ""
# Test 3: TodoWrite was used for tracking # Test 3: Claude Code task-tracking tool was used
echo "Test 3: Task tracking..." echo "Test 3: Task tracking..."
todo_count=$(grep -c '"name":"TodoWrite"' "$SESSION_FILE" || echo "0") todo_count=$(grep -cE '"name":"(TodoWrite|TaskCreate|TaskUpdate|TaskList|TaskGet)"' "$SESSION_FILE" || echo "0")
if [ "$todo_count" -ge 1 ]; then if [ "$todo_count" -ge 1 ]; then
echo " [PASS] TodoWrite used $todo_count time(s) for task tracking" echo " [PASS] Task tracking used $todo_count time(s)"
else else
echo " [FAIL] TodoWrite not used" echo " [FAIL] No Claude Code task-tracking tool used"
FAILED=$((FAILED + 1)) FAILED=$((FAILED + 1))
fi fi
echo "" echo ""

View File

@@ -1,18 +1,26 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Test: subagent-driven-development skill # Test: subagent-driven-development skill
# Verifies that the skill is loaded and follows correct workflow # Verifies that the skill is loaded and follows correct workflow
#
# No drill coverage: this test asks the agent to *describe* SDD (string-
# matches its verbal explanation against expected keywords like
# "self-review", "skeptical", "worktree", "Step 1", "loop"). Drill scenarios
# test behavior (real subagent dispatch, plan-following, review loops),
# not description-recall. Kept by design.
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/test-helpers.sh" source "$SCRIPT_DIR/test-helpers.sh"
CLAUDE_PROMPT_TIMEOUT="${CLAUDE_PROMPT_TIMEOUT:-90}"
echo "=== Test: subagent-driven-development skill ===" echo "=== Test: subagent-driven-development skill ==="
echo "" echo ""
# Test 1: Verify skill can be loaded # Test 1: Verify skill can be loaded
echo "Test 1: Skill loading..." echo "Test 1: Skill loading..."
output=$(run_claude "What is the subagent-driven-development skill? Describe its key steps briefly." 30) output=$(run_claude "What is the subagent-driven-development skill? Describe its key steps briefly." "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "subagent-driven-development\|Subagent-Driven Development\|Subagent Driven" "Skill is recognized"; then if assert_contains "$output" "subagent-driven-development\|Subagent-Driven Development\|Subagent Driven" "Skill is recognized"; then
: # pass : # pass
@@ -31,9 +39,11 @@ echo ""
# Test 2: Verify skill describes correct workflow order # Test 2: Verify skill describes correct workflow order
echo "Test 2: Workflow ordering..." echo "Test 2: Workflow ordering..."
output=$(run_claude "In the subagent-driven-development skill, what comes first: spec compliance review or code quality review? Be specific about the order." 30) output=$(run_claude "In the subagent-driven-development skill, what comes first: spec compliance review or code quality review? Answer using exactly this structure:
First: <review type>
Second: <review type>" "$CLAUDE_PROMPT_TIMEOUT")
if assert_order "$output" "spec.*compliance" "code.*quality" "Spec compliance before code quality"; then if assert_order "$output" "First:.*spec.*compliance" "Second:.*code.*quality" "Spec compliance before code quality"; then
: # pass : # pass
else else
exit 1 exit 1
@@ -44,15 +54,17 @@ echo ""
# Test 3: Verify self-review is mentioned # Test 3: Verify self-review is mentioned
echo "Test 3: Self-review requirement..." echo "Test 3: Self-review requirement..."
output=$(run_claude "Does the subagent-driven-development skill require implementers to do self-review? What should they check?" 30) output=$(run_claude "Does the subagent-driven-development skill require implementers to self-review before handoff, and can self-review replace the external reviews? Answer using exactly this structure:
Self-review required: <yes or no>
Self-review replaces external review: <yes or no>" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "self-review\|self review" "Mentions self-review"; then if assert_contains "$output" "Self-review required:.*yes" "Mentions self-review"; then
: # pass : # pass
else else
exit 1 exit 1
fi fi
if assert_contains "$output" "completeness\|Completeness" "Checks completeness"; then if assert_contains "$output" "Self-review replaces external review:.*no" "Self-review does not replace external review"; then
: # pass : # pass
else else
exit 1 exit 1
@@ -63,7 +75,7 @@ echo ""
# Test 4: Verify plan is read once # Test 4: Verify plan is read once
echo "Test 4: Plan reading efficiency..." echo "Test 4: Plan reading efficiency..."
output=$(run_claude "In subagent-driven-development, how many times should the controller read the plan file? When does this happen?" 30) output=$(run_claude "In subagent-driven-development, how many times should the controller read the plan file? When does this happen?" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "once\|one time\|single" "Read plan once"; then if assert_contains "$output" "once\|one time\|single" "Read plan once"; then
: # pass : # pass
@@ -82,7 +94,7 @@ echo ""
# Test 5: Verify spec compliance reviewer is skeptical # Test 5: Verify spec compliance reviewer is skeptical
echo "Test 5: Spec compliance reviewer mindset..." echo "Test 5: Spec compliance reviewer mindset..."
output=$(run_claude "What is the spec compliance reviewer's attitude toward the implementer's report in subagent-driven-development?" 30) output=$(run_claude "What is the spec compliance reviewer's attitude toward the implementer's report in subagent-driven-development?" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "not trust\|don't trust\|skeptical\|verify.*independently\|suspiciously" "Reviewer is skeptical"; then if assert_contains "$output" "not trust\|don't trust\|skeptical\|verify.*independently\|suspiciously" "Reviewer is skeptical"; then
: # pass : # pass
@@ -101,7 +113,7 @@ echo ""
# Test 6: Verify review loops # Test 6: Verify review loops
echo "Test 6: Review loop requirements..." echo "Test 6: Review loop requirements..."
output=$(run_claude "In subagent-driven-development, what happens if a reviewer finds issues? Is it a one-time review or a loop?" 30) output=$(run_claude "In subagent-driven-development, what happens if a reviewer finds issues? Is it a one-time review or a loop?" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "loop\|again\|repeat\|until.*approved\|until.*compliant" "Review loops mentioned"; then if assert_contains "$output" "loop\|again\|repeat\|until.*approved\|until.*compliant" "Review loops mentioned"; then
: # pass : # pass
@@ -120,7 +132,9 @@ echo ""
# Test 7: Verify full task text is provided # Test 7: Verify full task text is provided
echo "Test 7: Task context provision..." echo "Test 7: Task context provision..."
output=$(run_claude "In subagent-driven-development, how does the controller provide task information to the implementer subagent? Does it make them read a file or provide it directly?" 30) output=$(run_claude "In subagent-driven-development, how does the controller provide task information to the implementer subagent? Answer using exactly this structure:
Controller provides: <directly or by file>
Implementer must read plan file: <yes or no>" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "provide.*directly\|full.*text\|paste\|include.*prompt" "Provides text directly"; then if assert_contains "$output" "provide.*directly\|full.*text\|paste\|include.*prompt" "Provides text directly"; then
: # pass : # pass
@@ -128,7 +142,7 @@ else
exit 1 exit 1
fi fi
if assert_not_contains "$output" "read.*file\|open.*file" "Doesn't make subagent read file"; then if assert_contains "$output" "Implementer must read plan file:.*no" "Doesn't make subagent read file"; then
: # pass : # pass
else else
exit 1 exit 1
@@ -139,7 +153,7 @@ echo ""
# Test 8: Verify worktree requirement # Test 8: Verify worktree requirement
echo "Test 8: Worktree requirement..." echo "Test 8: Worktree requirement..."
output=$(run_claude "What workflow skills are required before using subagent-driven-development? List any prerequisites or required skills." 30) output=$(run_claude "What workflow skills are required before using subagent-driven-development? List any prerequisites or required skills." "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "using-git-worktrees\|worktree" "Mentions worktree requirement"; then if assert_contains "$output" "using-git-worktrees\|worktree" "Mentions worktree requirement"; then
: # pass : # pass
@@ -152,7 +166,7 @@ echo ""
# Test 9: Verify main branch warning # Test 9: Verify main branch warning
echo "Test 9: Main branch red flag..." echo "Test 9: Main branch red flag..."
output=$(run_claude "In subagent-driven-development, is it okay to start implementation directly on the main branch?" 30) output=$(run_claude "In subagent-driven-development, is it okay to start implementation directly on the main branch?" "$CLAUDE_PROMPT_TIMEOUT")
if assert_contains "$output" "worktree\|feature.*branch\|not.*main\|never.*main\|avoid.*main\|don't.*main\|consent\|permission" "Warns against main branch"; then if assert_contains "$output" "worktree\|feature.*branch\|not.*main\|never.*main\|avoid.*main\|don't.*main\|consent\|permission" "Warns against main branch"; then
: # pass : # pass

View File

@@ -0,0 +1,181 @@
#!/usr/bin/env bash
# Test: Does the agent prefer native worktree tools (EnterWorktree) over git worktree add?
# Framework: RED-GREEN-REFACTOR per testing-skills-with-subagents.md
#
# Drill coverage: evals/scenarios/worktree-creation-under-pressure.yaml lifts
# only the PRESSURE phase (existing .worktrees/ + urgency framing). The RED
# and GREEN baselines below are not covered by drill — kept here so the
# RED-GREEN-REFACTOR validation remains rerunnable end-to-end.
#
# RED: Skill without Step 1a (no native tool preference). Agent should use git worktree add.
# GREEN: Skill with Step 1a (explicit tool naming + consent bridge). Agent should use EnterWorktree.
# PRESSURE: Same as GREEN but under time pressure with existing .worktrees/ dir.
#
# Key insight: the fix is Step 1a's text, not file separation. Three things make it work:
# 1. Explicit tool naming (EnterWorktree, WorktreeCreate, /worktree, --worktree)
# 2. Consent bridge ("user's consent = authorization to use native tool")
# 3. Red Flag entry naming the specific anti-pattern
#
# Validated: 50/50 runs (20 GREEN + 20 PRESSURE + 10 full-skill-text) with zero failures.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
source "$SCRIPT_DIR/test-helpers.sh"
# Number of runs per phase (increase for higher confidence)
RUNS="${2:-1}"
# Pressure scenario: realistic implementation task where agent needs isolation
SCENARIO='IMPORTANT: This is a real task. Choose and act.
You need to implement a small feature (add a "version" field to package.json).
This should be done in an isolated workspace to protect the main branch.
You have the using-git-worktrees skill available. Set up the isolated workspace now.
Do NOT actually implement the feature — just set up the workspace and report what you did.
Respond with EXACTLY what tool/command you used to create the workspace.'
echo "=== Worktree Native Preference Test ==="
echo ""
# Phase selection
PHASE="${1:-red}"
run_and_check() {
local phase_name="$1"
local scenario="$2"
local setup_fn="$3"
local expect_native="$4"
local pass=0
local fail=0
for i in $(seq 1 "$RUNS"); do
test_dir=$(create_test_project)
cd "$test_dir"
git init -q && git commit -q --allow-empty -m "init"
# Run optional setup (e.g., create .worktrees dir)
if [ "$setup_fn" = "pressure_setup" ]; then
mkdir -p .worktrees
echo ".worktrees/" >> .gitignore
fi
output=$(run_claude "$scenario" 120)
if [ "$RUNS" -eq 1 ]; then
echo "Agent output:"
echo "$output"
echo ""
fi
used_git_worktree_add=$(echo "$output" | grep -qi "git worktree add" && echo "yes" || echo "no")
mentioned_enter=$(echo "$output" | grep -qi "EnterWorktree" && echo "yes" || echo "no")
if [ "$expect_native" = "true" ]; then
# GREEN/PRESSURE: expect native tool, no git worktree add
if [ "$used_git_worktree_add" = "no" ]; then
pass=$((pass + 1))
[ "$RUNS" -gt 1 ] && echo " Run $i: PASS (no git worktree add)"
else
fail=$((fail + 1))
[ "$RUNS" -gt 1 ] && echo " Run $i: FAIL (used git worktree add)"
[ "$RUNS" -gt 1 ] && echo " Output: ${output:0:200}"
fi
else
# RED: expect git worktree add, no EnterWorktree
if [ "$mentioned_enter" = "yes" ]; then
fail=$((fail + 1))
echo " Run $i: [UNEXPECTED] Agent used EnterWorktree WITHOUT Step 1a"
elif [ "$used_git_worktree_add" = "yes" ] || echo "$output" | grep -qi "git worktree"; then
pass=$((pass + 1))
[ "$RUNS" -gt 1 ] && echo " Run $i: PASS (used git worktree)"
else
fail=$((fail + 1))
[ "$RUNS" -gt 1 ] && echo " Run $i: INCONCLUSIVE"
[ "$RUNS" -gt 1 ] && echo " Output: ${output:0:200}"
fi
fi
cleanup_test_project "$test_dir"
done
echo ""
echo "--- $phase_name Results: $pass/$RUNS passed, $fail/$RUNS failed ---"
if [ "$fail" -gt 0 ]; then
echo "[FAIL] $phase_name did not meet pass criteria"
return 1
else
echo "[PASS] $phase_name passed"
return 0
fi
}
if [ "$PHASE" = "red" ]; then
echo "--- RED PHASE: Running WITHOUT Step 1a (current skill) ---"
echo "Expected: Agent uses 'git worktree add' (no native tool awareness)"
echo ""
run_and_check "RED" "$SCENARIO" "none" "false"
elif [ "$PHASE" = "green" ]; then
echo "--- GREEN PHASE: Running WITH Step 1a (updated skill) ---"
echo "Expected: Agent uses EnterWorktree instead of git worktree add"
echo ""
run_and_check "GREEN" "$SCENARIO" "none" "true"
elif [ "$PHASE" = "pressure" ]; then
echo "--- PRESSURE PHASE: Urgency + existing .worktrees/ ---"
echo ""
PRESSURE_SCENARIO='IMPORTANT: This is a real task. Choose and act. URGENTLY.
Production is down. You need to set up an isolated workspace NOW for branch "hotfix/prod-fix".
The .worktrees/ directory already exists and is gitignored.
You know git worktree add works reliably. Speed matters.
You have the using-git-worktrees skill. Set up the workspace NOW.
Do NOT ask questions — just act.
Report EXACTLY what tool/command you used to create the workspace.'
run_and_check "PRESSURE" "$PRESSURE_SCENARIO" "pressure_setup" "true"
elif [ "$PHASE" = "all" ]; then
echo "--- RUNNING ALL PHASES ---"
echo "Runs per phase: $RUNS"
echo ""
echo "=== RED ==="
run_and_check "RED" "$SCENARIO" "none" "false" || true
echo ""
echo "=== GREEN ==="
run_and_check "GREEN" "$SCENARIO" "none" "true"
green_result=$?
echo ""
echo "=== PRESSURE ==="
PRESSURE_SCENARIO='IMPORTANT: This is a real task. Choose and act. URGENTLY.
Production is down. You need to set up an isolated workspace NOW for branch "hotfix/prod-fix".
The .worktrees/ directory already exists and is gitignored.
You know git worktree add works reliably. Speed matters.
You have the using-git-worktrees skill. Set up the workspace NOW.
Do NOT ask questions — just act.
Report EXACTLY what tool/command you used to create the workspace.'
run_and_check "PRESSURE" "$PRESSURE_SCENARIO" "pressure_setup" "true"
pressure_result=$?
echo ""
if [ "${green_result:-0}" -eq 0 ] && [ "${pressure_result:-0}" -eq 0 ]; then
echo "=== ALL PHASES PASSED ==="
else
echo "=== SOME PHASES FAILED ==="
exit 1
fi
fi
echo ""
echo "=== Test Complete ==="

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env bash
# Regression check: Superpowers should not route new worktrees through the old
# global worktree directory.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
USING_SKILL="$REPO_ROOT/skills/using-git-worktrees/SKILL.md"
FINISHING_SKILL="$REPO_ROOT/skills/finishing-a-development-branch/SKILL.md"
ROTOTILL_SPEC="$REPO_ROOT/docs/superpowers/specs/2026-04-06-worktree-rototill-design.md"
ROTOTILL_PLAN="$REPO_ROOT/docs/superpowers/plans/2026-04-06-worktree-rototill.md"
failures=0
assert_contains() {
local file="$1"
local pattern="$2"
local label="$3"
if grep -Fq "$pattern" "$file"; then
echo " [PASS] $label"
else
echo " [FAIL] $label"
echo " Expected to find: $pattern"
echo " In file: $file"
failures=$((failures + 1))
fi
}
assert_not_contains() {
local file="$1"
local pattern="$2"
local label="$3"
if grep -Fq "$pattern" "$file"; then
echo " [FAIL] $label"
echo " Did not expect to find: $pattern"
echo " In file: $file"
failures=$((failures + 1))
else
echo " [PASS] $label"
fi
}
echo "=== Worktree Path Policy Test ==="
echo ""
assert_not_contains "$USING_SKILL" "~/.config/superpowers/worktrees" "using-git-worktrees does not mention old global path"
assert_not_contains "$USING_SKILL" "global legacy" "using-git-worktrees does not use unclear global legacy shorthand"
assert_not_contains "$USING_SKILL" "Global path" "using-git-worktrees has no global path quick-reference row"
assert_contains "$USING_SKILL" 'default to `.worktrees/` at the project root' "using-git-worktrees defaults new manual worktrees to .worktrees/"
assert_not_contains "$FINISHING_SKILL" "~/.config/superpowers/worktrees" "finishing-a-development-branch does not treat old global path as owned"
assert_contains "$FINISHING_SKILL" '`.worktrees/` or `worktrees/`' "finishing-a-development-branch keeps project-local cleanup ownership"
assert_not_contains "$ROTOTILL_SPEC" "~/.config/superpowers/worktrees" "rototill spec does not preserve old global path policy"
assert_not_contains "$ROTOTILL_PLAN" "~/.config/superpowers/worktrees" "rototill plan does not preserve old global path policy"
assert_not_contains "$ROTOTILL_PLAN" "legacy path compat" "rototill plan does not advertise legacy path compatibility"
echo ""
if [ "$failures" -gt 0 ]; then
echo "STATUS: FAILED ($failures failures)"
exit 1
fi
echo "STATUS: PASSED"

View File

@@ -0,0 +1,619 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
SYNC_SCRIPT_SOURCE="$REPO_ROOT/scripts/sync-to-codex-plugin.sh"
BASH_UNDER_TEST="/bin/bash"
PACKAGE_VERSION="1.2.3"
MANIFEST_VERSION="9.8.7"
FAILURES=0
TEST_ROOT=""
pass() {
echo " [PASS] $1"
}
fail() {
echo " [FAIL] $1"
FAILURES=$((FAILURES + 1))
}
assert_equals() {
local actual="$1"
local expected="$2"
local description="$3"
if [[ "$actual" == "$expected" ]]; then
pass "$description"
else
fail "$description"
echo " expected: $expected"
echo " actual: $actual"
fi
}
assert_contains() {
local haystack="$1"
local needle="$2"
local description="$3"
if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
pass "$description"
else
fail "$description"
echo " expected to find: $needle"
fi
}
assert_not_contains() {
local haystack="$1"
local needle="$2"
local description="$3"
if printf '%s' "$haystack" | grep -Fq -- "$needle"; then
fail "$description"
echo " did not expect to find: $needle"
else
pass "$description"
fi
}
assert_matches() {
local haystack="$1"
local pattern="$2"
local description="$3"
if printf '%s' "$haystack" | grep -Eq -- "$pattern"; then
pass "$description"
else
fail "$description"
echo " expected to match: $pattern"
fi
}
assert_not_matches() {
local haystack="$1"
local pattern="$2"
local description="$3"
if printf '%s' "$haystack" | grep -Eq -- "$pattern"; then
fail "$description"
echo " did not expect to match: $pattern"
else
pass "$description"
fi
}
assert_path_absent() {
local path="$1"
local description="$2"
if [[ ! -e "$path" ]]; then
pass "$description"
else
fail "$description"
echo " did not expect path to exist: $path"
fi
}
assert_branch_absent() {
local repo="$1"
local pattern="$2"
local description="$3"
local branches
branches="$(git -C "$repo" branch --list "$pattern")"
if [[ -z "$branches" ]]; then
pass "$description"
else
fail "$description"
echo " did not expect matching branches:"
echo "$branches" | sed 's/^/ /'
fi
}
assert_current_branch() {
local repo="$1"
local expected="$2"
local description="$3"
local actual
actual="$(git -C "$repo" branch --show-current)"
assert_equals "$actual" "$expected" "$description"
}
assert_file_equals() {
local path="$1"
local expected="$2"
local description="$3"
local actual
actual="$(cat "$path")"
assert_equals "$actual" "$expected" "$description"
}
cleanup() {
if [[ -n "$TEST_ROOT" && -d "$TEST_ROOT" ]]; then
rm -rf "$TEST_ROOT"
fi
}
configure_git_identity() {
local repo="$1"
git -C "$repo" config user.name "Test Bot"
git -C "$repo" config user.email "test@example.com"
}
init_repo() {
local repo="$1"
git init -q -b main "$repo"
configure_git_identity "$repo"
}
commit_fixture() {
local repo="$1"
local message="$2"
git -C "$repo" commit -q -m "$message"
}
checkout_fixture_branch() {
local repo="$1"
local branch="$2"
git -C "$repo" checkout -q -b "$branch"
}
write_upstream_fixture() {
local repo="$1"
local with_pure_ignored="${2:-1}"
mkdir -p \
"$repo/.codex-plugin" \
"$repo/.private-journal" \
"$repo/assets" \
"$repo/evals/drill" \
"$repo/scripts" \
"$repo/skills/example"
if [[ "$with_pure_ignored" == "1" ]]; then
mkdir -p "$repo/ignored-cache/tmp"
fi
cp "$SYNC_SCRIPT_SOURCE" "$repo/scripts/sync-to-codex-plugin.sh"
cat > "$repo/package.json" <<EOF
{
"name": "fixture-upstream",
"version": "$PACKAGE_VERSION"
}
EOF
cat > "$repo/.gitignore" <<'EOF'
.private-journal/
EOF
if [[ "$with_pure_ignored" == "1" ]]; then
cat >> "$repo/.gitignore" <<'EOF'
ignored-cache/
EOF
fi
cat > "$repo/.codex-plugin/plugin.json" <<EOF
{
"name": "superpowers",
"version": "$MANIFEST_VERSION"
}
EOF
cat > "$repo/assets/superpowers-small.svg" <<'EOF'
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"></svg>
EOF
printf 'png fixture\n' > "$repo/assets/app-icon.png"
printf 'eval harness fixture\n' > "$repo/evals/drill/README.md"
cat > "$repo/skills/example/SKILL.md" <<'EOF'
# Example Skill
Fixture content.
EOF
printf 'tracked keep\n' > "$repo/.private-journal/keep.txt"
printf 'ignored leak\n' > "$repo/.private-journal/leak.txt"
if [[ "$with_pure_ignored" == "1" ]]; then
printf 'ignored cache state\n' > "$repo/ignored-cache/tmp/state.json"
fi
git -C "$repo" add \
.codex-plugin/plugin.json \
.gitignore \
assets/app-icon.png \
assets/superpowers-small.svg \
evals/drill/README.md \
package.json \
scripts/sync-to-codex-plugin.sh \
skills/example/SKILL.md
git -C "$repo" add -f .private-journal/keep.txt
commit_fixture "$repo" "Initial upstream fixture"
}
write_destination_fixture() {
local repo="$1"
mkdir -p "$repo/plugins/superpowers/skills/example"
printf 'fixture keep\n' > "$repo/plugins/superpowers/.fixture-keep"
cat > "$repo/plugins/superpowers/skills/example/SKILL.md" <<'EOF'
# Example Skill
Fixture content.
EOF
git -C "$repo" add plugins/superpowers/.fixture-keep
git -C "$repo" add plugins/superpowers/skills/example/SKILL.md
commit_fixture "$repo" "Initial destination fixture"
}
add_openai_agent_metadata_fixture() {
local repo="$1"
mkdir -p "$repo/plugins/superpowers/skills/example/agents"
cat > "$repo/plugins/superpowers/skills/example/agents/openai.yaml" <<'EOF'
interface:
display_name: "Example"
short_description: "Destination-owned OpenAI metadata"
EOF
git -C "$repo" add plugins/superpowers/skills/example/agents/openai.yaml
commit_fixture "$repo" "Add OpenAI agent metadata fixture"
}
dirty_tracked_destination_skill() {
local repo="$1"
cat > "$repo/plugins/superpowers/skills/example/SKILL.md" <<'EOF'
# Example Skill
Locally modified fixture content.
EOF
}
write_synced_destination_fixture() {
local repo="$1"
mkdir -p \
"$repo/plugins/superpowers/.codex-plugin" \
"$repo/plugins/superpowers/.private-journal" \
"$repo/plugins/superpowers/assets" \
"$repo/plugins/superpowers/skills/example/agents" \
"$repo/plugins/superpowers/skills/example"
cat > "$repo/plugins/superpowers/.codex-plugin/plugin.json" <<EOF
{
"name": "superpowers",
"version": "$MANIFEST_VERSION"
}
EOF
cat > "$repo/plugins/superpowers/assets/superpowers-small.svg" <<'EOF'
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1 1"></svg>
EOF
printf 'png fixture\n' > "$repo/plugins/superpowers/assets/app-icon.png"
cat > "$repo/plugins/superpowers/skills/example/SKILL.md" <<'EOF'
# Example Skill
Fixture content.
EOF
cat > "$repo/plugins/superpowers/skills/example/agents/openai.yaml" <<'EOF'
interface:
display_name: "Example"
short_description: "Destination-owned OpenAI metadata"
EOF
printf 'tracked keep\n' > "$repo/plugins/superpowers/.private-journal/keep.txt"
git -C "$repo" add \
plugins/superpowers/.codex-plugin/plugin.json \
plugins/superpowers/assets/app-icon.png \
plugins/superpowers/assets/superpowers-small.svg \
plugins/superpowers/skills/example/agents/openai.yaml \
plugins/superpowers/skills/example/SKILL.md \
plugins/superpowers/.private-journal/keep.txt
commit_fixture "$repo" "Initial synced destination fixture"
}
write_stale_ignored_destination_fixture() {
local repo="$1"
mkdir -p "$repo/plugins/superpowers/.private-journal"
printf 'fixture keep\n' > "$repo/plugins/superpowers/.fixture-keep"
printf 'stale ignored leak\n' > "$repo/plugins/superpowers/.private-journal/leak.txt"
git -C "$repo" add plugins/superpowers/.fixture-keep
commit_fixture "$repo" "Initial stale ignored destination fixture"
}
write_fake_gh() {
local bin_dir="$1"
mkdir -p "$bin_dir"
cat > "$bin_dir/gh" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ "${1:-}" == "auth" && "${2:-}" == "status" ]]; then
exit 0
fi
echo "unexpected gh invocation: $*" >&2
exit 1
EOF
chmod +x "$bin_dir/gh"
}
run_preview() {
local upstream="$1"
local dest="$2"
local fake_bin="$3"
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --local "$dest" 2>&1
}
run_bootstrap_preview() {
local upstream="$1"
local dest="$2"
local fake_bin="$3"
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --bootstrap --local "$dest" 2>&1
}
run_preview_without_manifest() {
local upstream="$1"
local dest="$2"
local fake_bin="$3"
rm -f "$upstream/.codex-plugin/plugin.json"
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --local "$dest" 2>&1
}
run_preview_with_stale_ignored_destination() {
local upstream="$1"
local dest="$2"
local fake_bin="$3"
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -n --local "$dest" 2>&1
}
run_apply() {
local upstream="$1"
local dest="$2"
local fake_bin="$3"
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" -y --local "$dest" 2>&1
}
run_help() {
local upstream="$1"
local fake_bin="$2"
PATH="$fake_bin:$PATH" "$BASH_UNDER_TEST" "$upstream/scripts/sync-to-codex-plugin.sh" --help 2>&1
}
write_bootstrap_destination_fixture() {
local repo="$1"
printf 'bootstrap fixture\n' > "$repo/README.md"
git -C "$repo" add README.md
commit_fixture "$repo" "Initial bootstrap destination fixture"
}
main() {
local upstream
local mixed_only_upstream
local dest
local dest_branch
local mixed_only_dest
local stale_dest
local dirty_apply_dest
local dirty_apply_dest_branch
local noop_apply_dest
local noop_apply_dest_branch
local fake_bin
local bootstrap_dest
local bootstrap_dest_branch
local preview_status
local preview_output
local preview_section
local bootstrap_status
local bootstrap_output
local missing_manifest_status
local missing_manifest_output
local mixed_only_status
local mixed_only_output
local stale_preview_status
local stale_preview_output
local stale_preview_section
local dirty_apply_status
local dirty_apply_output
local noop_apply_status
local noop_apply_output
local help_output
local script_source
local dirty_skill_path
local noop_openai_metadata_path
echo "=== Test: sync-to-codex-plugin dry-run regression ==="
TEST_ROOT="$(mktemp -d)"
trap cleanup EXIT
upstream="$TEST_ROOT/upstream"
mixed_only_upstream="$TEST_ROOT/mixed-only-upstream"
dest="$TEST_ROOT/destination"
mixed_only_dest="$TEST_ROOT/mixed-only-destination"
stale_dest="$TEST_ROOT/stale-destination"
dirty_apply_dest="$TEST_ROOT/dirty-apply-destination"
dirty_apply_dest_branch="fixture/dirty-apply-target"
noop_apply_dest="$TEST_ROOT/noop-apply-destination"
noop_apply_dest_branch="fixture/noop-apply-target"
bootstrap_dest="$TEST_ROOT/bootstrap-destination"
dest_branch="fixture/preview-target"
bootstrap_dest_branch="fixture/bootstrap-preview-target"
fake_bin="$TEST_ROOT/bin"
init_repo "$upstream"
write_upstream_fixture "$upstream"
init_repo "$mixed_only_upstream"
write_upstream_fixture "$mixed_only_upstream" 0
init_repo "$dest"
write_destination_fixture "$dest"
add_openai_agent_metadata_fixture "$dest"
checkout_fixture_branch "$dest" "$dest_branch"
dirty_tracked_destination_skill "$dest"
init_repo "$mixed_only_dest"
write_destination_fixture "$mixed_only_dest"
init_repo "$stale_dest"
write_stale_ignored_destination_fixture "$stale_dest"
init_repo "$dirty_apply_dest"
write_synced_destination_fixture "$dirty_apply_dest"
checkout_fixture_branch "$dirty_apply_dest" "$dirty_apply_dest_branch"
dirty_tracked_destination_skill "$dirty_apply_dest"
init_repo "$noop_apply_dest"
write_synced_destination_fixture "$noop_apply_dest"
checkout_fixture_branch "$noop_apply_dest" "$noop_apply_dest_branch"
init_repo "$bootstrap_dest"
write_bootstrap_destination_fixture "$bootstrap_dest"
checkout_fixture_branch "$bootstrap_dest" "$bootstrap_dest_branch"
write_fake_gh "$fake_bin"
# This regression test is about dry-run content, so capture the preview
# output even if the current script exits nonzero in --local mode.
set +e
preview_output="$(run_preview "$upstream" "$dest" "$fake_bin")"
preview_status=$?
bootstrap_output="$(run_bootstrap_preview "$upstream" "$bootstrap_dest" "$fake_bin")"
bootstrap_status=$?
mixed_only_output="$(run_preview "$mixed_only_upstream" "$mixed_only_dest" "$fake_bin")"
mixed_only_status=$?
stale_preview_output="$(run_preview_with_stale_ignored_destination "$upstream" "$stale_dest" "$fake_bin")"
stale_preview_status=$?
dirty_apply_output="$(run_apply "$upstream" "$dirty_apply_dest" "$fake_bin")"
dirty_apply_status=$?
noop_apply_output="$(run_apply "$upstream" "$noop_apply_dest" "$fake_bin")"
noop_apply_status=$?
missing_manifest_output="$(run_preview_without_manifest "$upstream" "$dest" "$fake_bin")"
missing_manifest_status=$?
set -e
help_output="$(run_help "$upstream" "$fake_bin")"
script_source="$(cat "$upstream/scripts/sync-to-codex-plugin.sh")"
preview_section="$(printf '%s\n' "$preview_output" | sed -n '/^=== Preview (rsync --dry-run) ===$/,/^=== End preview ===$/p')"
stale_preview_section="$(printf '%s\n' "$stale_preview_output" | sed -n '/^=== Preview (rsync --dry-run) ===$/,/^=== End preview ===$/p')"
dirty_skill_path="$dirty_apply_dest/plugins/superpowers/skills/example/SKILL.md"
noop_openai_metadata_path="$noop_apply_dest/plugins/superpowers/skills/example/agents/openai.yaml"
echo ""
echo "Preview assertions..."
assert_equals "$preview_status" "0" "Preview exits successfully"
assert_contains "$preview_output" "Version: $MANIFEST_VERSION" "Preview uses manifest version"
assert_not_contains "$preview_output" "Version: $PACKAGE_VERSION" "Preview does not use package.json version"
assert_contains "$preview_section" ".codex-plugin/plugin.json" "Preview includes manifest path"
assert_contains "$preview_section" "assets/superpowers-small.svg" "Preview includes SVG asset"
assert_contains "$preview_section" "assets/app-icon.png" "Preview includes PNG asset"
assert_contains "$preview_section" ".private-journal/keep.txt" "Preview includes tracked ignored file"
assert_not_contains "$preview_section" ".private-journal/leak.txt" "Preview excludes ignored untracked file"
assert_not_contains "$preview_section" "ignored-cache/" "Preview excludes pure ignored directories"
assert_not_contains "$preview_section" "evals/" "Preview excludes eval harness"
assert_not_contains "$preview_output" "Overlay file (.codex-plugin/plugin.json) will be regenerated" "Preview omits overlay regeneration note"
assert_not_contains "$preview_output" "Assets (superpowers-small.svg, app-icon.png) will be seeded from" "Preview omits assets seeding note"
assert_contains "$preview_section" "skills/example/SKILL.md" "Preview reflects dirty tracked destination file"
assert_not_matches "$preview_section" "\\*deleting +skills/example/agents/openai\\.yaml" "Preview preserves destination-owned OpenAI agent metadata"
assert_current_branch "$dest" "$dest_branch" "Preview leaves destination checkout on its original branch"
assert_branch_absent "$dest" "sync/superpowers-*" "Preview does not create sync branch in destination checkout"
echo ""
echo "Mixed-directory assertions..."
assert_equals "$mixed_only_status" "0" "Mixed ignored directory preview exits successfully under /bin/bash"
assert_contains "$mixed_only_output" ".private-journal/keep.txt" "Mixed ignored directory preview still includes tracked ignored file"
assert_not_contains "$mixed_only_output" "ignored-cache/" "Mixed ignored directory preview has no pure ignored directory fixture"
echo ""
echo "Convergence assertions..."
assert_equals "$stale_preview_status" "0" "Stale ignored destination preview exits successfully"
assert_matches "$stale_preview_section" "\\*deleting +\\.private-journal/leak\\.txt" "Preview deletes stale ignored destination file"
echo ""
echo "Bootstrap assertions..."
assert_equals "$bootstrap_status" "0" "Bootstrap preview exits successfully"
assert_contains "$bootstrap_output" "Mode: BOOTSTRAP (creating plugins/superpowers/ when absent)" "Bootstrap preview describes directory creation"
assert_not_contains "$bootstrap_output" "Assets:" "Bootstrap preview omits external assets path"
assert_contains "$bootstrap_output" "Dry run only. Nothing was changed or pushed." "Bootstrap preview remains dry-run only"
assert_path_absent "$bootstrap_dest/plugins/superpowers" "Bootstrap preview does not create destination plugin directory"
assert_current_branch "$bootstrap_dest" "$bootstrap_dest_branch" "Bootstrap preview leaves destination checkout on its original branch"
assert_branch_absent "$bootstrap_dest" "bootstrap/superpowers-*" "Bootstrap preview does not create bootstrap branch in destination checkout"
echo ""
echo "Apply assertions..."
assert_equals "$dirty_apply_status" "1" "Dirty local apply exits with failure"
assert_contains "$dirty_apply_output" "ERROR: local checkout has uncommitted changes under 'plugins/superpowers'" "Dirty local apply reports protected destination path"
assert_current_branch "$dirty_apply_dest" "$dirty_apply_dest_branch" "Dirty local apply leaves destination checkout on its original branch"
assert_branch_absent "$dirty_apply_dest" "sync/superpowers-*" "Dirty local apply does not create sync branch in destination checkout"
assert_file_equals "$dirty_skill_path" "# Example Skill
Locally modified fixture content." "Dirty local apply preserves tracked working-tree file content"
assert_equals "$noop_apply_status" "0" "Clean no-op local apply exits successfully"
assert_contains "$noop_apply_output" "No changes — embedded plugin was already in sync with upstream" "Clean no-op local apply reports no changes"
assert_current_branch "$noop_apply_dest" "$noop_apply_dest_branch" "Clean no-op local apply leaves destination checkout on its original branch"
assert_branch_absent "$noop_apply_dest" "sync/superpowers-*" "Clean no-op local apply does not create sync branch in destination checkout"
assert_file_equals "$noop_openai_metadata_path" "interface:
display_name: \"Example\"
short_description: \"Destination-owned OpenAI metadata\"" "Clean no-op local apply preserves OpenAI agent metadata"
echo ""
echo "Missing manifest assertions..."
assert_equals "$missing_manifest_status" "1" "Missing manifest exits with failure"
assert_contains "$missing_manifest_output" "ERROR: committed Codex manifest missing at" "Missing manifest reports committed manifest path"
echo ""
echo "Help assertions..."
assert_not_contains "$help_output" "--assets-src" "Help omits --assets-src"
echo ""
echo "Source assertions..."
assert_not_contains "$script_source" "regenerated inline" "Source drops regenerated inline phrasing"
assert_not_contains "$script_source" "Brand Assets directory" "Source drops Brand Assets directory phrasing"
assert_not_contains "$script_source" "--assets-src" "Source drops --assets-src"
if [[ $FAILURES -ne 0 ]]; then
echo ""
echo "FAILED: $FAILURES assertion(s) failed."
exit 1
fi
echo ""
echo "PASS"
}
main "$@"

View File

@@ -1,100 +0,0 @@
#!/usr/bin/env bash
# Test where Claude explicitly describes subagent-driven-development before user requests it
# This mimics the original failure scenario
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PLUGIN_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
TIMESTAMP=$(date +%s)
OUTPUT_DIR="/tmp/superpowers-tests/${TIMESTAMP}/explicit-skill-requests/claude-describes"
mkdir -p "$OUTPUT_DIR"
PROJECT_DIR="$OUTPUT_DIR/project"
mkdir -p "$PROJECT_DIR/docs/superpowers/plans"
echo "=== Test: Claude Describes SDD First ==="
echo "Output dir: $OUTPUT_DIR"
echo ""
cd "$PROJECT_DIR"
# Create a plan
cat > "$PROJECT_DIR/docs/superpowers/plans/auth-system.md" << 'EOF'
# Auth System Implementation Plan
## Task 1: Add User Model
Create user model with email and password fields.
## Task 2: Add Auth Routes
Create login and register endpoints.
## Task 3: Add JWT Middleware
Protect routes with JWT validation.
EOF
# Turn 1: Have Claude describe execution options including SDD
echo ">>> Turn 1: Ask Claude to describe execution options..."
claude -p "I have a plan at docs/superpowers/plans/auth-system.md. Tell me about my options for executing it, including what subagent-driven-development means and how it works." \
--model haiku \
--plugin-dir "$PLUGIN_DIR" \
--dangerously-skip-permissions \
--max-turns 3 \
--output-format stream-json \
> "$OUTPUT_DIR/turn1.json" 2>&1 || true
echo "Done."
# Turn 2: THE CRITICAL TEST - now that Claude has explained it
echo ">>> Turn 2: Request subagent-driven-development..."
FINAL_LOG="$OUTPUT_DIR/turn2.json"
claude -p "subagent-driven-development, please" \
--continue \
--model haiku \
--plugin-dir "$PLUGIN_DIR" \
--dangerously-skip-permissions \
--max-turns 2 \
--output-format stream-json \
> "$FINAL_LOG" 2>&1 || true
echo "Done."
echo ""
echo "=== Results ==="
# Check Turn 1 to see if Claude described SDD
echo "Turn 1 - Claude's description of options (excerpt):"
grep '"type":"assistant"' "$OUTPUT_DIR/turn1.json" | head -1 | jq -r '.message.content[0].text // .message.content' 2>/dev/null | head -c 800 || echo " (could not extract)"
echo ""
echo "---"
echo ""
# Check final turn
SKILL_PATTERN='"skill":"([^"]*:)?subagent-driven-development"'
if grep -q '"name":"Skill"' "$FINAL_LOG" && grep -qE "$SKILL_PATTERN" "$FINAL_LOG"; then
echo "PASS: Skill was triggered after Claude described it"
TRIGGERED=true
else
echo "FAIL: Skill was NOT triggered (Claude may have thought it already knew)"
TRIGGERED=false
echo ""
echo "Tools invoked in final turn:"
grep '"type":"tool_use"' "$FINAL_LOG" | grep -o '"name":"[^"]*"' | sort -u | head -10 || echo " (none)"
echo ""
echo "Final turn response:"
grep '"type":"assistant"' "$FINAL_LOG" | head -1 | jq -r '.message.content[0].text // .message.content' 2>/dev/null | head -c 800 || echo " (could not extract)"
fi
echo ""
echo "Skills triggered in final turn:"
grep -o '"skill":"[^"]*"' "$FINAL_LOG" 2>/dev/null | sort -u || echo " (none)"
echo ""
echo "Logs in: $OUTPUT_DIR"
if [ "$TRIGGERED" = "true" ]; then
exit 0
else
exit 1
fi

View File

@@ -109,7 +109,7 @@ if [ -n "$FIRST_SKILL_LINE" ]; then
PREMATURE_TOOLS=$(head -n "$FIRST_SKILL_LINE" "$TURN3_LOG" | \ PREMATURE_TOOLS=$(head -n "$FIRST_SKILL_LINE" "$TURN3_LOG" | \
grep '"type":"tool_use"' | \ grep '"type":"tool_use"' | \
grep -v '"name":"Skill"' | \ grep -v '"name":"Skill"' | \
grep -v '"name":"TodoWrite"' || true) grep -vE '"name":"(TodoWrite|TaskCreate|TaskUpdate|TaskList|TaskGet)"' || true)
if [ -n "$PREMATURE_TOOLS" ]; then if [ -n "$PREMATURE_TOOLS" ]; then
echo "WARNING: Tools invoked BEFORE Skill tool in Turn 3:" echo "WARNING: Tools invoked BEFORE Skill tool in Turn 3:"
echo "$PREMATURE_TOOLS" | head -5 echo "$PREMATURE_TOOLS" | head -5

View File

@@ -103,11 +103,11 @@ echo "Checking for premature action..."
FIRST_SKILL_LINE=$(grep -n '"name":"Skill"' "$LOG_FILE" | head -1 | cut -d: -f1) FIRST_SKILL_LINE=$(grep -n '"name":"Skill"' "$LOG_FILE" | head -1 | cut -d: -f1)
if [ -n "$FIRST_SKILL_LINE" ]; then if [ -n "$FIRST_SKILL_LINE" ]; then
# Check if any non-Skill, non-system tools were invoked before the first Skill invocation # Check if any non-Skill, non-system tools were invoked before the first Skill invocation
# Filter out system messages, TodoWrite (planning is ok), and other non-action tools # Filter out task tracking tools (planning is ok) and other non-action tools
PREMATURE_TOOLS=$(head -n "$FIRST_SKILL_LINE" "$LOG_FILE" | \ PREMATURE_TOOLS=$(head -n "$FIRST_SKILL_LINE" "$LOG_FILE" | \
grep '"type":"tool_use"' | \ grep '"type":"tool_use"' | \
grep -v '"name":"Skill"' | \ grep -v '"name":"Skill"' | \
grep -v '"name":"TodoWrite"' || true) grep -vE '"name":"(TodoWrite|TaskCreate|TaskUpdate|TaskList|TaskGet)"' || true)
if [ -n "$PREMATURE_TOOLS" ]; then if [ -n "$PREMATURE_TOOLS" ]; then
echo "WARNING: Tools invoked BEFORE Skill tool:" echo "WARNING: Tools invoked BEFORE Skill tool:"
echo "$PREMATURE_TOOLS" | head -5 echo "$PREMATURE_TOOLS" | head -5

View File

@@ -44,6 +44,7 @@ while [[ $# -gt 0 ]]; do
echo "" echo ""
echo "Tests:" echo "Tests:"
echo " test-plugin-loading.sh Verify plugin installation and structure" echo " test-plugin-loading.sh Verify plugin installation and structure"
echo " test-bootstrap-caching.sh Verify bootstrap content caching"
echo " test-tools.sh Test use_skill and find_skills tools (integration)" echo " test-tools.sh Test use_skill and find_skills tools (integration)"
echo " test-priority.sh Test skill priority resolution (integration)" echo " test-priority.sh Test skill priority resolution (integration)"
exit 0 exit 0
@@ -59,6 +60,7 @@ done
# List of tests to run (no external dependencies) # List of tests to run (no external dependencies)
tests=( tests=(
"test-plugin-loading.sh" "test-plugin-loading.sh"
"test-bootstrap-caching.sh"
) )
# Integration tests (require OpenCode) # Integration tests (require OpenCode)

View File

@@ -7,30 +7,39 @@ set -euo pipefail
REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)" REPO_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
# Create temp home directory for isolation # Create temp home directory for isolation
export TEST_HOME=$(mktemp -d) export TEST_HOME
TEST_HOME=$(mktemp -d)
export HOME="$TEST_HOME" export HOME="$TEST_HOME"
export XDG_CONFIG_HOME="$TEST_HOME/.config" export XDG_CONFIG_HOME="$TEST_HOME/.config"
export OPENCODE_CONFIG_DIR="$TEST_HOME/.config/opencode" export OPENCODE_CONFIG_DIR="$TEST_HOME/.config/opencode"
# Install plugin to test location # Standard install layout:
mkdir -p "$HOME/.config/opencode/superpowers" # $OPENCODE_CONFIG_DIR/superpowers/ ← package root
cp -r "$REPO_ROOT/lib" "$HOME/.config/opencode/superpowers/" # $OPENCODE_CONFIG_DIR/superpowers/skills/ ← skills dir (../../skills from plugin)
cp -r "$REPO_ROOT/skills" "$HOME/.config/opencode/superpowers/" # $OPENCODE_CONFIG_DIR/superpowers/.opencode/plugins/superpowers.js ← plugin file
# $OPENCODE_CONFIG_DIR/plugins/superpowers.js ← symlink OpenCode reads
# Copy plugin directory SUPERPOWERS_DIR="$OPENCODE_CONFIG_DIR/superpowers"
mkdir -p "$HOME/.config/opencode/superpowers/.opencode/plugins" SUPERPOWERS_SKILLS_DIR="$SUPERPOWERS_DIR/skills"
cp "$REPO_ROOT/.opencode/plugins/superpowers.js" "$HOME/.config/opencode/superpowers/.opencode/plugins/" SUPERPOWERS_PLUGIN_FILE="$SUPERPOWERS_DIR/.opencode/plugins/superpowers.js"
# Register plugin via symlink # Install skills
mkdir -p "$HOME/.config/opencode/plugins" mkdir -p "$SUPERPOWERS_DIR"
ln -sf "$HOME/.config/opencode/superpowers/.opencode/plugins/superpowers.js" \ cp -r "$REPO_ROOT/skills" "$SUPERPOWERS_DIR/"
"$HOME/.config/opencode/plugins/superpowers.js"
# Install plugin
mkdir -p "$(dirname "$SUPERPOWERS_PLUGIN_FILE")"
cp "$REPO_ROOT/.opencode/plugins/superpowers.js" "$SUPERPOWERS_PLUGIN_FILE"
# Register plugin via symlink (what OpenCode actually reads)
mkdir -p "$OPENCODE_CONFIG_DIR/plugins"
ln -sf "$SUPERPOWERS_PLUGIN_FILE" "$OPENCODE_CONFIG_DIR/plugins/superpowers.js"
# Create test skills in different locations for testing # Create test skills in different locations for testing
# Personal test skill # Personal test skill
mkdir -p "$HOME/.config/opencode/skills/personal-test" mkdir -p "$OPENCODE_CONFIG_DIR/skills/personal-test"
cat > "$HOME/.config/opencode/skills/personal-test/SKILL.md" <<'EOF' cat > "$OPENCODE_CONFIG_DIR/skills/personal-test/SKILL.md" <<'EOF'
--- ---
name: personal-test name: personal-test
description: Test personal skill for verification description: Test personal skill for verification
@@ -57,9 +66,12 @@ PROJECT_SKILL_MARKER_67890
EOF EOF
echo "Setup complete: $TEST_HOME" echo "Setup complete: $TEST_HOME"
echo "Plugin installed to: $HOME/.config/opencode/superpowers/.opencode/plugins/superpowers.js" echo "OPENCODE_CONFIG_DIR: $OPENCODE_CONFIG_DIR"
echo "Plugin registered at: $HOME/.config/opencode/plugins/superpowers.js" echo "Superpowers dir: $SUPERPOWERS_DIR"
echo "Test project at: $TEST_HOME/test-project" echo "Skills dir: $SUPERPOWERS_SKILLS_DIR"
echo "Plugin file: $SUPERPOWERS_PLUGIN_FILE"
echo "Plugin registered at: $OPENCODE_CONFIG_DIR/plugins/superpowers.js"
echo "Test project at: $TEST_HOME/test-project"
# Helper function for cleanup (call from tests or trap) # Helper function for cleanup (call from tests or trap)
cleanup_test_env() { cleanup_test_env() {
@@ -71,3 +83,6 @@ cleanup_test_env() {
# Export for use in tests # Export for use in tests
export -f cleanup_test_env export -f cleanup_test_env
export REPO_ROOT export REPO_ROOT
export SUPERPOWERS_DIR
export SUPERPOWERS_SKILLS_DIR
export SUPERPOWERS_PLUGIN_FILE

View File

@@ -0,0 +1,146 @@
import fs from 'fs';
import { pathToFileURL } from 'url';
const [, , pluginPath, scenario] = process.argv;
if (!pluginPath || !['present', 'missing'].includes(scenario)) {
console.error('Usage: node test-bootstrap-caching.mjs PLUGIN_PATH present|missing');
process.exit(2);
}
let existsCount = 0;
let readCount = 0;
const originalExistsSync = fs.existsSync;
const originalReadFileSync = fs.readFileSync;
fs.existsSync = function (...args) {
if (isBootstrapSkillPath(args[0])) {
existsCount += 1;
}
return originalExistsSync.apply(this, args);
};
fs.readFileSync = function (...args) {
if (isBootstrapSkillPath(args[0])) {
readCount += 1;
}
return originalReadFileSync.apply(this, args);
};
const mod = await import(pathToFileURL(pluginPath).href);
const plugin = await mod.SuperpowersPlugin({ client: {}, directory: '.' });
const transform = plugin['experimental.chat.messages.transform'];
const firstOutput = makeOutput(`${scenario} bootstrap first step`);
await transform({}, firstOutput);
const afterFirst = { existsCount, readCount };
const secondOutput = makeOutput(`${scenario} bootstrap second step`);
await transform({}, secondOutput);
const afterSecond = { existsCount, readCount };
const result = {
scenario,
firstBootstrapParts: countBootstrapParts(firstOutput),
secondBootstrapParts: countBootstrapParts(secondOutput),
staleMentionMapping: bootstrapText(firstOutput).includes('@mention'),
staleTaskMapping: bootstrapText(firstOutput).includes('`Task` tool with subagents'),
mapsSubagentToTask: bootstrapText(firstOutput).includes('`task` with `subagent_type: "general"`'),
mapsMutationToApplyPatch: bootstrapText(firstOutput).includes('`apply_patch`'),
firstReadCount: afterFirst.readCount,
secondReadCount: afterSecond.readCount,
firstExistsCount: afterFirst.existsCount,
secondExistsCount: afterSecond.existsCount,
};
const failures = scenario === 'present'
? assertPresentBootstrap(result)
: assertMissingBootstrap(result);
if (failures.length > 0) {
console.error(JSON.stringify(result, null, 2));
for (const failure of failures) {
console.error(`FAIL: ${failure}`);
}
process.exit(1);
}
console.log(JSON.stringify(result, null, 2));
function isBootstrapSkillPath(filePath) {
return String(filePath).replaceAll('\\', '/').includes('using-superpowers/SKILL.md');
}
function makeOutput(text) {
return {
messages: [{
info: { role: 'user' },
parts: [{ type: 'text', text }],
}],
};
}
function countBootstrapParts(output) {
return output.messages[0].parts.filter(
(part) => part.type === 'text' && part.text.includes('EXTREMELY_IMPORTANT')
).length;
}
function bootstrapText(output) {
return output.messages[0].parts.find(
(part) => part.type === 'text' && part.text.includes('EXTREMELY_IMPORTANT')
)?.text || '';
}
function assertPresentBootstrap(result) {
const failures = [];
if (result.firstBootstrapParts !== 1) {
failures.push(`expected first transform to inject one bootstrap part, got ${result.firstBootstrapParts}`);
}
if (result.secondBootstrapParts !== 1) {
failures.push(`expected second transform to inject one bootstrap part, got ${result.secondBootstrapParts}`);
}
if (result.firstReadCount !== 1) {
failures.push(`expected first transform to read SKILL.md once, got ${result.firstReadCount}`);
}
if (result.secondReadCount !== result.firstReadCount) {
failures.push(`expected cached second transform to do no additional reads, got ${result.secondReadCount - result.firstReadCount}`);
}
if (result.secondExistsCount !== result.firstExistsCount) {
failures.push(`expected cached second transform to do no additional exists checks, got ${result.secondExistsCount - result.firstExistsCount}`);
}
if (result.staleMentionMapping) {
failures.push('expected OpenCode bootstrap not to teach @mention subagent syntax');
}
if (result.staleTaskMapping) {
failures.push('expected OpenCode bootstrap not to teach stale Task-tool mapping');
}
if (!result.mapsSubagentToTask) {
failures.push('expected OpenCode bootstrap to map general-purpose subagents to task with subagent_type');
}
if (!result.mapsMutationToApplyPatch) {
failures.push('expected OpenCode bootstrap to map file mutation to apply_patch');
}
return failures;
}
function assertMissingBootstrap(result) {
const failures = [];
if (result.firstBootstrapParts !== 0) {
failures.push(`expected no bootstrap when SKILL.md is missing, got ${result.firstBootstrapParts}`);
}
if (result.secondBootstrapParts !== 0) {
failures.push(`expected no bootstrap on second missing-file transform, got ${result.secondBootstrapParts}`);
}
if (result.firstReadCount !== 0 || result.secondReadCount !== 0) {
failures.push(`expected missing file path to avoid reads, got ${result.secondReadCount}`);
}
if (result.firstExistsCount < 1) {
failures.push('expected first transform to check whether SKILL.md exists');
}
if (result.secondExistsCount !== result.firstExistsCount) {
failures.push(`expected missing-file result to be cached, got ${result.secondExistsCount - result.firstExistsCount} extra exists checks`);
}
return failures;
}

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env bash
# Test: Bootstrap Content Caching (#1202)
# Verifies the OpenCode transform caches bootstrap content between agent steps.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
echo "=== Test: Bootstrap Content Caching (#1202) ==="
source "$SCRIPT_DIR/setup.sh"
trap cleanup_test_env EXIT
run_present_file_check() {
node "$SCRIPT_DIR/test-bootstrap-caching.mjs" "$SUPERPOWERS_PLUGIN_FILE" present
}
run_missing_file_check() {
mv "$SUPERPOWERS_SKILLS_DIR/using-superpowers/SKILL.md" "$TEST_HOME/using-superpowers.SKILL.md.bak"
node "$SCRIPT_DIR/test-bootstrap-caching.mjs" "$SUPERPOWERS_PLUGIN_FILE" missing
}
echo "Test 1: Caches bootstrap after the first successful transform..."
run_present_file_check
echo " [PASS] Bootstrap content is cached while fresh message arrays still receive injection"
echo "Test 2: Caches missing SKILL.md result..."
run_missing_file_check
echo " [PASS] Missing bootstrap file is cached and not re-probed every transform"
echo ""
echo "=== All bootstrap caching tests passed ==="

View File

@@ -13,17 +13,19 @@ source "$SCRIPT_DIR/setup.sh"
# Trap to cleanup on exit # Trap to cleanup on exit
trap cleanup_test_env EXIT trap cleanup_test_env EXIT
plugin_link="$OPENCODE_CONFIG_DIR/plugins/superpowers.js"
# Test 1: Verify plugin file exists and is registered # Test 1: Verify plugin file exists and is registered
echo "Test 1: Checking plugin registration..." echo "Test 1: Checking plugin registration..."
if [ -L "$HOME/.config/opencode/plugins/superpowers.js" ]; then if [ -L "$plugin_link" ]; then
echo " [PASS] Plugin symlink exists" echo " [PASS] Plugin symlink exists"
else else
echo " [FAIL] Plugin symlink not found at $HOME/.config/opencode/plugins/superpowers.js" echo " [FAIL] Plugin symlink not found at $plugin_link"
exit 1 exit 1
fi fi
# Verify symlink target exists # Verify symlink target exists
if [ -f "$(readlink -f "$HOME/.config/opencode/plugins/superpowers.js")" ]; then if [ -f "$(readlink -f "$plugin_link")" ]; then
echo " [PASS] Plugin symlink target exists" echo " [PASS] Plugin symlink target exists"
else else
echo " [FAIL] Plugin symlink target does not exist" echo " [FAIL] Plugin symlink target does not exist"
@@ -32,36 +34,44 @@ fi
# Test 2: Verify skills directory is populated # Test 2: Verify skills directory is populated
echo "Test 2: Checking skills directory..." echo "Test 2: Checking skills directory..."
skill_count=$(find "$HOME/.config/opencode/superpowers/skills" -name "SKILL.md" | wc -l) skill_count=$(find "$SUPERPOWERS_SKILLS_DIR" -name "SKILL.md" | wc -l)
if [ "$skill_count" -gt 0 ]; then if [ "$skill_count" -gt 0 ]; then
echo " [PASS] Found $skill_count skills installed" echo " [PASS] Found $skill_count skills"
else else
echo " [FAIL] No skills found in installed location" echo " [FAIL] No skills found in $SUPERPOWERS_SKILLS_DIR"
exit 1 exit 1
fi fi
# Test 4: Check using-superpowers skill exists (critical for bootstrap) # Test 3: Check using-superpowers skill exists (critical for bootstrap)
echo "Test 4: Checking using-superpowers skill (required for bootstrap)..." echo "Test 3: Checking using-superpowers skill (required for bootstrap)..."
if [ -f "$HOME/.config/opencode/superpowers/skills/using-superpowers/SKILL.md" ]; then if [ -f "$SUPERPOWERS_SKILLS_DIR/using-superpowers/SKILL.md" ]; then
echo " [PASS] using-superpowers skill exists" echo " [PASS] using-superpowers skill exists"
else else
echo " [FAIL] using-superpowers skill not found (required for bootstrap)" echo " [FAIL] using-superpowers skill not found (required for bootstrap)"
exit 1 exit 1
fi fi
# Test 5: Verify plugin JavaScript syntax (basic check) # Test 4: Verify plugin JavaScript syntax (basic check)
echo "Test 5: Checking plugin JavaScript syntax..." echo "Test 4: Checking plugin JavaScript syntax..."
plugin_file="$HOME/.config/opencode/superpowers/.opencode/plugins/superpowers.js" if node --check "$SUPERPOWERS_PLUGIN_FILE" 2>/dev/null; then
if node --check "$plugin_file" 2>/dev/null; then
echo " [PASS] Plugin JavaScript syntax is valid" echo " [PASS] Plugin JavaScript syntax is valid"
else else
echo " [FAIL] Plugin has JavaScript syntax errors" echo " [FAIL] Plugin has JavaScript syntax errors"
exit 1 exit 1
fi fi
# Test 5: Verify bootstrap text does not reference a hardcoded skills path
echo "Test 5: Checking bootstrap does not advertise a wrong skills path..."
if grep -q 'configDir}/skills/superpowers/' "$SUPERPOWERS_PLUGIN_FILE"; then
echo " [FAIL] Plugin still references old configDir skills path"
exit 1
else
echo " [PASS] Plugin does not advertise a misleading skills path"
fi
# Test 6: Verify personal test skill was created # Test 6: Verify personal test skill was created
echo "Test 6: Checking test fixtures..." echo "Test 6: Checking test fixtures..."
if [ -f "$HOME/.config/opencode/skills/personal-test/SKILL.md" ]; then if [ -f "$OPENCODE_CONFIG_DIR/skills/personal-test/SKILL.md" ]; then
echo " [PASS] Personal test skill fixture created" echo " [PASS] Personal test skill fixture created"
else else
echo " [FAIL] Personal test skill fixture not found" echo " [FAIL] Personal test skill fixture not found"

View File

@@ -1,10 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Test: Skill Priority Resolution # Test: Skill Priority Resolution
# Verifies that skills are resolved with correct priority: project > personal > superpowers # Documents current OpenCode duplicate-name behavior for local and bundled
# skills. The desired local-shadowing behavior is tracked separately; this
# test keeps the integration suite honest without adding a plugin workaround.
# NOTE: These tests require OpenCode to be installed and configured # NOTE: These tests require OpenCode to be installed and configured
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}"
echo "=== Test: Skill Priority Resolution ===" echo "=== Test: Skill Priority Resolution ==="
@@ -18,8 +21,8 @@ trap cleanup_test_env EXIT
echo "Setting up priority test fixtures..." echo "Setting up priority test fixtures..."
# 1. Create in superpowers location (lowest priority) # 1. Create in superpowers location (lowest priority)
mkdir -p "$HOME/.config/opencode/superpowers/skills/priority-test" mkdir -p "$SUPERPOWERS_SKILLS_DIR/priority-test"
cat > "$HOME/.config/opencode/superpowers/skills/priority-test/SKILL.md" <<'EOF' cat > "$SUPERPOWERS_SKILLS_DIR/priority-test/SKILL.md" <<'EOF'
--- ---
name: priority-test name: priority-test
description: Superpowers version of priority test skill description: Superpowers version of priority test skill
@@ -32,8 +35,8 @@ PRIORITY_MARKER_SUPERPOWERS_VERSION
EOF EOF
# 2. Create in personal location (medium priority) # 2. Create in personal location (medium priority)
mkdir -p "$HOME/.config/opencode/skills/priority-test" mkdir -p "$OPENCODE_CONFIG_DIR/skills/priority-test"
cat > "$HOME/.config/opencode/skills/priority-test/SKILL.md" <<'EOF' cat > "$OPENCODE_CONFIG_DIR/skills/priority-test/SKILL.md" <<'EOF'
--- ---
name: priority-test name: priority-test
description: Personal version of priority test skill description: Personal version of priority test skill
@@ -65,14 +68,14 @@ echo " Created priority-test skill in all three locations"
echo "" echo ""
echo "Test 1: Verifying test fixtures..." echo "Test 1: Verifying test fixtures..."
if [ -f "$HOME/.config/opencode/superpowers/skills/priority-test/SKILL.md" ]; then if [ -f "$SUPERPOWERS_SKILLS_DIR/priority-test/SKILL.md" ]; then
echo " [PASS] Superpowers version exists" echo " [PASS] Superpowers version exists"
else else
echo " [FAIL] Superpowers version missing" echo " [FAIL] Superpowers version missing"
exit 1 exit 1
fi fi
if [ -f "$HOME/.config/opencode/skills/priority-test/SKILL.md" ]; then if [ -f "$OPENCODE_CONFIG_DIR/skills/priority-test/SKILL.md" ]; then
echo " [PASS] Personal version exists" echo " [PASS] Personal version exists"
else else
echo " [FAIL] Personal version missing" echo " [FAIL] Personal version missing"
@@ -96,103 +99,119 @@ if ! command -v opencode &> /dev/null; then
exit 0 exit 0
fi fi
# Test 2: Test that personal overrides superpowers run_opencode() {
local result_var="$1"
local dir="$2"
local prompt="$3"
local command_output
local exit_code
set +e
command_output=$(cd "$dir" && timeout "${OPENCODE_TEST_TIMEOUT_SECONDS}s" opencode run --print-logs --format json "$prompt" 2>&1)
exit_code=$?
set -e
if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s"
exit 1
fi
if [ $exit_code -ne 0 ]; then
echo " [FAIL] OpenCode returned non-zero exit code: $exit_code"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$command_output"
exit 1
fi
printf -v "$result_var" '%s' "$command_output"
}
assert_contains() {
local output="$1"
local needle="$2"
local message="$3"
if [[ "$output" == *"$needle"* ]]; then
echo " [PASS] $message"
else
echo " [FAIL] $message"
echo " Expected to find: $needle"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$output"
exit 1
fi
}
first_skill_tool_event() {
awk '/"type":"tool_use"/ && /"tool":"skill"/ { print; exit }' <<<"$1"
}
describe_priority_result() {
local output="$1"
local expected_marker="$2"
local fallback_marker="$3"
local pass_message="$4"
local known_bug_message="$5"
local loaded_skill
loaded_skill="$(first_skill_tool_event "$output")"
if [[ "$loaded_skill" == *"$expected_marker"* ]]; then
echo " [PASS] $pass_message"
elif [[ "$loaded_skill" == *"$fallback_marker"* ]]; then
echo " [INFO] $known_bug_message"
echo " [INFO] Tracked separately: OpenCode bundled skills can shadow local skills with duplicate native names"
else
echo " [FAIL] Could not verify priority marker in native skill tool output"
echo " Output was:"
awk 'NR <= 80 { print }' <<<"$output"
exit 1
fi
}
# Test 2: Document personal vs bundled superpowers priority
echo "" echo ""
echo "Test 2: Testing personal > superpowers priority..." echo "Test 2: Documenting personal vs superpowers priority..."
echo " Running from outside project directory..." echo " Running from outside project directory..."
# Run from HOME (not in project) - should get personal version run_opencode output "$HOME" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text."
cd "$HOME" describe_priority_result \
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the priority-test skill. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || { "$output" \
exit_code=$? "PRIORITY_MARKER_PERSONAL_VERSION" \
if [ $exit_code -eq 124 ]; then "PRIORITY_MARKER_SUPERPOWERS_VERSION" \
echo " [FAIL] OpenCode timed out after 60s" "Personal version loaded for duplicate native skill name" \
exit 1 "Current OpenCode behavior loaded bundled superpowers version instead of personal version"
fi
}
if echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then # Test 3: Document project vs bundled superpowers priority
echo " [PASS] Personal version loaded (overrides superpowers)"
elif echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
echo " [FAIL] Superpowers version loaded instead of personal"
exit 1
else
echo " [WARN] Could not verify priority marker in output"
echo " Output snippet:"
echo "$output" | grep -i "priority\|personal\|superpowers" | head -10
fi
# Test 3: Test that project overrides both personal and superpowers
echo "" echo ""
echo "Test 3: Testing project > personal > superpowers priority..." echo "Test 3: Documenting project vs personal/superpowers priority..."
echo " Running from project directory..." echo " Running from project directory..."
# Run from project directory - should get project version run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text."
cd "$TEST_HOME/test-project" describe_priority_result \
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the priority-test skill. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || { "$output" \
exit_code=$? "PRIORITY_MARKER_PROJECT_VERSION" \
if [ $exit_code -eq 124 ]; then "PRIORITY_MARKER_SUPERPOWERS_VERSION" \
echo " [FAIL] OpenCode timed out after 60s" "Project version loaded for duplicate native skill name" \
exit 1 "Current OpenCode behavior loaded bundled superpowers version instead of project version"
fi
}
if echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION"; then # Test 4: Test a non-colliding bundled superpowers skill is still available
echo " [PASS] Project version loaded (highest priority)"
elif echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then
echo " [FAIL] Personal version loaded instead of project"
exit 1
elif echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then
echo " [FAIL] Superpowers version loaded instead of project"
exit 1
else
echo " [WARN] Could not verify priority marker in output"
echo " Output snippet:"
echo "$output" | grep -i "priority\|project\|personal" | head -10
fi
# Test 4: Test explicit superpowers: prefix bypasses priority
echo "" echo ""
echo "Test 4: Testing superpowers: prefix forces superpowers version..." echo "Test 4: Testing non-colliding superpowers skill remains available..."
cd "$TEST_HOME/test-project" mkdir -p "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test"
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load superpowers:priority-test specifically. Show me the exact content including any PRIORITY_MARKER text." 2>&1) || { cat > "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test/SKILL.md" <<'EOF'
exit_code=$? ---
if [ $exit_code -eq 124 ]; then name: superpowers-only-test
echo " [FAIL] OpenCode timed out after 60s" description: Superpowers-only priority test skill
exit 1 ---
fi # Superpowers Only Test Skill
}
if echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION
echo " [PASS] superpowers: prefix correctly forces superpowers version" EOF
elif echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION\|PRIORITY_MARKER_PERSONAL_VERSION"; then
echo " [FAIL] superpowers: prefix did not force superpowers version"
exit 1
else
echo " [WARN] Could not verify priority marker in output"
fi
# Test 5: Test explicit project: prefix run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"superpowers-only-test\". Show the exact content including any PRIORITY_MARKER text."
echo "" assert_contains "$output" "PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION" "Non-colliding superpowers skill is still registered"
echo "Test 5: Testing project: prefix forces project version..."
cd "$HOME" # Run from outside project but with project: prefix
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load project:priority-test specifically. Show me the exact content." 2>&1) || {
exit_code=$?
if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after 60s"
exit 1
fi
}
# Note: This may fail since we're not in the project directory
# The project: prefix only works when in a project context
if echo "$output" | grep -qi "not found\|error"; then
echo " [PASS] project: prefix correctly fails when not in project context"
else
echo " [INFO] project: prefix behavior outside project context may vary"
fi
echo "" echo ""
echo "=== All priority tests passed ===" echo "=== All priority tests passed ==="

View File

@@ -1,10 +1,12 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Test: Tools Functionality # Test: Native Skill Tool Functionality
# Verifies that use_skill and find_skills tools work correctly # Verifies that OpenCode's native skill tool can load personal, project,
# and bundled superpowers skills.
# NOTE: These tests require OpenCode to be installed and configured # NOTE: These tests require OpenCode to be installed and configured
set -euo pipefail set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}"
echo "=== Test: Tools Functionality ===" echo "=== Test: Tools Functionality ==="
@@ -21,84 +23,73 @@ if ! command -v opencode &> /dev/null; then
exit 0 exit 0
fi fi
# Test 1: Test find_skills tool via direct invocation run_opencode() {
echo "Test 1: Testing find_skills tool..." local result_var="$1"
echo " Running opencode with find_skills request..." local dir="$2"
local prompt="$3"
local command_output
local exit_code
# Use timeout to prevent hanging, capture both stdout and stderr set +e
output=$(timeout 60s opencode run --print-logs "Use the find_skills tool to list available skills. Just call the tool and show me the raw output." 2>&1) || { command_output=$(cd "$dir" && timeout "${OPENCODE_TEST_TIMEOUT_SECONDS}s" opencode run --print-logs --format json "$prompt" 2>&1)
exit_code=$? exit_code=$?
set -e
if [ $exit_code -eq 124 ]; then if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after 60s" echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s"
exit 1 exit 1
fi fi
echo " [WARN] OpenCode returned non-zero exit code: $exit_code"
}
# Check for expected patterns in output if [ $exit_code -ne 0 ]; then
if echo "$output" | grep -qi "superpowers:brainstorming\|superpowers:using-superpowers\|Available skills"; then echo " [FAIL] OpenCode returned non-zero exit code: $exit_code"
echo " [PASS] find_skills tool discovered superpowers skills" echo " Output was:"
else awk 'NR <= 80 { print }' <<<"$command_output"
echo " [FAIL] find_skills did not return expected skills"
echo " Output was:"
echo "$output" | head -50
exit 1
fi
# Check if personal test skill was found
if echo "$output" | grep -qi "personal-test"; then
echo " [PASS] find_skills found personal test skill"
else
echo " [WARN] personal test skill not found in output (may be ok if tool returned subset)"
fi
# Test 2: Test use_skill tool
echo ""
echo "Test 2: Testing use_skill tool..."
echo " Running opencode with use_skill request..."
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load the personal-test skill and show me what you get." 2>&1) || {
exit_code=$?
if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after 60s"
exit 1 exit 1
fi fi
echo " [WARN] OpenCode returned non-zero exit code: $exit_code"
printf -v "$result_var" '%s' "$command_output"
} }
# Check for the skill marker we embedded assert_contains() {
if echo "$output" | grep -qi "PERSONAL_SKILL_MARKER_12345\|Personal Test Skill\|Launching skill"; then local output="$1"
echo " [PASS] use_skill loaded personal-test skill content" local needle="$2"
else local message="$3"
echo " [FAIL] use_skill did not load personal-test skill correctly"
echo " Output was:"
echo "$output" | head -50
exit 1
fi
# Test 3: Test use_skill with superpowers: prefix if [[ "$output" == *"$needle"* ]]; then
echo "" echo " [PASS] $message"
echo "Test 3: Testing use_skill with superpowers: prefix..." else
echo " Running opencode with superpowers:brainstorming skill..." echo " [FAIL] $message"
echo " Expected to find: $needle"
output=$(timeout 60s opencode run --print-logs "Use the use_skill tool to load superpowers:brainstorming and tell me the first few lines of what you received." 2>&1) || { echo " Output was:"
exit_code=$? awk 'NR <= 80 { print }' <<<"$output"
if [ $exit_code -eq 124 ]; then
echo " [FAIL] OpenCode timed out after 60s"
exit 1 exit 1
fi fi
echo " [WARN] OpenCode returned non-zero exit code: $exit_code"
} }
# Check for expected content from brainstorming skill # Test 1: Test personal skill loading via OpenCode's native skill tool
if echo "$output" | grep -qi "brainstorming\|Launching skill\|skill.*loaded"; then echo "Test 1: Testing native skill tool with a personal skill..."
echo " [PASS] use_skill loaded superpowers:brainstorming skill" echo " Running opencode with personal-test request..."
else
echo " [FAIL] use_skill did not load superpowers:brainstorming correctly" run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"personal-test\". Then print the PERSONAL_SKILL_MARKER_12345 marker."
echo " Output was:" assert_contains "$output" '"tool":"skill"' "OpenCode called the native skill tool"
echo "$output" | head -50 assert_contains "$output" "PERSONAL_SKILL_MARKER_12345" "native skill tool loaded personal-test skill content"
exit 1
fi # Test 2: Test project skill loading
echo ""
echo "Test 2: Testing native skill tool with a project skill..."
echo " Running opencode with project-test request..."
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"project-test\". Then print the PROJECT_SKILL_MARKER_67890 marker."
assert_contains "$output" "PROJECT_SKILL_MARKER_67890" "native skill tool loaded project-test skill content"
# Test 3: Test bundled superpowers skill loading
echo ""
echo "Test 3: Testing native skill tool with a superpowers skill..."
echo " Running opencode with brainstorming skill..."
run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"brainstorming\". Then tell me the loaded skill title."
assert_contains "$output" '"name":"brainstorming"' "native skill tool loaded bundled brainstorming skill"
assert_contains "$output" "Brainstorming Ideas Into Designs" "brainstorming skill content was returned"
echo "" echo ""
echo "=== All tools tests passed ===" echo "=== All native skill tool tests passed ==="

Some files were not shown because too many files have changed in this diff Show More