From f2cbfbefebbfef77321e4c9abc9e949826bea9d7 Mon Sep 17 00:00:00 2001 From: Jesse Vincent Date: Mon, 4 May 2026 15:05:01 -0700 Subject: [PATCH] Release v5.1.0 (#1468) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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) * 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) * 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) * docs: clarify executing-plans in What Does NOT Change section Co-Authored-By: Claude Opus 4.6 (1M context) * 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) * 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) * 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) * Revert "Replace subagent review loops with lightweight inline self-review" This reverts commit bf8f7572eb85d793b73a44913e8039f9a2e83c1e. * Reapply "Replace subagent review loops with lightweight inline self-review" This reverts commit b045fa3950f4adffd9228d6ddb15aaee7ab2a556. * 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 ab500dade6187cf78b9b263ecf4799ec3420d1ef. * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) * 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) --------- Co-authored-by: Drew Ritter Co-authored-by: Claude Opus 4.6 (1M context) Co-authored-by: Drew Ritter Co-authored-by: Blaž Čulina Co-authored-by: Jesse Vincent Co-authored-by: voidborne-d Co-authored-by: Richard Luo Co-authored-by: Drew Ritter 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 --- .claude-plugin/marketplace.json | 2 +- .claude-plugin/plugin.json | 2 +- .codex-plugin/plugin.json | 5 +- .codex/INSTALL.md | 67 -- .cursor-plugin/plugin.json | 2 +- .opencode/INSTALL.md | 31 +- .opencode/plugins/superpowers.js | 31 +- README.md | 149 +-- RELEASE-NOTES.md | 84 ++ agents/code-reviewer.md | 48 - commands/brainstorm.md | 5 - commands/execute-plan.md | 5 - commands/write-plan.md | 5 - docs/README.codex.md | 126 --- docs/README.opencode.md | 31 +- .../plans/2026-04-06-worktree-rototill.md | 879 ++++++++++++++++++ .../2026-04-06-worktree-rototill-design.md | 342 +++++++ docs/testing.md | 4 +- gemini-extension.json | 2 +- hooks/hooks-cursor.json | 2 +- package.json | 2 +- scripts/sync-to-codex-plugin.sh | 40 +- skills/executing-plans/SKILL.md | 2 +- .../finishing-a-development-branch/SKILL.md | 135 ++- skills/requesting-code-review/SKILL.md | 16 +- .../requesting-code-review/code-reviewer.md | 214 +++-- skills/subagent-driven-development/SKILL.md | 4 +- .../code-quality-reviewer-prompt.md | 5 +- skills/systematic-debugging/CREATION-LOG.md | 2 +- .../root-cause-tracing.md | 2 +- skills/using-git-worktrees/SKILL.md | 193 ++-- .../references/codex-tools.md | 55 +- .../references/copilot-tools.md | 12 +- .../references/gemini-tools.md | 24 +- skills/writing-plans/SKILL.md | 2 +- tests/claude-code/README.md | 12 + tests/claude-code/run-skill-tests.sh | 1 + .../test-requesting-code-review.sh | 214 +++++ ...subagent-driven-development-integration.sh | 34 +- .../test-worktree-native-preference.sh | 176 ++++ .../test-sync-to-codex-plugin.sh | 44 + tests/opencode/run-tests.sh | 2 + tests/opencode/test-bootstrap-caching.mjs | 124 +++ tests/opencode/test-bootstrap-caching.sh | 32 + tests/opencode/test-priority.sh | 191 ++-- tests/opencode/test-tools.sh | 123 ++- 46 files changed, 2669 insertions(+), 814 deletions(-) delete mode 100644 .codex/INSTALL.md delete mode 100644 agents/code-reviewer.md delete mode 100644 commands/brainstorm.md delete mode 100644 commands/execute-plan.md delete mode 100644 commands/write-plan.md delete mode 100644 docs/README.codex.md create mode 100644 docs/superpowers/plans/2026-04-06-worktree-rototill.md create mode 100644 docs/superpowers/specs/2026-04-06-worktree-rototill-design.md create mode 100755 tests/claude-code/test-requesting-code-review.sh create mode 100755 tests/claude-code/test-worktree-native-preference.sh create mode 100644 tests/opencode/test-bootstrap-caching.mjs create mode 100755 tests/opencode/test-bootstrap-caching.sh diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index b6c7949d..109bf72e 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -9,7 +9,7 @@ { "name": "superpowers", "description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques", - "version": "5.0.7", + "version": "5.1.0", "source": "./", "author": { "name": "Jesse Vincent", diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index cad4d55f..3c266623 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "superpowers", "description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques", - "version": "5.0.7", + "version": "5.1.0", "author": { "name": "Jesse Vincent", "email": "jesse@fsck.com" diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index d4f3f7a3..da22bc7e 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "superpowers", - "version": "5.0.7", + "version": "5.1.0", "description": "An agentic skills framework & software development methodology that works: planning, TDD, debugging, and collaboration workflows.", "author": { "name": "Jesse Vincent", @@ -36,6 +36,9 @@ "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", diff --git a/.codex/INSTALL.md b/.codex/INSTALL.md deleted file mode 100644 index c415e2e1..00000000 --- a/.codex/INSTALL.md +++ /dev/null @@ -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`. diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index 153deac4..b007cf60 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "superpowers", "displayName": "Superpowers", "description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques", - "version": "5.0.7", + "version": "5.1.0", "author": { "name": "Jesse Vincent", "email": "jesse@fsck.com" diff --git a/.opencode/INSTALL.md b/.opencode/INSTALL.md index 2dc2b238..94c34151 100644 --- a/.opencode/INSTALL.md +++ b/.opencode/INSTALL.md @@ -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" +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 If you previously installed superpowers using `git clone` and symlinks, remove the old setup: @@ -46,7 +50,10 @@ use skill tool to load superpowers/brainstorming ## 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: @@ -64,6 +71,26 @@ To pin a specific version: 2. Verify the plugin line in your `opencode.json` 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 1. Use `skill` tool to list what's discovered diff --git a/.opencode/plugins/superpowers.js b/.opencode/plugins/superpowers.js index 48a2b72d..f2b95f23 100644 --- a/.opencode/plugins/superpowers.js +++ b/.opencode/plugins/superpowers.js @@ -46,17 +46,29 @@ const normalizePath = (p, homeDir) => { 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 }) => { const homeDir = os.homedir(); const superpowersSkillsDir = path.resolve(__dirname, '../../skills'); const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir); const configDir = envConfigDir || path.join(homeDir, '.config/opencode'); - // Helper to generate bootstrap content + // Helper to generate bootstrap content (cached after first call) const getBootstrapContent = () => { + // Return cached result on subsequent calls + if (_bootstrapCache !== undefined) return _bootstrapCache; + // Try to load using-superpowers skill 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 { content } = extractAndStripFrontmatter(fullContent); @@ -70,7 +82,7 @@ When skills reference tools you don't have, substitute OpenCode equivalents: Use OpenCode's native \`skill\` tool to list and load skills.`; - return ` + _bootstrapCache = ` 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.** @@ -79,6 +91,8 @@ ${content} ${toolMapping} `; + + return _bootstrapCache; }; return { @@ -98,13 +112,22 @@ ${toolMapping} // 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(); if (!bootstrap || !output.messages.length) return; const firstUser = output.messages.find(m => m.info.role === 'user'); if (!firstUser || !firstUser.parts.length) return; - // Only inject once + + // 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 }); } diff --git a/README.md b/README.md index c10c960f..ea17e30e 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ 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 CLI](#codex-cli), [Codex App](#codex-app), [Factory Droid](#factory-droid), [Gemini CLI](#gemini-cli), [OpenCode](#opencode), [Cursor](#cursor), [GitHub Copilot CLI](#github-copilot-cli). + ## How it works It starts from the moment you fire up your coding agent. As soon as it sees that you're building something, it *doesn't* just jump into trying to write code. Instead, it steps back and asks you what you're really trying to do. @@ -26,95 +30,126 @@ Thanks! ## Installation -**Note:** Installation differs by platform. +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) -Install the plugin from Anthropic's official marketplace: +#### Official Marketplace -```bash -/plugin install superpowers@claude-plugins-official -``` +- Install the plugin from Anthropic's official marketplace: -### Claude Code (Superpowers Marketplace) + ```bash + /plugin install superpowers@claude-plugins-official + ``` + +#### Superpowers Marketplace The Superpowers marketplace provides Superpowers and some other related plugins for Claude Code. -In Claude Code, register the marketplace first: +- Register the marketplace: -```bash -/plugin marketplace add obra/superpowers-marketplace -``` + ```bash + /plugin marketplace add obra/superpowers-marketplace + ``` -Then install the plugin from this marketplace: +- Install the plugin from this marketplace: -```bash -/plugin install superpowers@superpowers-marketplace -``` + ```bash + /plugin install superpowers@superpowers-marketplace + ``` -### OpenAI Codex CLI +### Codex CLI -- Open plugin search interface +Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins). -```bash -/plugins -``` +- Open the plugin search interface: -Search for Superpowers + ```bash + /plugins + ``` -```bash -superpowers -``` +- Search for Superpowers: -Select `Install Plugin` + ```bash + superpowers + ``` -### OpenAI Codex App +- Select `Install Plugin`. + +### Codex App + +Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins). - In the Codex app, click on Plugins in the sidebar. -- You should see `Superpowers` in the Coding section. +- You should see `Superpowers` in the Coding section. - Click the `+` next to Superpowers and follow the prompts. +### Factory Droid -### Cursor (via Plugin Marketplace) +- Register the marketplace: -In Cursor Agent chat, install from marketplace: + ```bash + droid plugin marketplace add https://github.com/obra/superpowers + ``` -```text -/add-plugin superpowers -``` +- Install the plugin: -or search for "superpowers" in the plugin marketplace. - -### OpenCode - -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) - -### GitHub Copilot CLI - -```bash -copilot plugin marketplace add obra/superpowers-marketplace -copilot plugin install superpowers@superpowers-marketplace -``` + ```bash + droid plugin install superpowers@superpowers + ``` ### Gemini CLI -```bash -gemini extensions install https://github.com/obra/superpowers -``` +- Install the extension: -To update: + ```bash + gemini extensions install https://github.com/obra/superpowers + ``` -```bash -gemini extensions update superpowers -``` +- Update later: + + ```bash + gemini extensions update superpowers + ``` + +### 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) + +### Cursor + +- In Cursor Agent chat, install from marketplace: + + ```text + /add-plugin superpowers + ``` + +- Or search for "superpowers" in the plugin marketplace. + +### GitHub Copilot CLI + +- Register the marketplace: + + ```bash + copilot plugin marketplace add obra/superpowers-marketplace + ``` + +- Install the plugin: + + ```bash + copilot plugin install superpowers@superpowers-marketplace + ``` ## The Basic Workflow diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 675eca2a..50944a69 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,5 +1,89 @@ # 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. +- **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 diff --git a/agents/code-reviewer.md b/agents/code-reviewer.md deleted file mode 100644 index 4e14076b..00000000 --- a/agents/code-reviewer.md +++ /dev/null @@ -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: 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" Since a major project step has been completed, use the code-reviewer agent to validate the work against the plan and identify any issues. 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" A numbered step from the planning document has been completed, so the code-reviewer agent should review the work. -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. diff --git a/commands/brainstorm.md b/commands/brainstorm.md deleted file mode 100644 index dbc66997..00000000 --- a/commands/brainstorm.md +++ /dev/null @@ -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. diff --git a/commands/execute-plan.md b/commands/execute-plan.md deleted file mode 100644 index 298e2954..00000000 --- a/commands/execute-plan.md +++ /dev/null @@ -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. diff --git a/commands/write-plan.md b/commands/write-plan.md deleted file mode 100644 index 5275df71..00000000 --- a/commands/write-plan.md +++ /dev/null @@ -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. diff --git a/docs/README.codex.md b/docs/README.codex.md deleted file mode 100644 index 97e2319c..00000000 --- a/docs/README.codex.md +++ /dev/null @@ -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 diff --git a/docs/README.opencode.md b/docs/README.opencode.md index 71b74c52..95120669 100644 --- a/docs/README.opencode.md +++ b/docs/README.opencode.md @@ -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" +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 If you previously installed superpowers using `git clone` and symlinks, remove the old setup: @@ -78,7 +82,10 @@ Create project-specific skills in `.opencode/skills/` within your project. ## 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: @@ -112,6 +119,26 @@ Skills written for Claude Code are automatically adapted for OpenCode: 2. Verify the plugin line in your `opencode.json` is correct 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 1. Use OpenCode's `skill` tool to list available skills diff --git a/docs/superpowers/plans/2026-04-06-worktree-rototill.md b/docs/superpowers/plans/2026-04-06-worktree-rototill.md new file mode 100644 index 00000000..ae5acec1 --- /dev/null +++ b/docs/superpowers/plans/2026-04-06-worktree-rototill.md @@ -0,0 +1,879 @@ +# 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 `` on branch ``." +- Detached HEAD: "Already in isolated workspace at `` (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 existing 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. + +2. **Check for existing global directory:** + ```bash + project=$(basename "$(git rev-parse --show-toplevel)") + ls -d ~/.config/superpowers/worktrees/$project 2>/dev/null + ``` + If found, use it (backward compatibility with legacy global path). + +3. **Check your instructions for a worktree directory preference.** If specified, use it without asking. + +4. **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. + +Global directories (`~/.config/superpowers/worktrees/`) need no verification. + +#### Create the Worktree + +```bash +project=$(basename "$(git rev-parse --show-toplevel)") + +# Determine path based on chosen location +# For project-local: path="$LOCATION/$BRANCH_NAME" +# For global: path="~/.config/superpowers/worktrees/$project/$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 +Tests passing ( tests, 0 failures) +Ready to implement +``` + +## 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/` | +| Global path exists | Use it (backward compat) | +| 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 hooks symlink and legacy path compat +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 ( 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 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 +git pull +git merge + +# Verify tests on merged result + + +# Only after merge succeeds: remove worktree, then delete branch +# (See Step 6 for worktree cleanup) +git branch -d +``` + +Then: Cleanup worktree (Step 6) + +#### Option 2: Push and Create PR + +```bash +# Push branch +git push -u origin + +# Create PR +gh pr create --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 `~/.config/superpowers/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 `~/.config/superpowers/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. diff --git a/docs/superpowers/specs/2026-04-06-worktree-rototill-design.md b/docs/superpowers/specs/2026-04-06-worktree-rototill-design.md new file mode 100644 index 00000000..a26e7886 --- /dev/null +++ b/docs/superpowers/specs/2026-04-06-worktree-rototill-design.md @@ -0,0 +1,342 @@ +# 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 `~/.config/superpowers/worktrees/`, superpowers owns it. Anything else (`.claude/worktrees/`, `~/.codex/worktrees/`, `.gemini/worktrees/`) belongs to the harness. + +## 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 for existing `.worktrees/` or `worktrees/` directory — if found, use it. If both exist, `.worktrees/` wins. +2. Check for existing `~/.config/superpowers/worktrees/<project>/` directory — if found, use it (backward compatibility with legacy global path). +3. Check the project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent) for a worktree directory preference. +4. Default to `.worktrees/`. + +No interactive directory selection prompt. The global path (`~/.config/superpowers/worktrees/`) is no longer offered as a choice to new users, but existing worktrees at that location are detected and used for backward compatibility. + +**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 ~/.config/superpowers/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 `~/.config/superpowers/worktrees/` = ours, anything else = hands off` heuristic works for every current harness. If a future harness adopts `.worktrees/` 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) diff --git a/docs/testing.md b/docs/testing.md index 6f87afed..c283e78e 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -149,8 +149,8 @@ python3 tests/claude-code/analyze-token-usage.py ~/.claude/projects/<project-dir 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" +# Example for /Users/yourname/Documents/GitHub/superpowers/superpowers +SESSION_DIR="$HOME/.claude/projects/-Users-yourname-Documents-GitHub-superpowers-superpowers" # Find recent sessions ls -lt "$SESSION_DIR"/*.jsonl | head -5 diff --git a/gemini-extension.json b/gemini-extension.json index d52654ae..eea51fa7 100644 --- a/gemini-extension.json +++ b/gemini-extension.json @@ -1,6 +1,6 @@ { "name": "superpowers", "description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques", - "version": "5.0.7", + "version": "5.1.0", "contextFileName": "GEMINI.md" } diff --git a/hooks/hooks-cursor.json b/hooks/hooks-cursor.json index 6df4461f..84e6d338 100644 --- a/hooks/hooks-cursor.json +++ b/hooks/hooks-cursor.json @@ -3,7 +3,7 @@ "hooks": { "sessionStart": [ { - "command": "./hooks/session-start" + "command": "./hooks/run-hook.cmd session-start" } ] } diff --git a/package.json b/package.json index 04f22b42..2b814663 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "superpowers", - "version": "5.0.7", + "version": "5.1.0", "type": "module", "main": ".opencode/plugins/superpowers.js" } diff --git a/scripts/sync-to-codex-plugin.sh b/scripts/sync-to-codex-plugin.sh index 16fd89ae..fc0a8e85 100755 --- a/scripts/sync-to-codex-plugin.sh +++ b/scripts/sync-to-codex-plugin.sh @@ -4,7 +4,8 @@ # # 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/), commits, +# (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. # @@ -223,6 +224,7 @@ fi DEST="$DEST_REPO/$DEST_REL" PREVIEW_REPO="$DEST_REPO" PREVIEW_DEST="$DEST" +SYNC_SOURCE="" overlay_destination_paths() { local repo="$1" @@ -291,7 +293,7 @@ apply_to_preview_checkout() { mkdir -p "$PREVIEW_DEST" fi - rsync "${RSYNC_ARGS[@]}" "$UPSTREAM/" "$PREVIEW_DEST/" + rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$PREVIEW_DEST/" } preview_checkout_has_changes() { @@ -316,6 +318,36 @@ 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) # ============================================================================= @@ -331,7 +363,7 @@ if [[ $BOOTSTRAP -eq 1 ]]; then fi echo "" echo "=== Preview (rsync --dry-run) ===" -rsync "${RSYNC_ARGS[@]}" --dry-run --itemize-changes "$UPSTREAM/" "$PREVIEW_DEST/" +rsync "${RSYNC_ARGS[@]}" --dry-run --itemize-changes "$SYNC_SOURCE/" "$PREVIEW_DEST/" echo "=== End preview ===" echo "" @@ -368,7 +400,7 @@ echo "Syncing upstream content..." if [[ $BOOTSTRAP -eq 1 ]]; then mkdir -p "$DEST" fi -rsync "${RSYNC_ARGS[@]}" "$UPSTREAM/" "$DEST/" +rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$DEST/" # Bail early if nothing actually changed cd "$DEST_REPO" diff --git a/skills/executing-plans/SKILL.md b/skills/executing-plans/SKILL.md index e67f94c5..a5918627 100644 --- a/skills/executing-plans/SKILL.md +++ b/skills/executing-plans/SKILL.md @@ -65,6 +65,6 @@ After all tasks complete and verified: ## Integration **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:finishing-a-development-branch** - Complete development after all tasks diff --git a/skills/finishing-a-development-branch/SKILL.md b/skills/finishing-a-development-branch/SKILL.md index c308b43b..43da0ae1 100644 --- a/skills/finishing-a-development-branch/SKILL.md +++ b/skills/finishing-a-development-branch/SKILL.md @@ -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. -**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." @@ -37,7 +37,24 @@ Stop. Don't proceed 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 # 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?" -### 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? @@ -61,30 +78,45 @@ Implementation complete. What would you like to do? 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 4: Execute Choice +### Step 5: Execute Choice #### Option 1: Merge Locally ```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> - -# Pull latest git pull - -# Merge feature branch git merge <feature-branch> # Verify tests on merged result <test command> -# If tests pass -git branch -d <feature-branch> +# Only after merge succeeds: cleanup worktree (Step 6), then delete 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 @@ -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 @@ -127,36 +159,46 @@ Wait for exact confirmation. If confirmed: ```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> ``` -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 -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/`, `worktrees/`, or `~/.config/superpowers/worktrees/`:** Superpowers created this worktree — we own cleanup. + ```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 | Option | Merge | Push | Keep Worktree | Cleanup Branch | |--------|-------|------|---------------|----------------| -| 1. Merge locally | ✓ | - | - | ✓ | -| 2. Create PR | - | ✓ | ✓ | - | -| 3. Keep as-is | - | - | ✓ | - | -| 4. Discard | - | - | - | ✓ (force) | +| 1. Merge locally | yes | - | - | yes | +| 2. Create PR | - | yes | yes | - | +| 3. Keep as-is | - | - | yes | - | +| 4. Discard | - | - | - | yes (force) | ## Common Mistakes @@ -165,13 +207,25 @@ git worktree remove <worktree-path> - **Fix:** Always verify tests before offering options **Open-ended questions** -- **Problem:** "What should I do next?" → ambiguous -- **Fix:** Present exactly 4 structured options +- **Problem:** "What should I do next?" is ambiguous +- **Fix:** Present exactly 4 structured options (or 3 for detached HEAD) -**Automatic worktree cleanup** -- **Problem:** Remove worktree when might need it (Option 2, 3) +**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/`, `worktrees/`, or `~/.config/superpowers/worktrees/` + **No confirmation for discard** - **Problem:** Accidentally delete work - **Fix:** Require typed "discard" confirmation @@ -183,18 +237,15 @@ git worktree remove <worktree-path> - 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 -- Present exactly 4 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 - -## 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 +- `cd` to main repo root before worktree removal +- Run `git worktree prune` after removal diff --git a/skills/requesting-code-review/SKILL.md b/skills/requesting-code-review/SKILL.md index fe7c8d90..34b83404 100644 --- a/skills/requesting-code-review/SKILL.md +++ b/skills/requesting-code-review/SKILL.md @@ -5,7 +5,7 @@ description: Use when completing tasks, implementing major features, or before m # 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. @@ -29,16 +29,15 @@ BASE_SHA=$(git rev-parse HEAD~1) # or origin/main 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` +Use Task tool with `general-purpose` type, fill template at `code-reviewer.md` **Placeholders:** -- `{WHAT_WAS_IMPLEMENTED}` - What you just built +- `{DESCRIPTION}` - Brief summary of what you built - `{PLAN_OR_REQUIREMENTS}` - What it should do - `{BASE_SHA}` - Starting commit - `{HEAD_SHA}` - Ending commit -- `{DESCRIPTION}` - Brief summary **3. Act on feedback:** - 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}') HEAD_SHA=$(git rev-parse HEAD) -[Dispatch superpowers:code-reviewer subagent] - WHAT_WAS_IMPLEMENTED: Verification and repair functions for conversation index +[Dispatch code reviewer subagent] + DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types PLAN_OR_REQUIREMENTS: Task 2 from docs/superpowers/plans/deployment-plan.md BASE_SHA: a7981ec HEAD_SHA: 3df7661 - DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types [Subagent returns]: Strengths: Clean architecture, real tests @@ -82,7 +80,7 @@ You: [Fix progress indicators] - Fix before moving to next task **Executing Plans:** -- Review after each batch (3 tasks) +- Review after each task or at natural checkpoints - Get feedback, apply, continue **Ad-Hoc Development:** diff --git a/skills/requesting-code-review/code-reviewer.md b/skills/requesting-code-review/code-reviewer.md index 3c427c91..525e4b47 100644 --- a/skills/requesting-code-review/code-reviewer.md +++ b/skills/requesting-code-review/code-reviewer.md @@ -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:** -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 +**Purpose:** Review completed work against requirements and code quality standards before it cascades into more work. -## What Was Implemented +``` +Task tool (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} -**Head:** {HEAD_SHA} + ## Git Range to Review -```bash -git diff --stat {BASE_SHA}..{HEAD_SHA} -git diff {BASE_SHA}..{HEAD_SHA} + **Base:** {BASE_SHA} + **Head:** {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:** -- 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 +**Reviewer returns:** Strengths, Issues (Critical / Important / Minor), Recommendations, Assessment ## Example Output diff --git a/skills/subagent-driven-development/SKILL.md b/skills/subagent-driven-development/SKILL.md index 5150b186..ea7ac8fd 100644 --- a/skills/subagent-driven-development/SKILL.md +++ b/skills/subagent-driven-development/SKILL.md @@ -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 +**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 ```dot @@ -265,7 +267,7 @@ Done! ## Integration **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:requesting-code-review** - Code review template for reviewer subagents - **superpowers:finishing-a-development-branch** - Complete development after all tasks diff --git a/skills/subagent-driven-development/code-quality-reviewer-prompt.md b/skills/subagent-driven-development/code-quality-reviewer-prompt.md index a04201ac..51f901a5 100644 --- a/skills/subagent-driven-development/code-quality-reviewer-prompt.md +++ b/skills/subagent-driven-development/code-quality-reviewer-prompt.md @@ -7,14 +7,13 @@ Use this template when dispatching a code quality reviewer subagent. **Only dispatch after spec compliance review passes.** ``` -Task tool (superpowers:code-reviewer): +Task tool (general-purpose): 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] BASE_SHA: [commit before task] HEAD_SHA: [current commit] - DESCRIPTION: [task summary] ``` **In addition to standard code quality concerns, the reviewer should check:** diff --git a/skills/systematic-debugging/CREATION-LOG.md b/skills/systematic-debugging/CREATION-LOG.md index 024d00a5..9aa03092 100644 --- a/skills/systematic-debugging/CREATION-LOG.md +++ b/skills/systematic-debugging/CREATION-LOG.md @@ -4,7 +4,7 @@ Reference example of extracting, structuring, and bulletproofing a critical skil ## 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) - Core mandate: ALWAYS find root cause, NEVER fix symptoms - Rules designed to resist time pressure and rationalization diff --git a/skills/systematic-debugging/root-cause-tracing.md b/skills/systematic-debugging/root-cause-tracing.md index 94847749..12ef5222 100644 --- a/skills/systematic-debugging/root-cause-tracing.md +++ b/skills/systematic-debugging/root-cause-tracing.md @@ -33,7 +33,7 @@ digraph when_to_use { ### 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 diff --git a/skills/using-git-worktrees/SKILL.md b/skills/using-git-worktrees/SKILL.md index e153843c..134d3714 100644 --- a/skills/using-git-worktrees/SKILL.md +++ b/skills/using-git-worktrees/SKILL.md @@ -1,104 +1,117 @@ --- 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 ## 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." -## Directory Selection Process +## Step 0: Detect Existing Isolation -Follow this priority order: - -### 1. Check Existing Directories +**Before creating anything, check if you are already in an isolated workspace.** ```bash -# Check in priority order -ls -d .worktrees 2>/dev/null # Preferred (hidden) -ls -d worktrees 2>/dev/null # Alternative +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) ``` -**If found:** Use that directory. If both exist, `.worktrees` wins. - -### 2. Check CLAUDE.md +**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 -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 3 (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. -``` -No worktree directory found. Where should I create worktrees? +Has the user already indicated their worktree preference in your instructions? If not, ask for consent before creating a worktree: -1. .worktrees/ (project-local, hidden) -2. ~/.config/superpowers/worktrees/<project-name>/ (global location) +> "Would you like me to set up an isolated worktree? It protects your current branch from changes." -Which would you prefer? -``` +Honor any existing declared preference without asking. If the user declines consent, work in place and skip to Step 3. -## 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 3. + +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. **Check for an existing global directory:** + ```bash + project=$(basename "$(git rev-parse --show-toplevel)") + ls -d ~/.config/superpowers/worktrees/$project 2>/dev/null + ``` + If found, use it (backward compatibility with legacy global path). + +4. **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:** ```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 ``` -**If NOT ignored:** - -Per Jesse's rule "Fix broken things immediately": -1. Add appropriate line to .gitignore -2. Commit the change -3. Proceed with worktree creation +**If NOT ignored:** Add to .gitignore, commit the change, then proceed. **Why critical:** Prevents accidentally committing worktree contents to repository. -### For Global Directory (~/.config/superpowers/worktrees) +Global directories (`~/.config/superpowers/worktrees/`) need no verification. -No .gitignore verification needed - outside project entirely. - -## Creation Steps - -### 1. Detect Project Name +#### Create the Worktree ```bash project=$(basename "$(git rev-parse --show-toplevel)") -``` -### 2. Create Worktree +# Determine path based on chosen location +# For project-local: path="$LOCATION/$BRANCH_NAME" +# For global: path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME" -```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" 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 3: Project Setup Auto-detect and run appropriate setup: @@ -117,23 +130,20 @@ if [ -f pyproject.toml ]; then poetry install; fi if [ -f go.mod ]; then go mod download; fi ``` -### 4. Verify Clean Baseline +## Step 4: Verify Clean Baseline -Run tests to ensure worktree starts clean: +Run tests to ensure workspace starts clean: ```bash -# Examples - use project-appropriate command -npm test -cargo test -pytest -go test ./... +# 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. -### 5. Report Location +### Report ``` Worktree ready at <full-path> @@ -145,16 +155,32 @@ Ready to implement <feature-name> | 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 CLAUDE.md → Ask user | +| Neither exists | Check instruction file, then default `.worktrees/` | +| Global path exists | Use it (backward compat) | | 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 @@ -163,56 +189,27 @@ Ready to implement <feature-name> ### Assuming directory location - **Problem:** Creates inconsistency, violates project conventions -- **Fix:** Follow priority: existing > CLAUDE.md > ask +- **Fix:** Follow priority: existing > global legacy > 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 -### 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 **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) - Skip baseline test verification - Proceed with failing tests without asking -- Assume directory location when ambiguous -- Skip CLAUDE.md check **Always:** -- Follow directory priority: existing > CLAUDE.md > ask +- Run Step 0 detection first +- Prefer native tools over git fallback +- Follow directory priority: existing > global legacy > instruction file > default - Verify directory is ignored for project-local - Auto-detect and run project setup - 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 diff --git a/skills/using-superpowers/references/codex-tools.md b/skills/using-superpowers/references/codex-tools.md index 539b2b1c..f50d40d4 100644 --- a/skills/using-superpowers/references/codex-tools.md +++ b/skills/using-superpowers/references/codex-tools.md @@ -4,9 +4,9 @@ Skills use Claude Code tool names. When you encounter these in a skill, use your | Skill references | Codex equivalent | |-----------------|------------------| -| `Task` tool (dispatch subagent) | `spawn_agent` (see [Named agent dispatch](#named-agent-dispatch)) | +| `Task` tool (dispatch subagent) | `spawn_agent` (see [Subagent dispatch requires multi-agent support](#subagent-dispatch-requires-multi-agent-support)) | | Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls | -| Task returns result | `wait` | +| Task returns result | `wait_agent` | | Task completes automatically | `close_agent` to free slot | | `TodoWrite` (task tracking) | `update_plan` | | `Skill` tool (invoke a skill) | Skills load natively — just follow the instructions | @@ -22,53 +22,12 @@ Add to your Codex config (`~/.codex/config.toml`): 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 - -Claude Code skills reference named agent types like `superpowers:code-reviewer`. -Codex does not have a named agent registry — `spawn_agent` creates generic agents -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. +Legacy note: Codex builds before `rust-v0.115.0` exposed spawned-agent +waiting as `wait`. Current Codex uses `wait_agent` for spawned agents. The +`wait` name now belongs to code-mode `exec/wait`, which resumes a yielded exec +cell by `cell_id`; it is not the spawned-agent result tool. ## Environment Detection diff --git a/skills/using-superpowers/references/copilot-tools.md b/skills/using-superpowers/references/copilot-tools.md index 4316cdbc..ae3cf5a6 100644 --- a/skills/using-superpowers/references/copilot-tools.md +++ b/skills/using-superpowers/references/copilot-tools.md @@ -12,23 +12,13 @@ Skills use Claude Code tool names. When you encounter these in a skill, use your | `Glob` (search files by name) | `glob` | | `Skill` tool (invoke a skill) | `skill` | | `WebFetch` | `web_fetch` | -| `Task` tool (dispatch subagent) | `task` (see [Agent types](#agent-types)) | +| `Task` tool (dispatch subagent) | `task` with `agent_type: "general-purpose"` or `"explore"` | | Multiple `Task` calls (parallel) | Multiple `task` calls | | Task status/output | `read_agent`, `list_agents` | | `TodoWrite` (task tracking) | `sql` with built-in `todos` table | | `WebSearch` | No equivalent — use `web_fetch` with a search engine URL | | `EnterPlanMode` / `ExitPlanMode` | No equivalent — stay in the main session | -## Agent types - -Copilot CLI's `task` tool accepts an `agent_type` parameter: - -| Claude Code agent | Copilot CLI equivalent | -|-------------------|----------------------| -| `general-purpose` | `"general-purpose"` | -| `Explore` | `"explore"` | -| Named plugin agents (e.g. `superpowers:code-reviewer`) | Discovered automatically from installed plugins | - ## Async shell sessions Copilot CLI supports persistent async shell sessions, which have no direct Claude Code equivalent: diff --git a/skills/using-superpowers/references/gemini-tools.md b/skills/using-superpowers/references/gemini-tools.md index f8698033..91ef4049 100644 --- a/skills/using-superpowers/references/gemini-tools.md +++ b/skills/using-superpowers/references/gemini-tools.md @@ -14,11 +14,29 @@ Skills use Claude Code tool names. When you encounter these in a skill, use your | `Skill` tool (invoke a skill) | `activate_skill` | | `WebSearch` | `google_web_search` | | `WebFetch` | `web_fetch` | -| `Task` tool (dispatch subagent) | No equivalent — Gemini CLI does not support subagents | +| `Task` tool (dispatch subagent) | `@agent-name` (see [Subagent support](#subagent-support)) | -## No subagent support +## Subagent support -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`. +Gemini CLI supports subagents natively via the `@` syntax. Use the built-in `@generalist` agent to dispatch any task — it has access to all tools and follows the prompt you provide. + +When a skill says to dispatch a named agent type, use `@generalist` with the full prompt from the skill's prompt template: + +| Skill instruction | Gemini CLI equivalent | +|-------------------|----------------------| +| `Task tool (superpowers:implementer)` | `@generalist` with the filled `implementer-prompt.md` template | +| `Task tool (superpowers:spec-reviewer)` | `@generalist` with the filled `spec-reviewer-prompt.md` template | +| `Task tool (superpowers:code-reviewer)` | `@code-reviewer` (bundled agent) or `@generalist` with the filled review prompt | +| `Task tool (superpowers:code-quality-reviewer)` | `@generalist` with the filled `code-quality-reviewer-prompt.md` template | +| `Task tool (general-purpose)` with inline prompt | `@generalist` with your inline prompt | + +### Prompt filling + +Skills provide prompt templates with placeholders like `{WHAT_WAS_IMPLEMENTED}` or `[FULL TEXT of task]`. Fill all placeholders and pass the complete prompt as the message to `@generalist`. The prompt template itself contains the agent's role, review criteria, and expected output format — `@generalist` will follow it. + +### Parallel dispatch + +Gemini CLI supports parallel subagent dispatch. When a skill asks you to dispatch multiple independent subagent tasks in parallel, request all of those `@generalist` or named subagent tasks together in the same prompt. Keep dependent tasks sequential, but do not serialize independent subagent tasks just to preserve a simpler history. ## Additional Gemini CLI tools diff --git a/skills/writing-plans/SKILL.md b/skills/writing-plans/SKILL.md index 0d9c00ba..847412ec 100644 --- a/skills/writing-plans/SKILL.md +++ b/skills/writing-plans/SKILL.md @@ -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." -**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` - (User preferences for plan location override this default) diff --git a/tests/claude-code/README.md b/tests/claude-code/README.md index e53647ba..473f1f28 100644 --- a/tests/claude-code/README.md +++ b/tests/claude-code/README.md @@ -115,6 +115,18 @@ Full workflow execution test (~10-30 minutes): - Subagents follow the skill correctly - Final code is functional and tested +#### test-requesting-code-review.sh +Behavioral test for the code reviewer subagent (~5 minutes): +- Builds a tiny project with a baseline commit +- Adds a second commit that plants two real bugs (SQL injection, plaintext password handling) +- Dispatches the code reviewer via the requesting-code-review skill +- Verifies the reviewer flags the planted bugs at Critical/Important severity and refuses to approve + +**What it tests:** +- The skill actually dispatches a working code reviewer subagent +- The reviewer template produces reviewers that catch obvious security bugs +- The reviewer is not sycophantic — it does not approve a diff with planted Critical issues + ## Adding New Tests 1. Create new test file: `test-<skill-name>.sh` diff --git a/tests/claude-code/run-skill-tests.sh b/tests/claude-code/run-skill-tests.sh index 3e339fd3..023e9794 100755 --- a/tests/claude-code/run-skill-tests.sh +++ b/tests/claude-code/run-skill-tests.sh @@ -79,6 +79,7 @@ tests=( # Integration tests (slow, full execution) integration_tests=( "test-subagent-driven-development-integration.sh" + "test-requesting-code-review.sh" ) # Add integration tests if requested diff --git a/tests/claude-code/test-requesting-code-review.sh b/tests/claude-code/test-requesting-code-review.sh new file mode 100755 index 00000000..ca8baafa --- /dev/null +++ b/tests/claude-code/test-requesting-code-review.sh @@ -0,0 +1,214 @@ +#!/usr/bin/env bash +# Integration Test: requesting-code-review skill +# Verifies the code reviewer dispatched via the skill catches a planted bug +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +PLUGIN_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +source "$SCRIPT_DIR/test-helpers.sh" + +echo "========================================" +echo " Integration Test: requesting-code-review" +echo "========================================" +echo "" +echo "This test verifies the code reviewer subagent by:" +echo " 1. Setting up a tiny project with a baseline commit" +echo " 2. Adding a second commit that plants an obvious bug" +echo " 3. Dispatching the code reviewer via the requesting-code-review skill" +echo " 4. Verifying the reviewer flags the planted bug as Critical/Important" +echo "" + +TEST_PROJECT=$(create_test_project) +echo "Test project: $TEST_PROJECT" +trap "cleanup_test_project $TEST_PROJECT" EXIT + +cd "$TEST_PROJECT" + +# Baseline: a small "safe" implementation +mkdir -p src +cat > src/db.js <<'EOF' +import { Database } from "./database-driver.js"; + +const db = new Database(); + +export async function findUserByEmail(email) { + if (typeof email !== "string" || !email) { + throw new Error("email required"); + } + return db.query( + "SELECT id, email, created_at FROM users WHERE email = ?", + [email], + ); +} +EOF + +cat > package.json <<'EOF' +{ "name": "test-codereview", "version": "1.0.0", "type": "module" } +EOF + +git init --quiet +git config user.email "test@test.com" +git config user.name "Test User" +git add . +git commit -m "Initial: parameterized findUserByEmail" --quiet +BASE_SHA=$(git rev-parse HEAD) + +# Second commit: plant two real bugs +# 1. SQL injection — switch from parameterized to string concatenation +# 2. Logs the user's password hash on every successful login +cat > src/db.js <<'EOF' +import { Database } from "./database-driver.js"; + +const db = new Database(); + +export async function findUserByEmail(email) { + return db.query( + "SELECT id, email, password_hash, created_at FROM users WHERE email = '" + email + "'", + ); +} + +export async function login(email, password) { + const user = await findUserByEmail(email); + if (user && user.password_hash === hash(password)) { + console.log("login success", { email, password_hash: user.password_hash }); + return user; + } + return null; +} + +function hash(s) { return s; } +EOF + +git add . +git commit -m "Refactor user lookup, add login" --quiet +HEAD_SHA=$(git rev-parse HEAD) + +echo "" +echo "Planted bugs in $BASE_SHA..$HEAD_SHA:" +echo " - SQL injection (string concat instead of parameterized query)" +echo " - Password hash logged in plaintext on every successful login" +echo " - hash() is the identity function (passwords stored & compared in plaintext)" +echo "" + +OUTPUT_FILE="$TEST_PROJECT/claude-output.txt" + +PROMPT="I just finished a refactor. The change is between commits $BASE_SHA and $HEAD_SHA on the current branch. + +Use the superpowers:requesting-code-review skill to review these changes before I merge. Follow the skill exactly: dispatch the code reviewer subagent with the template, give the subagent the SHA range, and report back what it found. + +Print the reviewer's full output." + +# 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 "================================================================================" +cd "$TEST_PROJECT" && timeout 600 claude -p "$PROMPT" \ + --plugin-dir "$PLUGIN_DIR" \ + --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || { + echo "" + echo "================================================================================" + echo "EXECUTION FAILED (exit code: $?)" + exit 1 +} +echo "================================================================================" + +echo "" +echo "Analyzing reviewer output..." +echo "" + +# Find the session transcript. Because we ran claude from $TEST_PROJECT (a +# unique tmp dir), its sessions live in their own ~/.claude/projects/ folder. +# Resolve the real path (macOS mktemp returns /var/... but claude normalizes +# it to /private/var/...) and replicate claude's normalization (every +# non-alphanumeric char becomes `-`). +TEST_PROJECT_REAL=$(cd "$TEST_PROJECT" && pwd -P) +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) + +FAILED=0 + +echo "=== Verification Tests ===" +echo "" + +# Test 1: Skill was actually invoked, and a subagent was actually dispatched +echo "Test 1: requesting-code-review skill invoked + reviewer subagent dispatched..." +if [ -z "$SESSION_FILE" ] || [ ! -f "$SESSION_FILE" ]; then + echo " [FAIL] Could not locate session transcript in $SESSION_DIR" + FAILED=$((FAILED + 1)) +elif ! grep -q '"skill":"superpowers:requesting-code-review"' "$SESSION_FILE"; then + echo " [FAIL] requesting-code-review skill was not invoked" + echo " Session: $SESSION_FILE" + FAILED=$((FAILED + 1)) +elif ! grep -q '"name":"Agent"' "$SESSION_FILE"; then + echo " [FAIL] Skill ran but no subagent was dispatched" + FAILED=$((FAILED + 1)) +else + echo " [PASS] Skill invoked and subagent dispatched" +fi +echo "" + +# Test 2: Reviewer caught the SQL injection +echo "Test 2: SQL injection flagged..." +if grep -qiE "sql injection|injection|string concat|parameterize|prepared statement|sanitiz" "$OUTPUT_FILE"; then + echo " [PASS] Reviewer flagged the SQL injection vector" +else + echo " [FAIL] Reviewer missed the SQL injection — most obvious planted bug" + FAILED=$((FAILED + 1)) +fi +echo "" + +# Test 3: Reviewer caught the credential / password issue (either logging or no real hashing) +echo "Test 3: Credential handling issue flagged..." +if grep -qiE "password|credential|secret|plaintext|log.*hash|hash.*log|sensitive" "$OUTPUT_FILE"; then + echo " [PASS] Reviewer flagged a credential / password handling issue" +else + echo " [FAIL] Reviewer missed the password/credential issues" + FAILED=$((FAILED + 1)) +fi +echo "" + +# Test 4: Reviewer marked at least one issue as Critical or Important (not just Minor) +echo "Test 4: Severity classification..." +if grep -qiE "critical|important|severe|high.*risk|security" "$OUTPUT_FILE"; then + echo " [PASS] Reviewer classified findings at Critical/Important severity" +else + echo " [FAIL] Reviewer did not classify findings as Critical or Important" + FAILED=$((FAILED + 1)) +fi +echo "" + +# Test 5: Reviewer did NOT approve the diff for merge +echo "Test 5: Reviewer verdict..." +# A correct reviewer says No or "With fixes". A broken/sycophantic reviewer says Yes/Ready. +if grep -qiE "ready to merge.*yes|approved.*for merge|^\s*yes\s*$|safe to merge" "$OUTPUT_FILE" \ + && ! grep -qiE "ready to merge.*no|with fixes|do not merge|not ready|block.*merge" "$OUTPUT_FILE"; then + echo " [FAIL] Reviewer approved a diff with planted Critical bugs" + FAILED=$((FAILED + 1)) +else + echo " [PASS] Reviewer did not approve the diff" +fi +echo "" + +echo "========================================" +echo " Test Summary" +echo "========================================" +echo "" + +if [ $FAILED -eq 0 ]; then + echo "STATUS: PASSED" + echo "The code reviewer correctly:" + echo " ✓ Was dispatched via the requesting-code-review skill" + echo " ✓ Flagged the SQL injection" + echo " ✓ Flagged the credential handling issues" + echo " ✓ Classified findings at Critical/Important severity" + echo " ✓ Did not approve the diff for merge" + exit 0 +else + echo "STATUS: FAILED" + echo "Failed $FAILED verification tests" + echo "" + echo "Output saved to: $OUTPUT_FILE" + exit 1 +fi diff --git a/tests/claude-code/test-subagent-driven-development-integration.sh b/tests/claude-code/test-subagent-driven-development-integration.sh index f0b17fb1..95a551bc 100755 --- a/tests/claude-code/test-subagent-driven-development-integration.sh +++ b/tests/claude-code/test-subagent-driven-development-integration.sh @@ -135,8 +135,7 @@ EOF # Note: We use a longer timeout since this is integration testing # Use --allowed-tools to enable tool usage in headless mode -# IMPORTANT: Run from superpowers directory so local dev skills are available -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. +PROMPT="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: 1. Read the plan once at the beginning @@ -147,9 +146,14 @@ IMPORTANT: Follow the skill exactly. I will be verifying that you: 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 "================================================================================" -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 "EXECUTION FAILED (exit code: $?)" @@ -161,13 +165,17 @@ echo "" echo "Execution complete. Analyzing results..." echo "" -# Find the session transcript -# Session files are in ~/.claude/projects/-<working-dir>/<session-id>.jsonl -WORKING_DIR_ESCAPED=$(echo "$SCRIPT_DIR/../.." | sed 's/\//-/g' | sed 's/^-//') -SESSION_DIR="$HOME/.claude/projects/$WORKING_DIR_ESCAPED" - -# Find the most recent session file (created during this test run) -SESSION_FILE=$(find "$SESSION_DIR" -name "*.jsonl" -type f -mmin -60 2>/dev/null | sort -r | head -1) +# Find the session transcript. Because we ran claude from $TEST_PROJECT (a +# unique tmp dir), its sessions live in their own ~/.claude/projects/ folder +# and we can pick the most-recent one without racing other concurrent sessions. +# Resolve the real path because macOS mktemp returns /var/... but claude +# normalizes it to /private/var/... when naming the project dir. +TEST_PROJECT_REAL=$(cd "$TEST_PROJECT" && pwd -P) +# 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 echo "ERROR: Could not find session transcript file" @@ -194,9 +202,9 @@ else fi 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..." -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 echo " [PASS] $task_count subagents dispatched" else diff --git a/tests/claude-code/test-worktree-native-preference.sh b/tests/claude-code/test-worktree-native-preference.sh new file mode 100755 index 00000000..cbfe7f29 --- /dev/null +++ b/tests/claude-code/test-worktree-native-preference.sh @@ -0,0 +1,176 @@ +#!/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: 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 ===" diff --git a/tests/codex-plugin-sync/test-sync-to-codex-plugin.sh b/tests/codex-plugin-sync/test-sync-to-codex-plugin.sh index a8fc245b..441230e1 100755 --- a/tests/codex-plugin-sync/test-sync-to-codex-plugin.sh +++ b/tests/codex-plugin-sync/test-sync-to-codex-plugin.sh @@ -73,6 +73,19 @@ assert_matches() { 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" @@ -244,6 +257,22 @@ EOF 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" @@ -261,6 +290,7 @@ write_synced_destination_fixture() { "$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 @@ -282,12 +312,19 @@ EOF 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 @@ -415,6 +452,7 @@ main() { local help_output local script_source local dirty_skill_path + local noop_openai_metadata_path echo "=== Test: sync-to-codex-plugin dry-run regression ===" @@ -443,6 +481,7 @@ main() { init_repo "$dest" write_destination_fixture "$dest" + add_openai_agent_metadata_fixture "$dest" checkout_fixture_branch "$dest" "$dest_branch" dirty_tracked_destination_skill "$dest" @@ -490,6 +529,7 @@ main() { 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..." @@ -505,6 +545,7 @@ main() { 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" @@ -542,6 +583,9 @@ Locally modified fixture content." "Dirty local apply preserves tracked working- 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..." diff --git a/tests/opencode/run-tests.sh b/tests/opencode/run-tests.sh index 334e2ef1..d9b100ef 100755 --- a/tests/opencode/run-tests.sh +++ b/tests/opencode/run-tests.sh @@ -44,6 +44,7 @@ while [[ $# -gt 0 ]]; do echo "" echo "Tests:" 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-priority.sh Test skill priority resolution (integration)" exit 0 @@ -59,6 +60,7 @@ done # List of tests to run (no external dependencies) tests=( "test-plugin-loading.sh" + "test-bootstrap-caching.sh" ) # Integration tests (require OpenCode) diff --git a/tests/opencode/test-bootstrap-caching.mjs b/tests/opencode/test-bootstrap-caching.mjs new file mode 100644 index 00000000..55c4e9eb --- /dev/null +++ b/tests/opencode/test-bootstrap-caching.mjs @@ -0,0 +1,124 @@ +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), + 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 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}`); + } + 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; +} diff --git a/tests/opencode/test-bootstrap-caching.sh b/tests/opencode/test-bootstrap-caching.sh new file mode 100755 index 00000000..958e9940 --- /dev/null +++ b/tests/opencode/test-bootstrap-caching.sh @@ -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 ===" diff --git a/tests/opencode/test-priority.sh b/tests/opencode/test-priority.sh index b7de0d61..b9f3e08a 100755 --- a/tests/opencode/test-priority.sh +++ b/tests/opencode/test-priority.sh @@ -1,10 +1,13 @@ #!/usr/bin/env bash # 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 set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}" echo "=== Test: Skill Priority Resolution ===" @@ -96,103 +99,119 @@ if ! command -v opencode &> /dev/null; then exit 0 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 "Test 2: Testing personal > superpowers priority..." +echo "Test 2: Documenting personal vs superpowers priority..." echo " Running from outside project directory..." -# Run from HOME (not in project) - should get personal version -cd "$HOME" -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) || { - exit_code=$? - if [ $exit_code -eq 124 ]; then - echo " [FAIL] OpenCode timed out after 60s" - exit 1 - fi -} +run_opencode output "$HOME" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text." +describe_priority_result \ + "$output" \ + "PRIORITY_MARKER_PERSONAL_VERSION" \ + "PRIORITY_MARKER_SUPERPOWERS_VERSION" \ + "Personal version loaded for duplicate native skill name" \ + "Current OpenCode behavior loaded bundled superpowers version instead of personal version" -if echo "$output" | grep -qi "PRIORITY_MARKER_PERSONAL_VERSION"; then - 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 +# Test 3: Document project vs bundled superpowers priority echo "" -echo "Test 3: Testing project > personal > superpowers priority..." +echo "Test 3: Documenting project vs personal/superpowers priority..." echo " Running from project directory..." -# Run from project directory - should get project version -cd "$TEST_HOME/test-project" -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) || { - exit_code=$? - if [ $exit_code -eq 124 ]; then - echo " [FAIL] OpenCode timed out after 60s" - exit 1 - fi -} +run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"priority-test\". Show the exact content including any PRIORITY_MARKER text." +describe_priority_result \ + "$output" \ + "PRIORITY_MARKER_PROJECT_VERSION" \ + "PRIORITY_MARKER_SUPERPOWERS_VERSION" \ + "Project version loaded for duplicate native skill name" \ + "Current OpenCode behavior loaded bundled superpowers version instead of project version" -if echo "$output" | grep -qi "PRIORITY_MARKER_PROJECT_VERSION"; then - 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 +# Test 4: Test a non-colliding bundled superpowers skill is still available 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" -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) || { - exit_code=$? - if [ $exit_code -eq 124 ]; then - echo " [FAIL] OpenCode timed out after 60s" - exit 1 - fi -} +mkdir -p "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test" +cat > "$SUPERPOWERS_SKILLS_DIR/superpowers-only-test/SKILL.md" <<'EOF' +--- +name: superpowers-only-test +description: Superpowers-only priority test skill +--- +# Superpowers Only Test Skill -if echo "$output" | grep -qi "PRIORITY_MARKER_SUPERPOWERS_VERSION"; then - echo " [PASS] superpowers: prefix correctly forces superpowers version" -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 +PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION +EOF -# Test 5: Test explicit project: prefix -echo "" -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 +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." +assert_contains "$output" "PRIORITY_MARKER_SUPERPOWERS_ONLY_VERSION" "Non-colliding superpowers skill is still registered" echo "" echo "=== All priority tests passed ===" diff --git a/tests/opencode/test-tools.sh b/tests/opencode/test-tools.sh index e4590fea..da79f3d5 100755 --- a/tests/opencode/test-tools.sh +++ b/tests/opencode/test-tools.sh @@ -1,10 +1,12 @@ #!/usr/bin/env bash -# Test: Tools Functionality -# Verifies that use_skill and find_skills tools work correctly +# Test: Native Skill Tool Functionality +# 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 set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +OPENCODE_TEST_TIMEOUT_SECONDS="${OPENCODE_TEST_TIMEOUT_SECONDS:-120}" echo "=== Test: Tools Functionality ===" @@ -21,84 +23,73 @@ if ! command -v opencode &> /dev/null; then exit 0 fi -# Test 1: Test find_skills tool via direct invocation -echo "Test 1: Testing find_skills tool..." -echo " Running opencode with find_skills request..." +run_opencode() { + local result_var="$1" + local dir="$2" + local prompt="$3" + local command_output + local exit_code -# Use timeout to prevent hanging, capture both stdout and stderr -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) || { + 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 60s" + echo " [FAIL] OpenCode timed out after ${OPENCODE_TEST_TIMEOUT_SECONDS}s" exit 1 fi - echo " [WARN] OpenCode returned non-zero exit code: $exit_code" -} -# Check for expected patterns in output -if echo "$output" | grep -qi "superpowers:brainstorming\|superpowers:using-superpowers\|Available skills"; then - echo " [PASS] find_skills tool discovered superpowers skills" -else - 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" + 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 - echo " [WARN] OpenCode returned non-zero exit code: $exit_code" + + printf -v "$result_var" '%s' "$command_output" } -# Check for the skill marker we embedded -if echo "$output" | grep -qi "PERSONAL_SKILL_MARKER_12345\|Personal Test Skill\|Launching skill"; then - echo " [PASS] use_skill loaded personal-test skill content" -else - echo " [FAIL] use_skill did not load personal-test skill correctly" - echo " Output was:" - echo "$output" | head -50 - exit 1 -fi +assert_contains() { + local output="$1" + local needle="$2" + local message="$3" -# Test 3: Test use_skill with superpowers: prefix -echo "" -echo "Test 3: Testing use_skill with superpowers: prefix..." -echo " Running opencode with superpowers:brainstorming skill..." - -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) || { - exit_code=$? - if [ $exit_code -eq 124 ]; then - echo " [FAIL] OpenCode timed out after 60s" + 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 - echo " [WARN] OpenCode returned non-zero exit code: $exit_code" } -# Check for expected content from brainstorming skill -if echo "$output" | grep -qi "brainstorming\|Launching skill\|skill.*loaded"; then - echo " [PASS] use_skill loaded superpowers:brainstorming skill" -else - echo " [FAIL] use_skill did not load superpowers:brainstorming correctly" - echo " Output was:" - echo "$output" | head -50 - exit 1 -fi +# Test 1: Test personal skill loading via OpenCode's native skill tool +echo "Test 1: Testing native skill tool with a personal skill..." +echo " Running opencode with personal-test request..." + +run_opencode output "$TEST_HOME/test-project" "Call the skill tool with name \"personal-test\". Then print the PERSONAL_SKILL_MARKER_12345 marker." +assert_contains "$output" '"tool":"skill"' "OpenCode called the native skill tool" +assert_contains "$output" "PERSONAL_SKILL_MARKER_12345" "native skill tool loaded personal-test skill content" + +# 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 "=== All tools tests passed ===" +echo "=== All native skill tool tests passed ==="