mirror of
https://github.com/obra/superpowers.git
synced 2026-06-09 17:02:07 +00:00
Compare commits
211 Commits
gs/plan-mo
...
codex/bump
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d180481eb9 | ||
|
|
201f945838 | ||
|
|
49bf5ad6dc | ||
|
|
4bd0973879 | ||
|
|
452f1ed40b | ||
|
|
cafbc5a4bd | ||
|
|
da35948daf | ||
|
|
d4d99117f2 | ||
|
|
01034bcf8f | ||
|
|
b87a5e4721 | ||
|
|
e47d6f4f85 | ||
|
|
5c0402736e | ||
|
|
d0e413b591 | ||
|
|
d25618db58 | ||
|
|
3d6dc90c6d | ||
|
|
a152bb3932 | ||
|
|
3dfb376268 | ||
|
|
491df7360c | ||
|
|
9088f563e7 | ||
|
|
d4cf61b4c8 | ||
|
|
7f02ccd91b | ||
|
|
35e42a16ce | ||
|
|
58082d04f8 | ||
|
|
3dc0ea6876 | ||
|
|
0bf37499b4 | ||
|
|
f7c5312265 | ||
|
|
f5175fb31a | ||
|
|
45c7dc2cce | ||
|
|
39d29a6c28 | ||
|
|
f1d2005de3 | ||
|
|
c0a65f1b4d | ||
|
|
f10cddac0d | ||
|
|
371f41596b | ||
|
|
6f0adebe96 | ||
|
|
fd5b53cb85 | ||
|
|
be0357f98a | ||
|
|
3b412a3836 | ||
|
|
2e46e9590d | ||
|
|
58f821314d | ||
|
|
81472cc9e6 | ||
|
|
b4363df1b9 | ||
|
|
f2cbfbefeb | ||
|
|
e7a2d16476 | ||
|
|
6efe32c9e2 | ||
|
|
b55764852a | ||
|
|
9f42444ab1 | ||
|
|
99e4c656bf | ||
|
|
a5dd364e42 | ||
|
|
c4bbe651cb | ||
|
|
34c17aefb2 | ||
|
|
f9b088f7b3 | ||
|
|
bc25777c6a | ||
|
|
bcdd7fa24c | ||
|
|
6149f3635a | ||
|
|
777a9770d8 | ||
|
|
da283df058 | ||
|
|
a569527b89 | ||
|
|
ac1c715ffb | ||
|
|
8c8c5e87ce | ||
|
|
a5d36b1300 | ||
|
|
917e5f53b1 | ||
|
|
a6b1a1fa0c | ||
|
|
b7a8f76985 | ||
|
|
4b1b20f69f | ||
|
|
eeaf2ad15b | ||
|
|
dd237283db | ||
|
|
c0b417e409 | ||
|
|
1f20bef3f5 | ||
|
|
f0df5eca30 | ||
|
|
0a1124ba53 | ||
|
|
65d760f9c2 | ||
|
|
2d942f3b01 | ||
|
|
8b1669269c | ||
|
|
a2964d7a20 | ||
|
|
eafe962b18 | ||
|
|
9f04f06351 | ||
|
|
f076bd3431 | ||
|
|
9e3ed213a0 | ||
|
|
9e6e077d33 | ||
|
|
151cfb16a0 | ||
|
|
a1155f623f | ||
|
|
3f80f1c769 | ||
|
|
4ae1a3d6a6 | ||
|
|
e6221a48c5 | ||
|
|
4fd9aa2dd5 | ||
|
|
2b1bfe5db6 | ||
|
|
bd080e3cc8 | ||
|
|
eb2b44b23f | ||
|
|
80c0a45fcc | ||
|
|
c28b28ffbd | ||
|
|
33e9bea3cc | ||
|
|
74a0c004eb | ||
|
|
8ea39819ee | ||
|
|
764215331d | ||
|
|
eccd45305a | ||
|
|
fb4adab518 | ||
|
|
7e516434f2 | ||
|
|
8a0a5ca6a3 | ||
|
|
2d46da1b37 | ||
|
|
0002948041 | ||
|
|
3128a2c3cd | ||
|
|
f34ee479b7 | ||
|
|
3cee13e516 | ||
|
|
1128a721ca | ||
|
|
d1b5f578b0 | ||
|
|
61a64d7098 | ||
|
|
825a142aa3 | ||
|
|
bd537d817d | ||
|
|
24be2e8b7c | ||
|
|
a479e10050 | ||
|
|
a4c48714bc | ||
|
|
2c6a8a352d | ||
|
|
2b25774f31 | ||
|
|
f4b54a1717 | ||
|
|
911fa1d6c5 | ||
|
|
4e7c0842f8 | ||
|
|
689f27c968 | ||
|
|
537ec640fd | ||
|
|
c5e9538311 | ||
|
|
fd318b1b79 | ||
|
|
ea472dedf0 | ||
|
|
addfe8511a | ||
|
|
c6a2b1b576 | ||
|
|
d19703b0a1 | ||
|
|
6d21e9cc07 | ||
|
|
687a66183d | ||
|
|
363923f74a | ||
|
|
3188953b0c | ||
|
|
9ccce3bf07 | ||
|
|
b484bae134 | ||
|
|
ec99b7c4a4 | ||
|
|
263e3268f4 | ||
|
|
85cab6eff0 | ||
|
|
7619570679 | ||
|
|
8d9b94eb8d | ||
|
|
7f6380dd91 | ||
|
|
8d6d876424 | ||
|
|
9c98e01873 | ||
|
|
5ef73d25b7 | ||
|
|
920559aea7 | ||
|
|
9d2b886211 | ||
|
|
ec26561aaa | ||
|
|
f0a4538b31 | ||
|
|
f7b6107576 | ||
|
|
e02842e024 | ||
|
|
7446c842d8 | ||
|
|
5e2a89e985 | ||
|
|
d3c028e280 | ||
|
|
7f8edd9c12 | ||
|
|
81acbcd51e | ||
|
|
c070e6bd45 | ||
|
|
5f14c1aa29 | ||
|
|
bdbad07f02 | ||
|
|
419889b0d3 | ||
|
|
715e18e448 | ||
|
|
21a774e95c | ||
|
|
9df7269d73 | ||
|
|
5e5d353916 | ||
|
|
c5e6eaf411 | ||
|
|
bdd45c70ab | ||
|
|
ec3f7f1027 | ||
|
|
edbb62e50f | ||
|
|
33e55e60b2 | ||
|
|
74f2b1c96e | ||
|
|
991e9d4de9 | ||
|
|
133a0a80c6 | ||
|
|
57b346ddbc | ||
|
|
8c01ac8051 | ||
|
|
245d50ec37 | ||
|
|
aba2542f5e | ||
|
|
3bdd66eaa5 | ||
|
|
c3ecc1b9ba | ||
|
|
f3083e55b0 | ||
|
|
70244011d4 | ||
|
|
d48b14e5ac | ||
|
|
daa3fb2322 | ||
|
|
69eaf3cf34 | ||
|
|
582264a54a | ||
|
|
7b99c39c08 | ||
|
|
6c274dcc2a | ||
|
|
ee14caeadd | ||
|
|
5e51c3ee5a | ||
|
|
f57638a747 | ||
|
|
4180afb7bd | ||
|
|
e4226df22e | ||
|
|
866f2bdb47 | ||
|
|
3c220d0cc1 | ||
|
|
02b3d7c96d | ||
|
|
1c53f5deb6 | ||
|
|
a26cbaab2e | ||
|
|
b23c084070 | ||
|
|
aa3bb5fe16 | ||
|
|
3d245777f0 | ||
|
|
26d7cca61b | ||
|
|
ad716b8d1b | ||
|
|
e4a2375cb7 | ||
|
|
d2d6cf4852 | ||
|
|
54d9133d7a | ||
|
|
394cf85013 | ||
|
|
31bbbe2dbb | ||
|
|
5fbefbd0a9 | ||
|
|
a0b9ecce2b | ||
|
|
772ec9f834 | ||
|
|
e16d611eee | ||
|
|
b7cad76134 | ||
|
|
4c836817da | ||
|
|
7f2ee614b6 | ||
|
|
b97b5f228d | ||
|
|
93c8966cab | ||
|
|
19df3db59b | ||
|
|
f8cf545bc5 |
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "4.2.0",
|
||||
"version": "5.1.0",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "4.2.0",
|
||||
"version": "5.1.0",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
@@ -9,5 +9,12 @@
|
||||
"homepage": "https://github.com/obra/superpowers",
|
||||
"repository": "https://github.com/obra/superpowers",
|
||||
"license": "MIT",
|
||||
"keywords": ["skills", "tdd", "debugging", "collaboration", "best-practices", "workflows"]
|
||||
"keywords": [
|
||||
"skills",
|
||||
"tdd",
|
||||
"debugging",
|
||||
"collaboration",
|
||||
"best-practices",
|
||||
"workflows"
|
||||
]
|
||||
}
|
||||
|
||||
48
.codex-plugin/plugin.json
Normal file
48
.codex-plugin/plugin.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "5.1.0",
|
||||
"description": "An agentic skills framework & software development methodology that works: planning, TDD, debugging, and collaboration workflows.",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com",
|
||||
"url": "https://github.com/obra"
|
||||
},
|
||||
"homepage": "https://github.com/obra/superpowers",
|
||||
"repository": "https://github.com/obra/superpowers",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"brainstorming",
|
||||
"subagent-driven-development",
|
||||
"skills",
|
||||
"planning",
|
||||
"tdd",
|
||||
"debugging",
|
||||
"code-review",
|
||||
"workflow"
|
||||
],
|
||||
"skills": "./skills/",
|
||||
"hooks": "./hooks/hooks-codex.json",
|
||||
"interface": {
|
||||
"displayName": "Superpowers",
|
||||
"shortDescription": "Planning, TDD, debugging, and delivery workflows for coding agents",
|
||||
"longDescription": "Use Superpowers to guide agent work through brainstorming, implementation planning, test-driven development, systematic debugging, parallel execution, code review, and finish-the-branch workflows.",
|
||||
"developerName": "Jesse Vincent",
|
||||
"category": "Coding",
|
||||
"capabilities": [
|
||||
"Interactive",
|
||||
"Read",
|
||||
"Write"
|
||||
],
|
||||
"defaultPrompt": [
|
||||
"I've got an idea for something I'd like to build.",
|
||||
"Let's add a feature to this project."
|
||||
],
|
||||
"websiteURL": "https://github.com/obra/superpowers",
|
||||
"privacyPolicyURL": "https://docs.github.com/en/site-policy/privacy-policies/github-general-privacy-statement",
|
||||
"termsOfServiceURL": "https://docs.github.com/en/site-policy/github-terms/github-terms-of-service",
|
||||
"brandColor": "#F59E0B",
|
||||
"composerIcon": "./assets/superpowers-small.svg",
|
||||
"logo": "./assets/app-icon.png",
|
||||
"screenshots": []
|
||||
}
|
||||
}
|
||||
@@ -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`.
|
||||
23
.cursor-plugin/plugin.json
Normal file
23
.cursor-plugin/plugin.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"displayName": "Superpowers",
|
||||
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.1.0",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
},
|
||||
"homepage": "https://github.com/obra/superpowers",
|
||||
"repository": "https://github.com/obra/superpowers",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"skills",
|
||||
"tdd",
|
||||
"debugging",
|
||||
"collaboration",
|
||||
"best-practices",
|
||||
"workflows"
|
||||
],
|
||||
"skills": "./skills/",
|
||||
"hooks": "./hooks/hooks-cursor.json"
|
||||
}
|
||||
52
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
52
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Something isn't working as expected
|
||||
labels: bug
|
||||
---
|
||||
|
||||
<!--
|
||||
BEFORE FILING: Search open AND closed issues. The Windows SessionStart
|
||||
hook alone has been reported 29 times. If your issue already exists,
|
||||
add a comment or reaction to the existing one instead.
|
||||
-->
|
||||
|
||||
- [ ] I searched existing issues and this is not a duplicate
|
||||
|
||||
## Environment
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Superpowers version | |
|
||||
| Harness (Claude Code, Cursor, etc.) | |
|
||||
| Harness version | |
|
||||
| Model | |
|
||||
| OS + shell | |
|
||||
|
||||
## Is this a Superpowers issue or a platform issue?
|
||||
<!-- Superpowers is a plugin. Some reported "bugs" are actually issues
|
||||
in the underlying platform or model. If you're not sure, try
|
||||
reproducing without Superpowers installed.
|
||||
|
||||
If the problem persists without Superpowers, file the issue with
|
||||
your platform instead. -->
|
||||
|
||||
- [ ] I confirmed this issue does not occur without Superpowers installed
|
||||
|
||||
## What happened?
|
||||
<!-- Be specific. "It doesn't work" is not a bug report. -->
|
||||
|
||||
## Steps to reproduce
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Expected behavior
|
||||
<!-- What should have happened? -->
|
||||
|
||||
## Actual behavior
|
||||
<!-- What happened instead? -->
|
||||
|
||||
## Debug log or conversation transcript
|
||||
<!-- A debug log or conversation transcript showing the issue is the
|
||||
single most helpful thing you can include. Without one, we're
|
||||
guessing. Screenshots of error output are also useful. -->
|
||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Questions & Help
|
||||
url: https://discord.gg/35wsABTejz
|
||||
about: For usage questions, troubleshooting help, and general discussion, please visit our Discord instead of opening an issue.
|
||||
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: Feature Request
|
||||
about: Propose a change or addition to Superpowers
|
||||
labels: enhancement
|
||||
---
|
||||
|
||||
<!--
|
||||
BEFORE FILING: Search open AND closed issues. Many features have been
|
||||
requested before — some were implemented differently, some are in
|
||||
progress, and some were intentionally declined.
|
||||
-->
|
||||
|
||||
- [ ] I searched existing issues and this has not been proposed before
|
||||
|
||||
## What problem does this solve?
|
||||
<!-- Describe the problem from your own experience. What were you doing,
|
||||
what went wrong or was missing, and why did it matter?
|
||||
|
||||
"It would be cool if..." is not a problem statement. -->
|
||||
|
||||
## Proposed solution
|
||||
<!-- What specifically do you want to happen? Be concrete. -->
|
||||
|
||||
## What alternatives did you consider?
|
||||
<!-- What other approaches could solve the same problem? Why is your
|
||||
proposal better? -->
|
||||
|
||||
## Is this appropriate for core Superpowers?
|
||||
<!-- Would this benefit someone working on a completely different kind
|
||||
of project? If this is specific to your domain, workflow, or a
|
||||
third-party tool, it may belong as its own plugin instead. -->
|
||||
|
||||
## Context
|
||||
<!-- Optional: version info, harness, model, workflow where you hit this. -->
|
||||
23
.github/ISSUE_TEMPLATE/platform_support.md
vendored
Normal file
23
.github/ISSUE_TEMPLATE/platform_support.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
name: IDE / Platform Support Request
|
||||
about: Request support for a new IDE, editor, or AI coding tool
|
||||
labels: platform-support
|
||||
---
|
||||
|
||||
<!--
|
||||
BEFORE FILING: Search existing issues — your IDE may already be
|
||||
requested or discussed.
|
||||
-->
|
||||
|
||||
- [ ] I searched existing issues for this IDE/platform
|
||||
|
||||
## Which IDE or platform?
|
||||
<!-- Name and link -->
|
||||
|
||||
## Does this tool have a plugin or extension system?
|
||||
<!-- If yes, link to the docs. If no, explain how third-party
|
||||
integrations typically work with this tool. -->
|
||||
|
||||
## Have you tried manual installation?
|
||||
<!-- Many tools work with Superpowers through manual setup even without
|
||||
official support. Did you try? What happened? -->
|
||||
126
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
126
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<!--
|
||||
BEFORE SUBMITTING: Read every word of this template. PRs that leave
|
||||
sections blank, contain multiple unrelated changes, or show no evidence
|
||||
of human involvement will be closed without review.
|
||||
-->
|
||||
|
||||
## What problem are you trying to solve?
|
||||
<!-- Describe the specific problem you encountered. If this was a session
|
||||
issue, include: what you were doing, what went wrong, the model's
|
||||
exact failure mode, and ideally a transcript or session log.
|
||||
|
||||
"Improving" something is not a problem statement. What broke? What
|
||||
failed? What was the user experience that motivated this? -->
|
||||
|
||||
## What does this PR change?
|
||||
<!-- 1-3 sentences. What, not why — the "why" belongs above. -->
|
||||
|
||||
## Is this change appropriate for the core library?
|
||||
<!-- Superpowers core contains general-purpose skills and infrastructure
|
||||
that benefit all users. Ask yourself:
|
||||
|
||||
- Would this be useful to someone working on a completely different
|
||||
kind of project than yours?
|
||||
- Is this project-specific, team-specific, or tool-specific?
|
||||
- Does this integrate or promote a third-party service?
|
||||
|
||||
If your change is a new skill for a specific domain, workflow tool,
|
||||
or third-party integration, it belongs in its own plugin — not here.
|
||||
See the plugin development docs for how to publish it separately. -->
|
||||
|
||||
## What alternatives did you consider?
|
||||
<!-- What other approaches did you try or evaluate before landing on this
|
||||
one? Why were they worse? If you didn't consider alternatives, say so
|
||||
— but know that's a red flag. -->
|
||||
|
||||
## Does this PR contain multiple unrelated changes?
|
||||
<!-- If yes: stop. Split it into separate PRs. Bundled PRs will be closed.
|
||||
If you believe the changes are related, explain the dependency. -->
|
||||
|
||||
## Existing PRs
|
||||
- [ ] I have reviewed all open AND closed PRs for duplicates or prior art
|
||||
- Related PRs: <!-- #number, #number, or "none found" -->
|
||||
|
||||
<!-- If a related closed PR exists, explain what's different about your
|
||||
approach and why it should succeed where the other didn't. -->
|
||||
|
||||
## Environment tested
|
||||
|
||||
| Harness (e.g. Claude Code, Cursor) | Harness version | Model | Model version/ID |
|
||||
|-------------------------------------|-----------------|-------|------------------|
|
||||
| | | | |
|
||||
|
||||
## New harness support (required if this PR adds a new harness)
|
||||
|
||||
<!-- If this PR adds support for a new harness (IDE, CLI tool, agent
|
||||
runner), you MUST include a session transcript proving the
|
||||
integration actually works.
|
||||
|
||||
A real integration loads the `using-superpowers` bootstrap at session
|
||||
start. The bootstrap is what causes skills to auto-trigger. Without
|
||||
it, the skills are dead weight — present on disk but never invoked
|
||||
at the right moments.
|
||||
|
||||
ACCEPTANCE TEST: Open a clean session in the new harness and send
|
||||
exactly this user message:
|
||||
|
||||
Let's make a react todo list
|
||||
|
||||
A working integration auto-triggers the `brainstorming` skill before
|
||||
any code is written. Paste the complete transcript below.
|
||||
|
||||
These are NOT real integrations and PRs that ship them will be closed:
|
||||
|
||||
- Manually copying skill files into the harness
|
||||
- Wrapping with `npx skills` or similar at-runtime shims
|
||||
- Anything that requires the user to opt in to skills per-session
|
||||
- Anything where brainstorming does not auto-trigger on the test above
|
||||
|
||||
If you are not sure whether your integration loads the bootstrap at
|
||||
session start, it does not.
|
||||
-->
|
||||
|
||||
<details>
|
||||
<summary>Clean-session transcript for "Let's make a react todo list"</summary>
|
||||
|
||||
```
|
||||
paste the complete transcript here
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Evaluation
|
||||
- What was the initial prompt you (or your human partner) used to start
|
||||
the session that led to this change?
|
||||
- How many eval sessions did you run AFTER making the change?
|
||||
- How did outcomes change compared to before the change?
|
||||
|
||||
<!-- "It works" is not evaluation. Describe the before/after difference
|
||||
you observed across multiple sessions. -->
|
||||
|
||||
## Rigor
|
||||
|
||||
- [ ] If this is a skills change: I used `superpowers:writing-skills` and
|
||||
completed adversarial pressure testing (paste results below)
|
||||
- [ ] This change was tested adversarially, not just on the happy path
|
||||
- [ ] I did not modify carefully-tuned content (Red Flags table,
|
||||
rationalizations, "human partner" language) without extensive evals
|
||||
showing the change is an improvement
|
||||
|
||||
<!-- If you changed wording in skills that shape agent behavior, show your
|
||||
eval methodology and results. These are not prose — they are code. -->
|
||||
|
||||
## Human review
|
||||
- [ ] A human has reviewed the COMPLETE proposed diff before submission
|
||||
|
||||
<!--
|
||||
STOP. If the checkbox above is not checked, do not submit this PR.
|
||||
|
||||
PRs will be closed without review if they:
|
||||
- Show no evidence of human involvement
|
||||
- Contain multiple unrelated changes
|
||||
- Promote or integrate third-party services or tools
|
||||
- Submit project-specific or personal configuration as core changes
|
||||
- Leave required sections blank or use placeholder text
|
||||
- Modify behavior-shaping content without eval evidence
|
||||
-->
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,6 +1,13 @@
|
||||
.worktrees/
|
||||
.private-journal/
|
||||
.claude/
|
||||
.DS_Store
|
||||
node_modules/
|
||||
inspo
|
||||
triage/
|
||||
|
||||
# Eval harness — drill ships its own gitignore at evals/.gitignore;
|
||||
# these are belt-and-suspenders entries for tools that don't recurse.
|
||||
evals/results/
|
||||
evals/.venv/
|
||||
evals/.env
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "evals"]
|
||||
path = evals
|
||||
url = git@github.com:prime-radiant-inc/superpowers-evals.git
|
||||
@@ -3,115 +3,111 @@
|
||||
## Prerequisites
|
||||
|
||||
- [OpenCode.ai](https://opencode.ai) installed
|
||||
- Git installed
|
||||
|
||||
## Installation Steps
|
||||
## Installation
|
||||
|
||||
### 1. Clone Superpowers
|
||||
Add superpowers to the `plugin` array in your `opencode.json` (global or project-level):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"]
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Register the Plugin
|
||||
Restart OpenCode. The plugin installs through OpenCode's plugin manager and
|
||||
registers all skills.
|
||||
|
||||
Create a symlink so OpenCode discovers the plugin:
|
||||
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:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/plugins
|
||||
# Remove old symlinks
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js
|
||||
ln -s ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js ~/.config/opencode/plugins/superpowers.js
|
||||
```
|
||||
|
||||
### 3. Symlink Skills
|
||||
|
||||
Create a symlink so OpenCode's native skill tool discovers superpowers skills:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills
|
||||
rm -rf ~/.config/opencode/skills/superpowers
|
||||
ln -s ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
|
||||
# Optionally remove the cloned repo
|
||||
rm -rf ~/.config/opencode/superpowers
|
||||
|
||||
# Remove skills.paths from opencode.json if you added one for superpowers
|
||||
```
|
||||
|
||||
### 4. Restart OpenCode
|
||||
|
||||
Restart OpenCode. The plugin will automatically inject superpowers context.
|
||||
|
||||
Verify by asking: "do you have superpowers?"
|
||||
Then follow the installation steps above.
|
||||
|
||||
## Usage
|
||||
|
||||
### Finding Skills
|
||||
|
||||
Use OpenCode's native `skill` tool to list available skills:
|
||||
Use OpenCode's native `skill` tool:
|
||||
|
||||
```
|
||||
use skill tool to list skills
|
||||
use skill tool to load brainstorming
|
||||
```
|
||||
|
||||
### Loading a Skill
|
||||
|
||||
Use OpenCode's native `skill` tool to load a specific skill:
|
||||
|
||||
```
|
||||
use skill tool to load superpowers/brainstorming
|
||||
```
|
||||
|
||||
### Personal Skills
|
||||
|
||||
Create your own skills in `~/.config/opencode/skills/`:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills/my-skill
|
||||
```
|
||||
|
||||
Create `~/.config/opencode/skills/my-skill/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-skill
|
||||
description: Use when [condition] - [what it does]
|
||||
---
|
||||
|
||||
# My Skill
|
||||
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
### Project Skills
|
||||
|
||||
Create project-specific skills in `.opencode/skills/` within your project.
|
||||
|
||||
**Skill Priority:** Project skills > Personal skills > Superpowers skills
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.config/opencode/superpowers
|
||||
git pull
|
||||
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:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git#v5.0.3"]
|
||||
}
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
1. Check plugin symlink: `ls -l ~/.config/opencode/plugins/superpowers.js`
|
||||
2. Check source exists: `ls ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
3. Check OpenCode logs for errors
|
||||
1. Check logs: `opencode run --print-logs "hello" 2>&1 | grep -i superpowers`
|
||||
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. Check skills symlink: `ls -l ~/.config/opencode/skills/superpowers`
|
||||
2. Verify it points to: `~/.config/opencode/superpowers/skills`
|
||||
3. Use `skill` tool to list what's discovered
|
||||
1. Use `skill` tool to list what's discovered
|
||||
2. Check that the plugin is loading (see above)
|
||||
|
||||
### Tool mapping
|
||||
|
||||
When skills reference Claude Code tools:
|
||||
- `TodoWrite` → `update_plan`
|
||||
- `Task` with subagents → `@mention` syntax
|
||||
- `Skill` tool → OpenCode's native `skill` tool
|
||||
- File operations → your native tools
|
||||
Skills speak in actions ("create a todo", "dispatch a subagent", "read a file"). On OpenCode these resolve to:
|
||||
|
||||
- "Create a todo" / "mark complete in todo list" → `todowrite`
|
||||
- `Subagent (general-purpose):` template → `task` tool with `subagent_type: "general"` (or `"explore"` for codebase exploration)
|
||||
- "Invoke a skill" → OpenCode's native `skill` tool
|
||||
- "Read a file" → `read`
|
||||
- "Create a file" / "edit a file" / "delete a file" → `apply_patch`
|
||||
- "Run a shell command" → `bash`
|
||||
- "Search file contents" / "find files by name" → `grep`, `glob`
|
||||
- "Fetch a URL" → `webfetch`
|
||||
|
||||
## Getting Help
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* Superpowers plugin for OpenCode.ai
|
||||
*
|
||||
* Injects superpowers bootstrap context via system prompt transform.
|
||||
* Skills are discovered via OpenCode's native skill tool from symlinked directory.
|
||||
* Injects superpowers bootstrap context via message transform.
|
||||
* Auto-registers skills directory via config hook (no symlinks needed).
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
@@ -46,33 +46,47 @@ 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);
|
||||
|
||||
const toolMapping = `**Tool Mapping for OpenCode:**
|
||||
When skills reference tools you don't have, substitute OpenCode equivalents:
|
||||
- \`TodoWrite\` → \`update_plan\`
|
||||
- \`Task\` tool with subagents → Use OpenCode's subagent system (@mention)
|
||||
- \`Skill\` tool → OpenCode's native \`skill\` tool
|
||||
- \`Read\`, \`Write\`, \`Edit\`, \`Bash\` → Your native tools
|
||||
When skills request actions, substitute OpenCode equivalents:
|
||||
- Create or update todos → \`todowrite\`
|
||||
- \`Subagent (general-purpose):\` → \`task\` with \`subagent_type: "general"\`
|
||||
- Invoke a skill → OpenCode's native \`skill\` tool
|
||||
- Read files → \`read\`
|
||||
- Create, edit, or delete files → \`apply_patch\`
|
||||
- Run shell commands → \`bash\`
|
||||
- Search files → \`grep\`, \`glob\`
|
||||
- Fetch a URL → \`webfetch\`
|
||||
|
||||
**Skills location:**
|
||||
Superpowers skills are in \`${configDir}/skills/superpowers/\`
|
||||
Use OpenCode's native \`skill\` tool to list and load skills.`;
|
||||
|
||||
return `<EXTREMELY_IMPORTANT>
|
||||
_bootstrapCache = `<EXTREMELY_IMPORTANT>
|
||||
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.**
|
||||
@@ -81,15 +95,45 @@ ${content}
|
||||
|
||||
${toolMapping}
|
||||
</EXTREMELY_IMPORTANT>`;
|
||||
|
||||
return _bootstrapCache;
|
||||
};
|
||||
|
||||
return {
|
||||
// Use system prompt transform to inject bootstrap (fixes #226 agent reset bug)
|
||||
'experimental.chat.system.transform': async (_input, output) => {
|
||||
const bootstrap = getBootstrapContent();
|
||||
if (bootstrap) {
|
||||
(output.system ||= []).push(bootstrap);
|
||||
// Inject skills path into live config so OpenCode discovers superpowers skills
|
||||
// without requiring manual symlinks or config file edits.
|
||||
// This works because Config.get() returns a cached singleton — modifications
|
||||
// here are visible when skills are lazily discovered later.
|
||||
config: async (config) => {
|
||||
config.skills = config.skills || {};
|
||||
config.skills.paths = config.skills.paths || [];
|
||||
if (!config.skills.paths.includes(superpowersSkillsDir)) {
|
||||
config.skills.paths.push(superpowersSkillsDir);
|
||||
}
|
||||
},
|
||||
|
||||
// Inject bootstrap into the first user message of each session.
|
||||
// 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;
|
||||
|
||||
// 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 });
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
121
.pi/extensions/superpowers.ts
Normal file
121
.pi/extensions/superpowers.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { dirname, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
|
||||
const EXTREMELY_IMPORTANT_MARKER = "<EXTREMELY_IMPORTANT>";
|
||||
const BOOTSTRAP_MARKER = "superpowers:using-superpowers bootstrap for pi";
|
||||
|
||||
const extensionDir = dirname(fileURLToPath(import.meta.url));
|
||||
const packageRoot = resolve(extensionDir, "../..");
|
||||
const skillsDir = resolve(packageRoot, "skills");
|
||||
const bootstrapSkillPath = resolve(skillsDir, "using-superpowers", "SKILL.md");
|
||||
|
||||
let cachedBootstrap: string | null | undefined;
|
||||
|
||||
export default function superpowersPiExtension(pi: ExtensionAPI) {
|
||||
let injectBootstrap = true;
|
||||
|
||||
pi.on("resources_discover", async () => ({
|
||||
skillPaths: [skillsDir],
|
||||
}));
|
||||
|
||||
pi.on("session_start", async () => {
|
||||
injectBootstrap = true;
|
||||
});
|
||||
|
||||
pi.on("session_compact", async () => {
|
||||
injectBootstrap = true;
|
||||
});
|
||||
|
||||
pi.on("agent_end", async () => {
|
||||
injectBootstrap = false;
|
||||
});
|
||||
|
||||
pi.on("context", async (event) => {
|
||||
if (!injectBootstrap) return;
|
||||
if (event.messages.some(messageContainsBootstrap)) return;
|
||||
|
||||
const bootstrap = getBootstrapContent();
|
||||
if (!bootstrap) return;
|
||||
|
||||
const bootstrapMessage = {
|
||||
role: "user" as const,
|
||||
content: [{ type: "text" as const, text: bootstrap }],
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
|
||||
const insertAt = firstNonCompactionSummaryIndex(event.messages);
|
||||
return {
|
||||
messages: [
|
||||
...event.messages.slice(0, insertAt),
|
||||
bootstrapMessage,
|
||||
...event.messages.slice(insertAt),
|
||||
],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getBootstrapContent(): string | null {
|
||||
if (cachedBootstrap !== undefined) return cachedBootstrap;
|
||||
|
||||
try {
|
||||
const skillContent = readFileSync(bootstrapSkillPath, "utf8");
|
||||
const body = stripFrontmatter(skillContent);
|
||||
cachedBootstrap = `${EXTREMELY_IMPORTANT_MARKER}
|
||||
${BOOTSTRAP_MARKER}
|
||||
|
||||
You have superpowers.
|
||||
|
||||
The using-superpowers skill content is included below and is already loaded for this Pi session. Follow it now. Do not try to load using-superpowers again.
|
||||
|
||||
${body}
|
||||
|
||||
${piToolMapping()}
|
||||
</EXTREMELY_IMPORTANT>`;
|
||||
return cachedBootstrap;
|
||||
} catch {
|
||||
cachedBootstrap = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function stripFrontmatter(content: string): string {
|
||||
const match = content.match(/^---\n[\s\S]*?\n---\n([\s\S]*)$/);
|
||||
return (match ? match[1] : content).trim();
|
||||
}
|
||||
|
||||
function piToolMapping(): string {
|
||||
return `## Pi tool mapping
|
||||
|
||||
Pi has native skills but does not expose Claude Code's \`Skill\` tool. When a Superpowers instruction says to invoke a skill, use Pi's native skill system instead: load the relevant \`SKILL.md\` with \`read\` when the skill applies, or let a human invoke \`/skill:name\` explicitly.
|
||||
|
||||
Pi's built-in coding tools are lowercase: \`read\`, \`write\`, \`edit\`, \`bash\`, plus optional \`grep\`, \`find\`, and \`ls\`. Use those for the corresponding actions: read a file, create or edit files, run shell commands, search file contents, find files by name, and list directories.
|
||||
|
||||
Pi does not ship a standard subagent tool. If a subagent tool such as \`subagent\` from \`pi-subagents\` is available, use it for Superpowers subagent workflows. If no subagent tool is available, do the work in this session or explain the missing capability instead of inventing \`Task\` calls.
|
||||
|
||||
Pi does not ship a standard task-list tool. If an installed todo/task tool is available, use it. Otherwise track work in plan files or a repo-local \`TODO.md\` when task tracking is needed. Treat older \`TodoWrite\` references as this task-tracking action.`;
|
||||
}
|
||||
|
||||
function messageContainsBootstrap(message: unknown): boolean {
|
||||
const content = (message as { content?: unknown }).content;
|
||||
if (typeof content === "string") return content.includes(BOOTSTRAP_MARKER);
|
||||
if (!Array.isArray(content)) return false;
|
||||
return content.some((part) => {
|
||||
return (
|
||||
part &&
|
||||
typeof part === "object" &&
|
||||
(part as { type?: unknown }).type === "text" &&
|
||||
typeof (part as { text?: unknown }).text === "string" &&
|
||||
(part as { text: string }).text.includes(BOOTSTRAP_MARKER)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function firstNonCompactionSummaryIndex(messages: unknown[]): number {
|
||||
let index = 0;
|
||||
while ((messages[index] as { role?: unknown } | undefined)?.role === "compactionSummary") {
|
||||
index += 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
21
.pre-commit-config.yaml
Normal file
21
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: evals-ruff-check
|
||||
name: evals ruff check
|
||||
entry: uv --project evals run ruff check
|
||||
language: system
|
||||
files: ^evals/.*\.py$
|
||||
|
||||
- id: evals-ruff-format-check
|
||||
name: evals ruff format --check
|
||||
entry: uv --project evals run ruff format --check
|
||||
language: system
|
||||
files: ^evals/.*\.py$
|
||||
|
||||
- id: evals-ty-check
|
||||
name: evals ty check
|
||||
entry: uv --directory evals run ty check
|
||||
language: system
|
||||
pass_filenames: false
|
||||
files: ^evals/.*\.py$
|
||||
20
.version-bump.json
Normal file
20
.version-bump.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"files": [
|
||||
{ "path": "package.json", "field": "version" },
|
||||
{ "path": ".claude-plugin/plugin.json", "field": "version" },
|
||||
{ "path": ".cursor-plugin/plugin.json", "field": "version" },
|
||||
{ "path": ".codex-plugin/plugin.json", "field": "version" },
|
||||
{ "path": ".claude-plugin/marketplace.json", "field": "plugins.0.version" },
|
||||
{ "path": "gemini-extension.json", "field": "version" }
|
||||
],
|
||||
"audit": {
|
||||
"exclude": [
|
||||
"CHANGELOG.md",
|
||||
"RELEASE-NOTES.md",
|
||||
"node_modules",
|
||||
".git",
|
||||
".version-bump.json",
|
||||
"scripts/bump-version.sh"
|
||||
]
|
||||
}
|
||||
}
|
||||
110
CLAUDE.md
Normal file
110
CLAUDE.md
Normal file
@@ -0,0 +1,110 @@
|
||||
# Superpowers — Contributor Guidelines
|
||||
|
||||
## If You Are an AI Agent
|
||||
|
||||
Stop. Read this section before doing anything.
|
||||
|
||||
This repo has a 94% PR rejection rate. Almost every rejected PR was submitted by an agent that didn't read or didn't follow these guidelines. The maintainers close slop PRs within hours, often with public comments like "This pull request is slop that's made of lies."
|
||||
|
||||
**Your job is to protect your human partner from that outcome.** Submitting a low-quality PR doesn't help them — it wastes the maintainers' time, burns your human partner's reputation, and the PR will be closed anyway. That is not being helpful. That is being a tool of embarrassment.
|
||||
|
||||
Before you open a PR against this repo, you MUST:
|
||||
|
||||
1. **Read the entire PR template** at `.github/PULL_REQUEST_TEMPLATE.md` and fill in every section with real, specific answers. Not summaries. Not placeholders.
|
||||
2. **Search for existing PRs** — open AND closed — that address the same problem. If duplicates exist, STOP and tell your human partner. Do not open another duplicate.
|
||||
3. **Verify this is a real problem.** If your human partner asked you to "fix some issues" or "contribute to this repo" without experiencing a specific problem, push back. Ask them what broke, what failed, what the user experience was.
|
||||
4. **Confirm the change belongs in core.** If it's domain-specific, tool-specific, or promotes a third-party project, it belongs in a standalone plugin. Tell your human partner.
|
||||
5. **Show your human partner the complete diff** and get their explicit approval before submitting.
|
||||
|
||||
If any of these checks fail, do not open the PR. Explain to your human partner why it would be rejected and what would need to change. They will thank you for saving them the embarrassment.
|
||||
|
||||
## Pull Request Requirements
|
||||
|
||||
**Every PR must fully complete the PR template.** No section may be left blank or filled with placeholder text. PRs that skip sections will be closed without review.
|
||||
|
||||
**Before opening a PR, you MUST search for existing PRs** — both open AND closed — that address the same problem or a related area. Reference what you found in the "Existing PRs" section. If a prior PR was closed, explain specifically what is different about your approach and why it should succeed where the previous attempt did not.
|
||||
|
||||
**PRs that show no evidence of human involvement will be closed.** A human must review the complete proposed diff before submission.
|
||||
|
||||
## What We Will Not Accept
|
||||
|
||||
### Third-party dependencies
|
||||
|
||||
PRs that add optional or required dependencies on third-party projects will not be accepted unless they are adding support for a new harness (e.g., a new IDE or CLI tool). Superpowers is a zero-dependency plugin by design. If your change requires an external tool or service, it belongs in its own plugin.
|
||||
|
||||
### "Compliance" changes to skills
|
||||
|
||||
Our internal skill philosophy differs from Anthropic's published guidance on writing skills. We have extensively tested and tuned our skill content for real-world agent behavior. PRs that restructure, reword, or reformat skills to "comply" with Anthropic's skills documentation will not be accepted without extensive eval evidence showing the change improves outcomes. The bar for modifying behavior-shaping content is very high.
|
||||
|
||||
### Project-specific or personal configuration
|
||||
|
||||
Skills, hooks, or configuration that only benefit a specific project, team, domain, or workflow do not belong in core. Publish these as a separate plugin.
|
||||
|
||||
### Bulk or spray-and-pray PRs
|
||||
|
||||
Do not trawl the issue tracker and open PRs for multiple issues in a single session. Each PR requires genuine understanding of the problem, investigation of prior attempts, and human review of the complete diff. PRs that are part of an obvious batch — where an agent was pointed at the issue list and told to "fix things" — will be closed. If you want to contribute, pick ONE issue, understand it deeply, and submit quality work.
|
||||
|
||||
### Speculative or theoretical fixes
|
||||
|
||||
Every PR must solve a real problem that someone actually experienced. "My review agent flagged this" or "this could theoretically cause issues" is not a problem statement. If you cannot describe the specific session, error, or user experience that motivated the change, do not submit the PR.
|
||||
|
||||
### Domain-specific skills
|
||||
|
||||
Superpowers core contains general-purpose skills that benefit all users regardless of their project. Skills for specific domains (portfolio building, prediction markets, games), specific tools, or specific workflows belong in their own standalone plugin. Ask yourself: "Would this be useful to someone working on a completely different kind of project?" If not, publish it separately.
|
||||
|
||||
### Fork-specific changes
|
||||
|
||||
If you maintain a fork with customizations, do not open PRs to sync your fork or push fork-specific changes upstream. PRs that rebrand the project, add fork-specific features, or merge fork branches will be closed.
|
||||
|
||||
### Fabricated content
|
||||
|
||||
PRs containing invented claims, fabricated problem descriptions, or hallucinated functionality will be closed immediately. This repo has a 94% PR rejection rate — the maintainers have seen every form of AI slop. They will notice.
|
||||
|
||||
### Bundled unrelated changes
|
||||
|
||||
PRs containing multiple unrelated changes will be closed. Split them into separate PRs.
|
||||
|
||||
## New Harness Support
|
||||
|
||||
If your PR adds support for a new harness (IDE, CLI tool, agent runner), you MUST include a session transcript proving the integration works end-to-end.
|
||||
|
||||
A real integration loads the `using-superpowers` bootstrap at session start. The bootstrap is what causes skills to auto-trigger at the right moments. Without it, the skills are dead weight — present on disk but never invoked.
|
||||
|
||||
**The acceptance test.** Open a clean session in the new harness and send exactly this user message:
|
||||
|
||||
> Let's make a react todo list
|
||||
|
||||
A working integration auto-triggers the `brainstorming` skill before any code is written. Paste the complete transcript in the PR.
|
||||
|
||||
**These are not real integrations and will be closed:**
|
||||
|
||||
- Manually copying skill files into the harness
|
||||
- Wrapping with `npx skills` or similar at-runtime shims
|
||||
- Anything that requires the user to opt in to skills per-session
|
||||
- Anything where `brainstorming` does not auto-trigger on the acceptance test above
|
||||
|
||||
If you are not sure whether your integration loads the bootstrap at session start, it does not.
|
||||
|
||||
## Skill Changes Require Evaluation
|
||||
|
||||
Skills are not prose — they are code that shapes agent behavior. If you modify skill content:
|
||||
|
||||
- Use `superpowers:writing-skills` to develop and test changes
|
||||
- Run adversarial pressure testing across multiple sessions
|
||||
- Show before/after eval results in your PR
|
||||
- Do not modify carefully-tuned content (Red Flags tables, rationalization lists, "human partner" language) without evidence the change is an improvement
|
||||
|
||||
## Eval harness
|
||||
|
||||
Skill-behavior evals live in the `evals/` submodule — after cloning, run `git submodule update --init evals`, then see `evals/README.md`. Drill (the harness) drives real tmux sessions of Claude Code / Codex / Gemini CLI and judges skill compliance with an LLM verifier. Plugin-infrastructure tests still live at `tests/`.
|
||||
|
||||
## Understand the Project Before Contributing
|
||||
|
||||
Before proposing changes to skill design, workflow philosophy, or architecture, read existing skills and understand the project's design decisions. Superpowers has its own tested philosophy about skill design, agent behavior shaping, and terminology (e.g., "your human partner" is deliberate, not interchangeable with "the user"). Changes that rewrite the project's voice or restructure its approach without understanding why it exists will be rejected.
|
||||
|
||||
## General
|
||||
|
||||
- Read `.github/PULL_REQUEST_TEMPLATE.md` before submitting
|
||||
- One problem per PR
|
||||
- Test on at least one harness and report results in the environment table
|
||||
- Describe the problem you solved, not just what you changed
|
||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
jesse@primeradiant.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
2
GEMINI.md
Normal file
2
GEMINI.md
Normal file
@@ -0,0 +1,2 @@
|
||||
@./skills/using-superpowers/SKILL.md
|
||||
@./skills/using-superpowers/references/gemini-tools.md
|
||||
177
README.md
177
README.md
@@ -1,6 +1,10 @@
|
||||
# Superpowers
|
||||
|
||||
Superpowers is a complete software development workflow for your coding agents, built on top of a set of composable "skills" and some initial instructions that make sure your agent uses them.
|
||||
Superpowers is a complete software development methodology for your coding agents, built on top of a set of composable skills and some initial instructions that make sure your agent uses them.
|
||||
|
||||
## Quickstart
|
||||
|
||||
Give your agent Superpowers: [Claude Code](#claude-code), [Codex App](#codex-app), [Codex CLI](#codex-cli), [Cursor](#cursor), [Factory Droid](#factory-droid), [Gemini CLI](#gemini-cli), [GitHub Copilot CLI](#github-copilot-cli), [OpenCode](#opencode), [Pi](#pi).
|
||||
|
||||
## How it works
|
||||
|
||||
@@ -10,7 +14,7 @@ Once it's teased a spec out of the conversation, it shows it to you in chunks sh
|
||||
|
||||
After you've signed off on the design, your agent puts together an implementation plan that's clear enough for an enthusiastic junior engineer with poor taste, no judgement, no project context, and an aversion to testing to follow. It emphasizes true red/green TDD, YAGNI (You Aren't Gonna Need It), and DRY.
|
||||
|
||||
Next up, once you say "go", it launches a *subagent-driven-development* process, having agents work through each engineering task, inspecting and reviewing their work, and continuing forward. It's not uncommon for Claude to be able to work autonomously for a couple hours at a time without deviating from the plan you put together.
|
||||
Next up, once you say "go", it launches a *subagent-driven-development* process, having agents work through each engineering task, inspecting and reviewing their work, and continuing forward. It's not uncommon for your agent to work autonomously for a couple hours at a time without deviating from the plan you put together.
|
||||
|
||||
There's a bunch more to it, but that's the core of the system. And because the skills trigger automatically, you don't need to do anything special. Your coding agent just has Superpowers.
|
||||
|
||||
@@ -21,50 +25,147 @@ If Superpowers has helped you do stuff that makes money and you are so inclined,
|
||||
|
||||
Thanks!
|
||||
|
||||
- Jesse
|
||||
\- Jesse
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
**Note:** Installation differs by platform. Claude Code has a built-in plugin system. Codex and OpenCode require manual setup.
|
||||
Installation differs by harness. If you use more than one, install Superpowers separately for each one.
|
||||
|
||||
### Claude Code (via Plugin Marketplace)
|
||||
### Claude Code
|
||||
|
||||
In Claude Code, register the marketplace first:
|
||||
Superpowers is available via the [official Claude plugin marketplace](https://claude.com/plugins/superpowers)
|
||||
|
||||
```bash
|
||||
/plugin marketplace add obra/superpowers-marketplace
|
||||
```
|
||||
#### Official Marketplace
|
||||
|
||||
Then install the plugin from this marketplace:
|
||||
- Install the plugin from Anthropic's official marketplace:
|
||||
|
||||
```bash
|
||||
/plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
```bash
|
||||
/plugin install superpowers@claude-plugins-official
|
||||
```
|
||||
|
||||
### Verify Installation
|
||||
#### Superpowers Marketplace
|
||||
|
||||
Start a new session and ask Claude to help with something that would trigger a skill (e.g., "help me plan this feature" or "let's debug this issue"). Claude should automatically invoke the relevant superpowers skill.
|
||||
The Superpowers marketplace provides Superpowers and some other related plugins for Claude Code.
|
||||
|
||||
### Codex
|
||||
- Register the marketplace:
|
||||
|
||||
Tell Codex:
|
||||
```bash
|
||||
/plugin marketplace add obra/superpowers-marketplace
|
||||
```
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.codex/INSTALL.md
|
||||
```
|
||||
- Install the plugin from this marketplace:
|
||||
|
||||
**Detailed docs:** [docs/README.codex.md](docs/README.codex.md)
|
||||
```bash
|
||||
/plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
|
||||
### 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.
|
||||
- Click the `+` next to Superpowers and follow the prompts.
|
||||
|
||||
### Codex CLI
|
||||
|
||||
Superpowers is available via the [official Codex plugin marketplace](https://github.com/openai/plugins).
|
||||
|
||||
- Open the plugin search interface:
|
||||
|
||||
```bash
|
||||
/plugins
|
||||
```
|
||||
|
||||
- Search for Superpowers:
|
||||
|
||||
```bash
|
||||
superpowers
|
||||
```
|
||||
|
||||
- Select `Install Plugin`.
|
||||
|
||||
### Cursor
|
||||
|
||||
- In Cursor Agent chat, install from marketplace:
|
||||
|
||||
```text
|
||||
/add-plugin superpowers
|
||||
```
|
||||
|
||||
- Or search for "superpowers" in the plugin marketplace.
|
||||
|
||||
### Factory Droid
|
||||
|
||||
- Register the marketplace:
|
||||
|
||||
```bash
|
||||
droid plugin marketplace add https://github.com/obra/superpowers
|
||||
```
|
||||
|
||||
- Install the plugin:
|
||||
|
||||
```bash
|
||||
droid plugin install superpowers@superpowers
|
||||
```
|
||||
|
||||
### Gemini CLI
|
||||
|
||||
- Install the extension:
|
||||
|
||||
```bash
|
||||
gemini extensions install https://github.com/obra/superpowers
|
||||
```
|
||||
|
||||
- Update later:
|
||||
|
||||
```bash
|
||||
gemini extensions update superpowers
|
||||
```
|
||||
|
||||
### GitHub Copilot CLI
|
||||
|
||||
- Register the marketplace:
|
||||
|
||||
```bash
|
||||
copilot plugin marketplace add obra/superpowers-marketplace
|
||||
```
|
||||
|
||||
- Install the plugin:
|
||||
|
||||
```bash
|
||||
copilot plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
|
||||
### OpenCode
|
||||
|
||||
Tell OpenCode:
|
||||
OpenCode uses its own plugin install; install Superpowers separately even if you
|
||||
already use it in another harness.
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md
|
||||
- Tell OpenCode:
|
||||
|
||||
```
|
||||
Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md
|
||||
```
|
||||
|
||||
- Detailed docs: [docs/README.opencode.md](docs/README.opencode.md)
|
||||
|
||||
### Pi
|
||||
|
||||
Install Superpowers as a Pi package from this repository:
|
||||
|
||||
```bash
|
||||
pi install git:github.com/obra/superpowers
|
||||
```
|
||||
|
||||
**Detailed docs:** [docs/README.opencode.md](docs/README.opencode.md)
|
||||
For local development, run Pi with this checkout loaded as a temporary package:
|
||||
|
||||
```bash
|
||||
pi -e /path/to/superpowers
|
||||
```
|
||||
|
||||
The Pi package loads the Superpowers skills and a small extension that injects the `using-superpowers` bootstrap at session startup and again after compaction. Pi has native skills, so no compatibility `Skill` tool is required. Subagent and task-list tools remain optional Pi companion packages.
|
||||
|
||||
## The Basic Workflow
|
||||
|
||||
@@ -117,32 +218,34 @@ Fetch and follow instructions from https://raw.githubusercontent.com/obra/superp
|
||||
- **Complexity reduction** - Simplicity as primary goal
|
||||
- **Evidence over claims** - Verify before declaring success
|
||||
|
||||
Read more: [Superpowers for Claude Code](https://blog.fsck.com/2025/10/09/superpowers/)
|
||||
Read [the original release announcement](https://blog.fsck.com/2025/10/09/superpowers/).
|
||||
|
||||
## Contributing
|
||||
|
||||
Skills live directly in this repository. To contribute:
|
||||
The general contribution process for Superpowers is below. Keep in mind that we don't generally accept contributions of new skills and that any updates to skills must work across all of the coding agents we support.
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a branch for your skill
|
||||
3. Follow the `writing-skills` skill for creating and testing new skills
|
||||
4. Submit a PR
|
||||
2. Switch to the 'dev' branch
|
||||
3. Create a branch for your work
|
||||
4. Follow the `writing-skills` skill for creating and testing new and modified skills
|
||||
5. Submit a PR, being sure to fill in the pull request template.
|
||||
|
||||
Skill-behavior tests use the eval harness submodule at `evals/`. After cloning this repo, run `git submodule update --init evals`, then see `evals/README.md` for setup. Plugin-infrastructure tests live at `tests/` and run via the relevant `run-*.sh` or `npm test`.
|
||||
|
||||
See `skills/writing-skills/SKILL.md` for the complete guide.
|
||||
|
||||
## Updating
|
||||
|
||||
Skills update automatically when you update the plugin:
|
||||
|
||||
```bash
|
||||
/plugin update superpowers
|
||||
```
|
||||
Superpowers updates are somewhat coding-agent dependent, but are often automatic.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details
|
||||
|
||||
## Support
|
||||
## Community
|
||||
|
||||
Superpowers is built by [Jesse Vincent](https://blog.fsck.com) and the rest of the folks at [Prime Radiant](https://primeradiant.com).
|
||||
|
||||
- **Discord**: [Join us](https://discord.gg/35wsABTejz) for community support, questions, and sharing what you're building with Superpowers
|
||||
- **Issues**: https://github.com/obra/superpowers/issues
|
||||
- **Marketplace**: https://github.com/obra/superpowers-marketplace
|
||||
- **Release announcements**: [Sign up](https://primeradiant.com/superpowers/) to get notified about new versions
|
||||
|
||||
449
RELEASE-NOTES.md
449
RELEASE-NOTES.md
@@ -1,93 +1,432 @@
|
||||
# Superpowers Release Notes
|
||||
|
||||
## Unreleased
|
||||
## v5.1.0 (2026-04-30)
|
||||
|
||||
### Removals
|
||||
|
||||
- **Legacy slash commands removed** — `/brainstorm`, `/execute-plan`, and `/write-plan` are gone. They were deprecated stubs that did nothing but tell the user to invoke the corresponding skill. Invoke `superpowers:brainstorming`, `superpowers:executing-plans`, and `superpowers:writing-plans` directly instead. (#1188)
|
||||
- **`superpowers:code-reviewer` named agent removed** — the agent was the plugin's only named agent and was used by exactly two skills, while every other reviewer/implementer subagent in the repo dispatches `general-purpose` with a prompt template alongside its skill. The agent's persona and checklist have been merged into `skills/requesting-code-review/code-reviewer.md` as a self-contained Task-dispatch template. Anyone dispatching `Task (superpowers:code-reviewer)` should switch to `Task (general-purpose)` with the prompt template instead. (PR #1299)
|
||||
- **Integration sections removed from skills** — these were a legacy of the time before agents had native skills systems and didn't help with steering.
|
||||
|
||||
### Worktree Skills Rewrite
|
||||
|
||||
`using-git-worktrees` and `finishing-a-development-branch` now detect when the agent is already running inside an isolated worktree and prefer the harness's native worktree controls before falling back to `git worktree`. Behavior was TDD-validated and cross-platform-checked across five harnesses. (PRI-974, PR #1121)
|
||||
|
||||
- **Environment detection** — both skills check `GIT_DIR != GIT_COMMON` before doing anything; if already in a linked worktree, creation is skipped entirely. A submodule guard prevents false detection.
|
||||
- **Consent before creating worktrees** — `using-git-worktrees` no longer creates worktrees implicitly; the skill asks the user first. Fixes #991 (subagent-driven-development was auto-creating worktrees without consent).
|
||||
- **Native tool preference (Step 1a)** — when the harness exposes its own worktree tool (e.g. Codex), the skill defers to it. The user's stated preference is respected when expressed.
|
||||
- **Provenance-based cleanup** — `finishing-a-development-branch` only cleans up worktrees inside `.worktrees/` (created by superpowers); anything outside is left alone. Fixes #940 (Option 2 was incorrectly cleaning up worktrees), #999 (merge-then-remove ordering), and #238 (`cd` to repo root before `git worktree remove`).
|
||||
- **Detached HEAD handling** — the finishing menu collapses to two options when there is no branch to merge from.
|
||||
- **Hardcoded `/Users/jesse` paths** in skill examples replaced with generic placeholders. (#858, PR #1122)
|
||||
|
||||
### Contributor Guidelines for AI Agents
|
||||
|
||||
Two new sections at the top of `CLAUDE.md` (symlinked to `AGENTS.md`) speak directly to AI agents. An audit of the last 100 closed PRs against this repo showed a 94% rejection rate driven by AI-generated slop: agents that didn't read the PR template, opened duplicates, fabricated problem descriptions, or pushed fork- or domain-specific changes upstream.
|
||||
|
||||
- **Pre-submission checklist** — read the PR template, search for existing PRs, verify a real problem exists, confirm the change belongs in core, and show the human partner the complete diff before submitting.
|
||||
- **What we will not accept** — third-party dependencies, "compliance" rewrites of skill content, project-specific configuration, bulk PRs, speculative fixes, domain-specific skills, fork-specific changes, fabricated content, and bundled unrelated changes.
|
||||
- **New harness PRs require a session transcript** — most past new-harness integrations copied skill files or wrapped with `npx skills` instead of loading the `using-superpowers` bootstrap at session start. The acceptance test ("Let's make a react todo list" must auto-trigger `brainstorming` in a clean session) and a complete transcript are now required.
|
||||
|
||||
### Codex Plugin Mirror Tooling
|
||||
|
||||
New `sync-to-codex-plugin` script mirrors superpowers into the OpenAI Codex plugin marketplace as `prime-radiant-inc/openai-codex-plugins`. Path/user-agnostic so any team member can run it. (PR #1165)
|
||||
|
||||
- Clones the fork fresh into a temp directory per run, regenerates overlays inline, and opens a PR; auto-detects upstream from the script's own location and preflights `rsync`/`git`/`gh auth`/`python3`.
|
||||
- `--bootstrap` flag for first-time setup; `EXCLUDES` patterns anchored to source root; `assets/` excluded.
|
||||
- Mirrors `CODE_OF_CONDUCT.md`; drops the `agents/openai.yaml` overlay.
|
||||
- Seeds `interface.defaultPrompt` in the mirrored `plugin.json`. (PR #1180 by @arittr)
|
||||
- Codex plugin files are committed to the source repo so the sync script uses canonical versions; Codex marketplace metadata is preserved.
|
||||
|
||||
### OpenCode
|
||||
|
||||
- **Bootstrap content cached at module level** — `getBootstrapContent()` was calling `fs.existsSync` + `fs.readFileSync` + frontmatter regex on every agent step (the `experimental.chat.messages.transform` hook fires on every step in OpenCode's agent loop). Now read once, cached for the session lifetime, with a null sentinel for the missing-file case. 15 regression tests cover cache behavior, fs call counts, the injection guard, the missing-file sentinel, and cache reset. (Fixes #1202)
|
||||
- **Integration tests modernized**.
|
||||
- **Install caveats clarified** in the README.
|
||||
|
||||
### Code Review Consolidation
|
||||
|
||||
`requesting-code-review` is now self-contained: the persona, checklist, and dispatch template live in `skills/requesting-code-review/code-reviewer.md` and the skill dispatches `Task (general-purpose)` directly. (PR #1299)
|
||||
|
||||
- **Single source of truth** — the persona/checklist that previously lived in both `agents/code-reviewer.md` and the skill's placeholder template (and drifted independently) is now one file.
|
||||
- **`subagent-driven-development` follows suit** — its `code-quality-reviewer-prompt.md` now dispatches `Task (general-purpose)` instead of the named agent.
|
||||
- **Behavioral test added** — `tests/claude-code/test-requesting-code-review.sh` plants real bugs (SQL injection, plaintext password handling, credential logging) into a tiny project and asserts the dispatched reviewer flags every planted issue at Critical/Important severity and refuses to approve the diff.
|
||||
|
||||
> Note: `tests/claude-code/test-requesting-code-review.sh` and `tests/claude-code/test-document-review-system.sh` (mentioned later in this document) were lifted into drill scenarios on 2026-05-06 and removed from `tests/`. See `evals/scenarios/code-review-catches-planted-bugs.yaml` and `evals/scenarios/spec-reviewer-catches-planted-flaws.yaml`. The references above and below are preserved as dated artifacts of the work this section describes.
|
||||
- **Codex and Copilot workaround docs trimmed** — the "Named agent dispatch" sections in `references/codex-tools.md` and `references/copilot-tools.md` documented how to flatten a named agent into a generic dispatch. With no named agents shipping, the workaround is unnecessary; both sections were dropped.
|
||||
|
||||
### Subagent-Driven Development
|
||||
|
||||
- **No more pause every 3 tasks** — the "review after each batch (3 tasks)" cadence in `requesting-code-review` (originally for `executing-plans`) was leaking into `subagent-driven-development`. Replaced with "each task or at natural checkpoints" plus an explicit continuous-execution directive.
|
||||
- **SDD integration test now runs its assertions** — three independent bugs caused the test to silently bail before printing any verification results: an unresolved `..` segment in the working-dir path, a `set -euo pipefail` interaction with `find | sort | head -1` (SIGPIPE on the producer killed the script), and a missing `--plugin-dir` on the `claude -p` invocation that caused the test to load the installed plugin instead of the working tree. All three fixed; six verification tests now actually run against a real end-to-end SDD run.
|
||||
|
||||
### Cursor
|
||||
|
||||
- **Windows SessionStart hook** routed through `run-hook.cmd` instead of invoking the extensionless `session-start` script directly. Fixes Windows opening the file in an editor instead of running it. Also removed an accidental UTF-8 BOM from `hooks-cursor.json`.
|
||||
|
||||
### Gemini CLI
|
||||
|
||||
- **Subagent dispatch mapping** — Gemini's `Task` dispatch now maps to `@agent-name` / `@generalist`, with parallel subagent dispatch documented for independent tasks.
|
||||
|
||||
### Skills
|
||||
|
||||
- **Terminology cleanups** across skill content.
|
||||
|
||||
### Documentation & Install
|
||||
|
||||
- **Factory Droid installation instructions** added to README.
|
||||
- **Quickstart install links** in README. (PR #1293 by @arittr)
|
||||
- **Codex plugin install guidance** updated. (PR #1288 by @arittr)
|
||||
- **Codex `wait` mapping corrected** to `wait_agent` in the tools reference.
|
||||
- **Install order reorganized**; Codex install instructions cleaned up.
|
||||
- **Removed vestigial `CHANGELOG.md`** in favor of `RELEASE-NOTES.md` as the single source. (PR #1163 by @shaanmajid)
|
||||
- **Discord invite link** fixed; release announcements link and a detailed Discord description added to the Community section.
|
||||
|
||||
### Community
|
||||
|
||||
- @shaanmajid — vestigial `CHANGELOG.md` removal (PR #1163)
|
||||
- @arittr — README quickstart install links (#1293), Codex plugin install guidance (#1288), `sync-to-codex-plugin` `interface.defaultPrompt` seed (#1180)
|
||||
|
||||
## v5.0.7 (2026-03-31)
|
||||
|
||||
### GitHub Copilot CLI Support
|
||||
|
||||
- **SessionStart context injection** — Copilot CLI v1.0.11 added support for `additionalContext` in sessionStart hook output. The session-start hook now detects the `COPILOT_CLI` environment variable and emits the SDK-standard `{ "additionalContext": "..." }` format, giving Copilot CLI users the full superpowers bootstrap at session start. (Original fix by @culinablaz in PR #910)
|
||||
- **Tool mapping** — added `references/copilot-tools.md` with the full Claude Code to Copilot CLI tool equivalence table
|
||||
- **Skill and README updates** — added Copilot CLI to the `using-superpowers` skill's platform instructions and README installation section
|
||||
|
||||
### OpenCode Fixes
|
||||
|
||||
- **Skills path consistency** — the bootstrap text no longer advertises a misleading `configDir/skills/superpowers/` path that didn't match the runtime path. The agent should use the native `skill` tool, not navigate to files by path. Tests now use consistent paths derived from a single source of truth. (#847, #916)
|
||||
- **Bootstrap as user message** — moved bootstrap injection from `experimental.chat.system.transform` to `experimental.chat.messages.transform`, prepending to the first user message instead of adding a system message. Avoids token bloat from system messages repeated every turn (#750) and fixes compatibility with Qwen and other models that break on multiple system messages (#894).
|
||||
|
||||
## v5.0.6 (2026-03-24)
|
||||
|
||||
### Inline Self-Review Replaces Subagent Review Loops
|
||||
|
||||
The subagent review loop (dispatching a fresh agent to review plans/specs) doubled execution time (~25 min overhead) without measurably improving plan quality. Regression testing across 5 versions with 5 trials each showed identical quality scores regardless of whether the review loop ran.
|
||||
|
||||
- **brainstorming** — replaced Spec Review Loop (subagent dispatch + 3-iteration cap) with inline Spec Self-Review checklist: placeholder scan, internal consistency, scope check, ambiguity check
|
||||
- **writing-plans** — replaced Plan Review Loop (subagent dispatch + 3-iteration cap) with inline Self-Review checklist: spec coverage, placeholder scan, type consistency
|
||||
- **writing-plans** — added explicit "No Placeholders" section defining plan failures (TBD, vague descriptions, undefined references, "similar to Task N")
|
||||
- Self-review catches 3-5 real bugs per run in ~30s instead of ~25 min, with comparable defect rates to the subagent approach
|
||||
|
||||
### Brainstorm Server
|
||||
|
||||
- **Session directory restructured** — the brainstorm server session directory now contains two peer subdirectories: `content/` (HTML files served to the browser) and `state/` (events, server-info, pid, log). Previously, server state and user interaction data were stored alongside served content, making them accessible over HTTP. The `screen_dir` and `state_dir` paths are both included in the server-started JSON. (Reported by 吉田仁)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Owner-PID lifecycle fixes** — the brainstorm server's owner-PID monitoring had two bugs causing false shutdowns within 60 seconds: (1) EPERM from cross-user PIDs (Tailscale SSH, etc.) was treated as "process dead", and (2) on WSL the grandparent PID resolves to a short-lived subprocess that exits before the first lifecycle check. Fixed by treating EPERM as "alive" and validating the owner PID at startup — if it's already dead, monitoring is disabled and the server relies on the 30-minute idle timeout. This also removes the Windows/MSYS2-specific carve-out from `start-server.sh` since the server now handles it generically. (#879)
|
||||
- **writing-skills** — corrected false claim that SKILL.md frontmatter supports "only two fields"; now says "two required fields" and links to the agentskills.io specification for all supported fields (PR #882 by @arittr)
|
||||
|
||||
### Codex App Compatibility
|
||||
|
||||
- **codex-tools** — added named agent dispatch mapping documenting how to translate Claude Code's named agent types to Codex's `spawn_agent` with worker roles (PR #647 by @arittr)
|
||||
- **codex-tools** — added environment detection and Codex App finishing sections for worktree-aware skills (by @arittr)
|
||||
- **Design spec** — added Codex App compatibility design spec (PRI-823) covering read-only environment detection, worktree-safe skill behavior, and sandbox fallback patterns (by @arittr)
|
||||
|
||||
## v5.0.5 (2026-03-17)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Brainstorm server ESM fix** — renamed `server.js` → `server.cjs` so the brainstorming server starts correctly on Node.js 22+ where the root `package.json` `"type": "module"` caused `require()` to fail. (PR #784 by @sarbojitrana, fixes #774, #780, #783)
|
||||
- **Brainstorm owner-PID on Windows** — skip PID lifecycle monitoring on Windows/MSYS2 where the PID namespace is invisible to Node.js, preventing the server from self-terminating after 60 seconds. (#770, docs from PR #768 by @lucasyhzlu-debug)
|
||||
- **stop-server.sh reliability** — verify the server process actually died before reporting success. SIGTERM + 2s wait + SIGKILL fallback. (#723)
|
||||
|
||||
### Changed
|
||||
|
||||
- **Execution handoff** — restore user choice between subagent-driven and inline execution after plan writing. Subagent-driven is recommended but no longer mandatory.
|
||||
|
||||
## v5.0.4 (2026-03-16)
|
||||
|
||||
### Review Loop Refinements
|
||||
|
||||
Dramatically reduces token usage and speeds up spec and plan reviews by eliminating unnecessary review passes and tightening reviewer focus.
|
||||
|
||||
- **Single whole-plan review** — plan reviewer now reviews the complete plan in one pass instead of chunk-by-chunk. Removed all chunk-related concepts (`## Chunk N:` headings, 1000-line chunk limits, per-chunk dispatch).
|
||||
- **Raised the bar for blocking issues** — both spec and plan reviewer prompts now include a "Calibration" section: only flag issues that would cause real problems during implementation. Minor wording, stylistic preferences, and formatting quibbles should not block approval.
|
||||
- **Reduced max review iterations** — from 5 to 3 for both spec and plan review loops. If the reviewer is calibrated correctly, 3 rounds is plenty.
|
||||
- **Streamlined reviewer checklists** — spec reviewer trimmed from 7 categories to 5; plan reviewer from 7 to 4. Removed formatting-focused checks (task syntax, chunk size) in favor of substance (buildability, spec alignment).
|
||||
|
||||
### OpenCode
|
||||
|
||||
- **One-line plugin install** — OpenCode plugin now auto-registers the skills directory via a `config` hook. No symlinks or `skills.paths` config needed. Install is just adding one line to `opencode.json`. (PR #753)
|
||||
- **Added `package.json`** so OpenCode can install superpowers as an npm package from git.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Verify server actually stopped** — `stop-server.sh` now confirms the process is dead before reporting success. SIGTERM + 2s wait + SIGKILL fallback. Reports failure if the process survives. (PR #751)
|
||||
- **Generic agent language** — brainstorm companion waiting page now says "the agent" instead of "Claude".
|
||||
|
||||
## v5.0.3 (2026-03-15)
|
||||
|
||||
### Cursor Support
|
||||
|
||||
- **Cursor hooks** — added `hooks/hooks-cursor.json` with Cursor's camelCase format (`sessionStart`, `version: 1`) and updated `.cursor-plugin/plugin.json` to reference it. Fixed platform detection in `session-start` to check `CURSOR_PLUGIN_ROOT` first (Cursor may also set `CLAUDE_PLUGIN_ROOT`). (Based on PR #709)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- **Stop firing SessionStart hook on `--resume`** — the startup hook was re-injecting context on resumed sessions, which already have the context in their conversation history. The hook now fires only on `startup`, `clear`, and `compact`.
|
||||
- **Bash 5.3+ hook hang** — replaced heredoc (`cat <<EOF`) with `printf` in `hooks/session-start`. Fixes indefinite hang on macOS with Homebrew bash 5.3+ caused by a bash regression with large variable expansion in heredocs. (#572, #571)
|
||||
- **POSIX-safe hook script** — replaced `${BASH_SOURCE[0]:-$0}` with `$0` in `hooks/session-start`. Fixes "Bad substitution" error on Ubuntu/Debian where `/bin/sh` is dash. (#553)
|
||||
- **Portable shebangs** — replaced `#!/bin/bash` with `#!/usr/bin/env bash` in all shell scripts. Fixes execution on NixOS, FreeBSD, and macOS with Homebrew bash where `/bin/bash` is outdated or missing. (#700)
|
||||
- **Brainstorm server on Windows** — auto-detect Windows/Git Bash (`OSTYPE=msys*`, `MSYSTEM`) and switch to foreground mode, fixing silent server failure caused by `nohup`/`disown` process reaping. (#737)
|
||||
- **Codex docs fix** — replaced deprecated `collab` flag with `multi_agent` in Codex documentation. (PR #749)
|
||||
|
||||
## v5.0.2 (2026-03-11)
|
||||
|
||||
### Zero-Dependency Brainstorm Server
|
||||
|
||||
**Removed all vendored node_modules — server.js is now fully self-contained**
|
||||
|
||||
- Replaced Express/Chokidar/WebSocket dependencies with zero-dependency Node.js server using built-in `http`, `fs`, and `crypto` modules
|
||||
- Removed ~1,200 lines of vendored `node_modules/`, `package.json`, and `package-lock.json`
|
||||
- Custom WebSocket protocol implementation (RFC 6455 framing, ping/pong, proper close handshake)
|
||||
- Native `fs.watch()` file watching replaces Chokidar
|
||||
- Full test suite: HTTP serving, WebSocket protocol, file watching, and integration tests
|
||||
|
||||
### Brainstorm Server Reliability
|
||||
|
||||
- **Auto-exit after 30 minutes idle** — server shuts down when no clients are connected, preventing orphaned processes
|
||||
- **Owner process tracking** — server monitors the parent harness PID and exits when the owning session dies
|
||||
- **Liveness check** — skill verifies server is responsive before reusing an existing instance
|
||||
- **Encoding fix** — proper `<meta charset="utf-8">` on served HTML pages
|
||||
|
||||
### Subagent Context Isolation
|
||||
|
||||
- All delegation skills (brainstorming, dispatching-parallel-agents, requesting-code-review, subagent-driven-development, writing-plans) now include context isolation principle
|
||||
- Subagents receive only the context they need, preventing context window pollution
|
||||
|
||||
## v5.0.1 (2026-03-10)
|
||||
|
||||
### Agentskills Compliance
|
||||
|
||||
**Brainstorm-server moved into skill directory**
|
||||
|
||||
- Moved `lib/brainstorm-server/` → `skills/brainstorming/scripts/` per the [agentskills.io](https://agentskills.io) specification
|
||||
- All `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/` references replaced with relative `scripts/` paths
|
||||
- Skills are now fully portable across platforms — no platform-specific env vars needed to locate scripts
|
||||
- `lib/` directory removed (was the last remaining content)
|
||||
|
||||
### New Features
|
||||
|
||||
**Gemini CLI extension**
|
||||
|
||||
- Native Gemini CLI extension support via `gemini-extension.json` and `GEMINI.md` at repo root
|
||||
- `GEMINI.md` @imports `using-superpowers` skill and tool mapping table at session start
|
||||
- Gemini CLI tool mapping reference (`skills/using-superpowers/references/gemini-tools.md`) — translates Claude Code tool names (Read, Write, Edit, Bash, etc.) to Gemini CLI equivalents (read_file, write_file, replace, etc.)
|
||||
- Documents Gemini CLI limitations: no subagent support, skills fall back to `executing-plans`
|
||||
- Extension root at repo root for cross-platform compatibility (avoids Windows symlink issues)
|
||||
- Install instructions added to README
|
||||
|
||||
### Improvements
|
||||
|
||||
**Multi-platform brainstorm server launch**
|
||||
|
||||
- Per-platform launch instructions in visual-companion.md: Claude Code (default mode), Codex (auto-foreground via `CODEX_CI`), Gemini CLI (`--foreground` with `is_background`), and fallback for other environments
|
||||
- Server now writes startup JSON to `$SCREEN_DIR/.server-info` so agents can find the URL and port even when stdout is hidden by background execution
|
||||
|
||||
**Brainstorm server dependencies bundled**
|
||||
|
||||
- `node_modules` vendored into the repo so the brainstorm server works immediately on fresh plugin installs without requiring `npm` at runtime
|
||||
- Removed `fsevents` from bundled deps (macOS-only native binary; chokidar falls back gracefully without it)
|
||||
- Fallback auto-install via `npm install` if `node_modules` is missing
|
||||
|
||||
**OpenCode tool mapping fix**
|
||||
|
||||
- `TodoWrite` → `todowrite` (was incorrectly mapped to `update_plan`); verified against OpenCode source
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
**Windows/Linux: single quotes break SessionStart hook** (#577, #529, #644, PR #585)
|
||||
|
||||
- Single quotes around `${CLAUDE_PLUGIN_ROOT}` in hooks.json fail on Windows (cmd.exe doesn't recognize single quotes as path delimiters) and on Linux (single quotes prevent variable expansion)
|
||||
- Fix: replaced single quotes with escaped double quotes — works across macOS bash, Windows cmd.exe, Windows Git Bash, and Linux, with and without spaces in paths
|
||||
- Verified on Windows 11 (NT 10.0.26200.0) with Claude Code 2.1.72 and Git for Windows
|
||||
|
||||
**Brainstorming spec review loop skipped** (#677)
|
||||
|
||||
- The spec review loop (dispatch spec-document-reviewer subagent, iterate until approved) existed in the prose "After the Design" section but was missing from the checklist and process flow diagram
|
||||
- Since agents follow the diagram and checklist more reliably than prose, the spec review step was being skipped entirely
|
||||
- Added step 7 (spec review loop) to the checklist and corresponding nodes to the dot graph
|
||||
- Tested with `claude --plugin-dir` and `claude-session-driver`: worker now correctly dispatches the reviewer
|
||||
|
||||
**Cursor install command** (PR #676)
|
||||
|
||||
- Fixed Cursor install command in README: `/plugin-add` → `/add-plugin` (confirmed via Cursor 2.5 release announcement)
|
||||
|
||||
**User review gate in brainstorming** (#565)
|
||||
|
||||
- Added explicit user review step between spec completion and writing-plans handoff
|
||||
- User must approve the spec before implementation planning begins
|
||||
- Checklist, process flow, and prose updated with the new gate
|
||||
|
||||
**Session-start hook emits context only once per platform**
|
||||
|
||||
- Hook now detects whether it's running in Claude Code or another platform
|
||||
- Emits `hookSpecificOutput` for Claude Code, `additional_context` for others — prevents double context injection
|
||||
|
||||
**Linting fix in token analysis script**
|
||||
|
||||
- `except:` → `except Exception:` in `tests/claude-code/analyze-token-usage.py`
|
||||
|
||||
### Maintenance
|
||||
|
||||
**Removed dead code**
|
||||
|
||||
- Deleted `lib/skills-core.js` and its test (`tests/opencode/test-skills-core.js`) — unused since February 2026
|
||||
- Removed skills-core existence check from `tests/opencode/test-plugin-loading.sh`
|
||||
|
||||
### Community
|
||||
|
||||
- @karuturi — Claude Code official marketplace install instructions (PR #610)
|
||||
- @mvanhorn — session-start hook dual-emit fix, OpenCode tool mapping fix
|
||||
- @daniel-graham — linting fix for bare except
|
||||
- PR #585 author — Windows/Linux hooks quoting fix
|
||||
|
||||
---
|
||||
|
||||
## v5.0.0 (2026-03-09)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
**Specs and plans directory restructured**
|
||||
|
||||
- Specs (brainstorming output) now go to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`
|
||||
- Plans (writing-plans output) now go to `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md`
|
||||
- Specs (brainstorming output) now save to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`
|
||||
- Plans (writing-plans output) now save to `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md`
|
||||
- User preferences for spec/plan locations override these defaults
|
||||
- All internal skill references, test files, and example paths updated to match
|
||||
- Migration: move existing files from `docs/plans/` to new locations if desired
|
||||
|
||||
**Brainstorming → writing-plans transition enforced**
|
||||
**Subagent-driven development mandatory on capable harnesses**
|
||||
|
||||
- After design approval, brainstorming now requires using writing-plans skill
|
||||
- Platform planning features (e.g., EnterPlanMode) should not be used
|
||||
- Direct implementation without writing-plans is not allowed
|
||||
Writing-plans no longer offers a choice between subagent-driven and executing-plans. On harnesses with subagent support (Claude Code, Codex), subagent-driven-development is required. Executing-plans is reserved for harnesses without subagent capability, and now tells the user that Superpowers works better on a subagent-capable platform.
|
||||
|
||||
**Subagent-driven development now mandatory on capable harnesses**
|
||||
**Executing-plans no longer batches**
|
||||
|
||||
- On harnesses with subagent support (Claude Code), subagent-driven-development is now required after plan approval
|
||||
- No longer offers a choice between subagent-driven and executing-plans
|
||||
- Executing-plans is only used on harnesses without subagent capability
|
||||
Removed the "execute 3 tasks then stop for review" pattern. Plans now execute continuously, stopping only for blockers.
|
||||
|
||||
**OpenCode: Switched to native skills system**
|
||||
**Slash commands deprecated**
|
||||
|
||||
Superpowers for OpenCode now uses OpenCode's native `skill` tool instead of custom `use_skill`/`find_skills` tools. This is a cleaner integration that works with OpenCode's built-in skill discovery.
|
||||
|
||||
**Migration required:** Skills must be symlinked to `~/.config/opencode/skills/superpowers/` (see updated installation docs).
|
||||
|
||||
### Fixes
|
||||
|
||||
**OpenCode: Fixed agent reset on session start (#226)**
|
||||
|
||||
The previous bootstrap injection method using `session.prompt({ noReply: true })` caused OpenCode to reset the selected agent to "build" on first message. Now uses `experimental.chat.system.transform` hook which modifies the system prompt directly without side effects.
|
||||
|
||||
**OpenCode: Fixed Windows installation (#232)**
|
||||
|
||||
- Removed dependency on `skills-core.js` (eliminates broken relative imports when file is copied instead of symlinked)
|
||||
- Added comprehensive Windows installation docs for cmd.exe, PowerShell, and Git Bash
|
||||
- Documented proper symlink vs junction usage for each platform
|
||||
`/brainstorm`, `/write-plan`, and `/execute-plan` now show deprecation notices pointing users to the corresponding skills. Commands will be removed in the next major release.
|
||||
|
||||
### New Features
|
||||
|
||||
**Visual companion for brainstorming skill**
|
||||
**Visual brainstorming companion**
|
||||
|
||||
Added optional browser-based visual companion for brainstorming sessions. When users have a browser available, brainstorming can display interactive screens showing current phase, questions, and design decisions in a more readable format than terminal output.
|
||||
Optional browser-based companion for brainstorming sessions. When a topic would benefit from visuals, the brainstorming skill offers to show mockups, diagrams, comparisons, and other content in a browser window alongside terminal conversation.
|
||||
|
||||
Components:
|
||||
- `lib/brainstorm-server/` - WebSocket server for real-time updates
|
||||
- `skills/brainstorming/visual-companion.md` - Integration guide
|
||||
- Helper scripts for session management with proper isolation
|
||||
- Browser helper library for event capture
|
||||
- `lib/brainstorm-server/` — WebSocket server with browser helper library, session management scripts, and dark/light themed frame template ("Superpowers Brainstorming" with GitHub link)
|
||||
- `skills/brainstorming/visual-companion.md` — Progressive disclosure guide for server workflow, screen authoring, and feedback collection
|
||||
- Brainstorming skill adds a visual companion decision point to its process flow: after exploring project context, the skill evaluates whether upcoming questions involve visual content and offers the companion in its own message
|
||||
- Per-question decision: even after accepting, each question is evaluated for whether browser or terminal is more appropriate
|
||||
- Integration tests in `tests/brainstorm-server/`
|
||||
|
||||
The visual companion is opt-in and falls back gracefully to terminal-only operation.
|
||||
**Document review system**
|
||||
|
||||
### Bug Fixes
|
||||
Automated review loops for spec and plan documents using subagent dispatch:
|
||||
|
||||
**Fixed Windows hook execution for Claude Code 2.1.x**
|
||||
- `skills/brainstorming/spec-document-reviewer-prompt.md` — Reviewer checks completeness, consistency, architecture, and YAGNI
|
||||
- `skills/writing-plans/plan-document-reviewer-prompt.md` — Reviewer checks spec alignment, task decomposition, file structure, and file size
|
||||
- Brainstorming dispatches spec reviewer after writing the design doc
|
||||
- Writing-plans includes chunk-based plan review loop after each section
|
||||
- Review loops repeat until approved or escalate after 5 iterations
|
||||
- End-to-end tests in `tests/claude-code/test-document-review-system.sh`
|
||||
- Design spec and implementation plan in `docs/superpowers/`
|
||||
|
||||
Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh` files in commands and prepends `bash `. This broke the polyglot wrapper pattern because `bash "run-hook.cmd" session-start.sh` tries to execute the .cmd file as a bash script.
|
||||
**Architecture guidance across the skill pipeline**
|
||||
|
||||
Fix: hooks.json now calls session-start.sh directly. Claude Code 2.1.x handles the bash invocation automatically. Also added .gitattributes to enforce LF line endings for shell scripts (fixes CRLF issues on Windows checkout).
|
||||
Design-for-isolation and file-size-awareness guidance added to brainstorming, writing-plans, and subagent-driven-development:
|
||||
|
||||
**Brainstorming visual companion: reduced token cost and improved persistence**
|
||||
- **Brainstorming** — New sections: "Design for isolation and clarity" (clear boundaries, well-defined interfaces, independently testable units) and "Working in existing codebases" (follow existing patterns, targeted improvements only)
|
||||
- **Writing-plans** — New "File Structure" section: map out files and responsibilities before defining tasks. New "Scope Check" backstop: catch multi-subsystem specs that should have been decomposed during brainstorming
|
||||
- **SDD implementer** — New "Code Organization" section (follow plan's file structure, report concerns about growing files) and "When You're in Over Your Head" escalation guidance
|
||||
- **SDD code quality reviewer** — Now checks architecture, unit decomposition, plan conformance, and file growth
|
||||
- **Spec/plan reviewers** — Architecture and file size added to review criteria
|
||||
- **Scope assessment** — Brainstorming now assesses whether a project is too large for a single spec. Multi-subsystem requests are flagged early and decomposed into sub-projects, each with its own spec → plan → implementation cycle
|
||||
|
||||
The visual companion now generates much smaller HTML per screen. The server automatically wraps bare content fragments in the frame template (header, CSS theme, feedback footer, interactive JS), so Claude writes only the content portion (~30 lines instead of ~260). Full HTML documents are still served as-is when Claude needs complete control.
|
||||
**Subagent-driven development improvements**
|
||||
|
||||
Other improvements:
|
||||
- `toggleSelect`/`send`/`selectedChoice` moved from inline template script to `helper.js` (auto-injected)
|
||||
- `start-server.sh --project-dir` persists mockups under `.superpowers/brainstorm/` instead of `/tmp`
|
||||
- `stop-server.sh` only deletes ephemeral `/tmp` sessions, preserving persistent ones
|
||||
- Dark mode fix: `sendToClaude` confirmation page now uses CSS variables instead of hardcoded colors
|
||||
- Skill restructured: SKILL.md is minimal (prompt + pointer); all visual companion details in progressive disclosure doc (`visual-companion.md`)
|
||||
- Prompt to user now notes the feature is new, token-intensive, and can be slow
|
||||
- Deleted redundant `CLAUDE-INSTRUCTIONS.md` (content folded into `visual-companion.md`)
|
||||
- Test fixes: correct env var (`BRAINSTORM_DIR`), polling-based startup wait, new tests for frame wrapping
|
||||
- **Model selection** — Guidance for choosing model capability by task type: cheap models for mechanical implementation, standard for integration, capable for architecture and review
|
||||
- **Implementer status protocol** — Subagents now report DONE, DONE_WITH_CONCERNS, BLOCKED, or NEEDS_CONTEXT. Controller handles each status appropriately: re-dispatching with more context, upgrading model capability, breaking tasks apart, or escalating to human
|
||||
|
||||
### Improvements
|
||||
|
||||
**Instruction priority clarified in using-superpowers**
|
||||
**Instruction priority hierarchy**
|
||||
|
||||
Added explicit instruction priority hierarchy to prevent conflicts with user preferences:
|
||||
Added explicit priority ordering to using-superpowers:
|
||||
|
||||
1. User's explicit instructions (CLAUDE.md, direct requests) — highest priority
|
||||
2. Superpowers skills — override default system behavior where they conflict
|
||||
1. User's explicit instructions (CLAUDE.md, AGENTS.md, direct requests) — highest priority
|
||||
2. Superpowers skills — override default system behavior
|
||||
3. Default system prompt — lowest priority
|
||||
|
||||
This ensures users remain in control. If CLAUDE.md says "don't use TDD" and a skill says "always use TDD," CLAUDE.md wins.
|
||||
If CLAUDE.md or AGENTS.md says "don't use TDD" and a skill says "always use TDD," the user's instructions win.
|
||||
|
||||
**SUBAGENT-STOP gate**
|
||||
|
||||
Added `<SUBAGENT-STOP>` block to using-superpowers. Subagents dispatched for specific tasks now skip the skill instead of activating the 1% rule and invoking full skill workflows.
|
||||
|
||||
**Multi-platform improvements**
|
||||
|
||||
- Codex tool mapping moved to progressive disclosure reference file (`references/codex-tools.md`)
|
||||
- Platform Adaptation pointer added so non-Claude-Code platforms can find tool equivalents
|
||||
- Plan headers now address "agentic workers" instead of "Claude" specifically
|
||||
- Collab feature requirement documented in `docs/README.codex.md`
|
||||
|
||||
**Writing-plans template updates**
|
||||
|
||||
- Plan steps now use checkbox syntax (`- [ ] **Step N:**`) for progress tracking
|
||||
- Plan header references both subagent-driven-development and executing-plans with platform-aware routing
|
||||
|
||||
---
|
||||
|
||||
## v4.3.1 (2026-02-21)
|
||||
|
||||
### Added
|
||||
|
||||
**Cursor support**
|
||||
|
||||
Superpowers now works with Cursor's plugin system. Includes a `.cursor-plugin/plugin.json` manifest and Cursor-specific installation instructions in the README. The SessionStart hook output now includes an `additional_context` field alongside the existing `hookSpecificOutput.additionalContext` for Cursor hook compatibility.
|
||||
|
||||
### Fixed
|
||||
|
||||
**Windows: Restored polyglot wrapper for reliable hook execution (#518, #504, #491, #487, #466, #440)**
|
||||
|
||||
Claude Code's `.sh` auto-detection on Windows was prepending `bash` to the hook command, breaking execution. The fix:
|
||||
|
||||
- Renamed `session-start.sh` to `session-start` (extensionless) so auto-detection doesn't interfere
|
||||
- Restored `run-hook.cmd` polyglot wrapper with multi-location bash discovery (standard Git for Windows paths, then PATH fallback)
|
||||
- Exits silently if no bash is found rather than erroring
|
||||
- On Unix, the wrapper runs the script directly via `exec bash`
|
||||
- Uses POSIX-safe `dirname "$0"` path resolution (works on dash/sh, not just bash)
|
||||
|
||||
This fixes SessionStart failures on Windows with spaces in paths, missing WSL, `set -euo pipefail` fragility on MSYS, and backslash mangling.
|
||||
|
||||
## v4.3.0 (2026-02-12)
|
||||
|
||||
This fix should dramatically improve superpowers skills compliance and should reduce the chances of Claude entering its native plan mode unintentionally.
|
||||
|
||||
### Changed
|
||||
|
||||
**Brainstorming skill now enforces its workflow instead of describing it**
|
||||
|
||||
Models were skipping the design phase and jumping straight to implementation skills like frontend-design, or collapsing the entire brainstorming process into a single text block. The skill now uses hard gates, a mandatory checklist, and a graphviz process flow to enforce compliance:
|
||||
|
||||
- `<HARD-GATE>`: no implementation skills, code, or scaffolding until design is presented and user approves
|
||||
- Explicit checklist (6 items) that must be created as tasks and completed in order
|
||||
- Graphviz process flow with `writing-plans` as the only valid terminal state
|
||||
- Anti-pattern callout for "this is too simple to need a design" — the exact rationalization models use to skip the process
|
||||
- Design section sizing based on section complexity, not project complexity
|
||||
|
||||
**Using-superpowers workflow graph intercepts EnterPlanMode**
|
||||
|
||||
Added an `EnterPlanMode` intercept to the skill flow graph. When the model is about to enter Claude's native plan mode, it checks whether brainstorming has happened and routes through the brainstorming skill instead. Plan mode is never entered.
|
||||
|
||||
### Fixed
|
||||
|
||||
**SessionStart hook now runs synchronously**
|
||||
|
||||
Changed `async: true` to `async: false` in hooks.json. When async, the hook could fail to complete before the model's first turn, meaning using-superpowers instructions weren't in context for the first message.
|
||||
|
||||
## v4.2.0 (2026-02-05)
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
name: code-reviewer
|
||||
description: |
|
||||
Use this agent when a major project step has been completed and needs to be reviewed against the original plan and coding standards. Examples: <example>Context: The user is creating a code-review agent that should be called after a logical chunk of code is written. user: "I've finished implementing the user authentication system as outlined in step 3 of our plan" assistant: "Great work! Now let me use the code-reviewer agent to review the implementation against our plan and coding standards" <commentary>Since a major project step has been completed, use the code-reviewer agent to validate the work against the plan and identify any issues.</commentary></example> <example>Context: User has completed a significant feature implementation. user: "The API endpoints for the task management system are now complete - that covers step 2 from our architecture document" assistant: "Excellent! Let me have the code-reviewer agent examine this implementation to ensure it aligns with our plan and follows best practices" <commentary>A numbered step from the planning document has been completed, so the code-reviewer agent should review the work.</commentary></example>
|
||||
model: inherit
|
||||
---
|
||||
|
||||
You are a Senior Code Reviewer with expertise in software architecture, design patterns, and best practices. Your role is to review completed project steps against original plans and ensure code quality standards are met.
|
||||
|
||||
When reviewing completed work, you will:
|
||||
|
||||
1. **Plan Alignment Analysis**:
|
||||
- Compare the implementation against the original planning document or step description
|
||||
- Identify any deviations from the planned approach, architecture, or requirements
|
||||
- Assess whether deviations are justified improvements or problematic departures
|
||||
- Verify that all planned functionality has been implemented
|
||||
|
||||
2. **Code Quality Assessment**:
|
||||
- Review code for adherence to established patterns and conventions
|
||||
- Check for proper error handling, type safety, and defensive programming
|
||||
- Evaluate code organization, naming conventions, and maintainability
|
||||
- Assess test coverage and quality of test implementations
|
||||
- Look for potential security vulnerabilities or performance issues
|
||||
|
||||
3. **Architecture and Design Review**:
|
||||
- Ensure the implementation follows SOLID principles and established architectural patterns
|
||||
- Check for proper separation of concerns and loose coupling
|
||||
- Verify that the code integrates well with existing systems
|
||||
- Assess scalability and extensibility considerations
|
||||
|
||||
4. **Documentation and Standards**:
|
||||
- Verify that code includes appropriate comments and documentation
|
||||
- Check that file headers, function documentation, and inline comments are present and accurate
|
||||
- Ensure adherence to project-specific coding standards and conventions
|
||||
|
||||
5. **Issue Identification and Recommendations**:
|
||||
- Clearly categorize issues as: Critical (must fix), Important (should fix), or Suggestions (nice to have)
|
||||
- For each issue, provide specific examples and actionable recommendations
|
||||
- When you identify plan deviations, explain whether they're problematic or beneficial
|
||||
- Suggest specific improvements with code examples when helpful
|
||||
|
||||
6. **Communication Protocol**:
|
||||
- If you find significant deviations from the plan, ask the coding agent to review and confirm the changes
|
||||
- If you identify issues with the original plan itself, recommend plan updates
|
||||
- For implementation problems, provide clear guidance on fixes needed
|
||||
- Always acknowledge what was done well before highlighting issues
|
||||
|
||||
Your output should be structured, actionable, and focused on helping maintain high code quality while ensuring project goals are met. Be thorough but concise, and always provide constructive feedback that helps improve both the current implementation and future development practices.
|
||||
BIN
assets/app-icon.png
Normal file
BIN
assets/app-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 47 KiB |
1
assets/superpowers-small.svg
Normal file
1
assets/superpowers-small.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg id="Calque_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M394.28,207.8c.81,2.41,1.39,4.78,1.8,7.07,1.61,9.03-.93,17.78-5.99,21.74-22.6,17.7-49.85,29.35-75.34,38.6-.59.22-1.09.28-1.4.34-2.22.47-4.95,1.04-7.25,0-1.46-.66-2.25-1.74-2.66-2.3-1.56-2.1-1.59-4.31-1.56-5.13.1-2.67-.01-4.69,0-4.82.45-3.52.91-10.66,1.41-21.28.6-3.87,2.16-9.63,6.94-13.96,4.01-3.62,8.33-4.6,14.59-5.87,10.76-2.19,37.21-8.22,47.42-16.56,1.63-1.33,2.97-2.65,4.19-3.96,3.72-3.99,6.39-7.92,7.93-10.36,3.22,3.22,7.25,8.48,9.92,16.47Z"/><path d="M428.67,185.28c-2.33,11.99-8.91,22.32-15.88,30.38.27-5.5-.05-12.11-1.86-19.08-5.04-19.36-19.74-34.7-37.78-37.78-32.21-9.74-70.59,3.79-99.08,18.29-3.87,1.95-9.52-2.77-11.84-8.16-3.32-7.71-1.63-6.28,2.61-8.49,38.31-20.03,82.01-39.61,123.91-29.7,8.26,1.95,15.96,5.26,23.48,10.54,11.32,7.96,20.21,24.74,16.44,44Z"/><path d="M117.72,304.2c-.81-2.41-1.39-4.78-1.8-7.07-1.61-9.03.93-17.78,5.99-21.74,22.6-17.7,49.85-29.35,75.34-38.6.59-.22,1.09-.28,1.4-.34,2.22-.47,4.95-1.04,7.25,0,1.46.66,2.25,1.74,2.66,2.3,1.56,2.1,1.59,4.31,1.56,5.13-.1,2.67.01,4.69,0,4.82-.45,3.52-.91,10.66-1.41,21.28-.6,3.87-2.16,9.63-6.94,13.96-4.01,3.62-8.33,4.6-14.59,5.87-10.76,2.19-37.21,8.22-47.42,16.56-1.63,1.33-2.97,2.65-4.19,3.96-3.72,3.99-6.39,7.92-7.93,10.36-3.22-3.22-7.25-8.48-9.92-16.47Z"/><path d="M83.33,326.72c2.33-11.99,8.91-22.32,15.88-30.38-.27,5.5.05,12.11,1.86,19.08,5.04,19.36,19.74,34.7,37.78,37.78,32.21,9.74,70.59-3.79,99.08-18.29,3.87-1.95,9.52,2.77,11.84,8.16,3.32,7.71,1.63,6.28-2.61,8.49-38.31,20.03-82.01,39.61-123.91,29.7-8.26-1.95-15.96-5.26-23.48-10.54-11.32-7.96-20.21-24.74-16.44-44Z"/><ellipse cx="255.16" cy="258.86" rx="28.95" ry="28.76"/></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -1,6 +0,0 @@
|
||||
---
|
||||
description: "You MUST use this before any creative work - creating features, building components, adding functionality, or modifying behavior. Explores requirements and design before implementation."
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Invoke the superpowers:brainstorming skill and follow it exactly as presented to you
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
description: Execute plan in batches with review checkpoints
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Invoke the superpowers:executing-plans skill and follow it exactly as presented to you
|
||||
@@ -1,6 +0,0 @@
|
||||
---
|
||||
description: Create detailed implementation plan with bite-sized tasks
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
Invoke the superpowers:writing-plans skill and follow it exactly as presented to you
|
||||
@@ -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 collab feature. Add to your Codex config:
|
||||
```toml
|
||||
[features]
|
||||
collab = 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
|
||||
@@ -2,169 +2,40 @@
|
||||
|
||||
Complete guide for using Superpowers with [OpenCode.ai](https://opencode.ai).
|
||||
|
||||
## Quick Install
|
||||
## Installation
|
||||
|
||||
Tell OpenCode:
|
||||
Add superpowers to the `plugin` array in your `opencode.json` (global or project-level):
|
||||
|
||||
```
|
||||
Clone https://github.com/obra/superpowers to ~/.config/opencode/superpowers, then create directory ~/.config/opencode/plugins, then symlink ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js to ~/.config/opencode/plugins/superpowers.js, then symlink ~/.config/opencode/superpowers/skills to ~/.config/opencode/skills/superpowers, then restart opencode.
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git"]
|
||||
}
|
||||
```
|
||||
|
||||
## Manual Installation
|
||||
Restart OpenCode. The plugin installs through OpenCode's plugin manager and
|
||||
registers all skills.
|
||||
|
||||
### Prerequisites
|
||||
Verify by asking: "Tell me about your superpowers"
|
||||
|
||||
- [OpenCode.ai](https://opencode.ai) installed
|
||||
- Git installed
|
||||
OpenCode uses its own plugin install. If you also use Claude Code, Codex, or
|
||||
another harness, install Superpowers separately for each one.
|
||||
|
||||
### macOS / Linux
|
||||
### Migrating from the old symlink-based install
|
||||
|
||||
If you previously installed superpowers using `git clone` and symlinks, remove the old setup:
|
||||
|
||||
```bash
|
||||
# 1. Install Superpowers (or update existing)
|
||||
if [ -d ~/.config/opencode/superpowers ]; then
|
||||
cd ~/.config/opencode/superpowers && git pull
|
||||
else
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
fi
|
||||
|
||||
# 2. Create directories
|
||||
mkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills
|
||||
|
||||
# 3. Remove old symlinks/directories if they exist
|
||||
# Remove old symlinks
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js
|
||||
rm -rf ~/.config/opencode/skills/superpowers
|
||||
|
||||
# 4. Create symlinks
|
||||
ln -s ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js ~/.config/opencode/plugins/superpowers.js
|
||||
ln -s ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
# Optionally remove the cloned repo
|
||||
rm -rf ~/.config/opencode/superpowers
|
||||
|
||||
# 5. Restart OpenCode
|
||||
# Remove skills.paths from opencode.json if you added one for superpowers
|
||||
```
|
||||
|
||||
#### Verify Installation
|
||||
|
||||
```bash
|
||||
ls -l ~/.config/opencode/plugins/superpowers.js
|
||||
ls -l ~/.config/opencode/skills/superpowers
|
||||
```
|
||||
|
||||
Both should show symlinks pointing to the superpowers directory.
|
||||
|
||||
### Windows
|
||||
|
||||
**Prerequisites:**
|
||||
- Git installed
|
||||
- Either **Developer Mode** enabled OR **Administrator privileges**
|
||||
- Windows 10: Settings → Update & Security → For developers
|
||||
- Windows 11: Settings → System → For developers
|
||||
|
||||
Pick your shell below: [Command Prompt](#command-prompt) | [PowerShell](#powershell) | [Git Bash](#git-bash)
|
||||
|
||||
#### Command Prompt
|
||||
|
||||
Run as Administrator, or with Developer Mode enabled:
|
||||
|
||||
```cmd
|
||||
:: 1. Install Superpowers
|
||||
git clone https://github.com/obra/superpowers.git "%USERPROFILE%\.config\opencode\superpowers"
|
||||
|
||||
:: 2. Create directories
|
||||
mkdir "%USERPROFILE%\.config\opencode\plugins" 2>nul
|
||||
mkdir "%USERPROFILE%\.config\opencode\skills" 2>nul
|
||||
|
||||
:: 3. Remove existing links (safe for reinstalls)
|
||||
del "%USERPROFILE%\.config\opencode\plugins\superpowers.js" 2>nul
|
||||
rmdir "%USERPROFILE%\.config\opencode\skills\superpowers" 2>nul
|
||||
|
||||
:: 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
mklink "%USERPROFILE%\.config\opencode\plugins\superpowers.js" "%USERPROFILE%\.config\opencode\superpowers\.opencode\plugins\superpowers.js"
|
||||
|
||||
:: 5. Create skills junction (works without special privileges)
|
||||
mklink /J "%USERPROFILE%\.config\opencode\skills\superpowers" "%USERPROFILE%\.config\opencode\superpowers\skills"
|
||||
|
||||
:: 6. Restart OpenCode
|
||||
```
|
||||
|
||||
#### PowerShell
|
||||
|
||||
Run as Administrator, or with Developer Mode enabled:
|
||||
|
||||
```powershell
|
||||
# 1. Install Superpowers
|
||||
git clone https://github.com/obra/superpowers.git "$env:USERPROFILE\.config\opencode\superpowers"
|
||||
|
||||
# 2. Create directories
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\plugins"
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\skills"
|
||||
|
||||
# 3. Remove existing links (safe for reinstalls)
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\plugins\superpowers.js" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\skills\superpowers" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.config\opencode\plugins\superpowers.js" -Target "$env:USERPROFILE\.config\opencode\superpowers\.opencode\plugins\superpowers.js"
|
||||
|
||||
# 5. Create skills junction (works without special privileges)
|
||||
New-Item -ItemType Junction -Path "$env:USERPROFILE\.config\opencode\skills\superpowers" -Target "$env:USERPROFILE\.config\opencode\superpowers\skills"
|
||||
|
||||
# 6. Restart OpenCode
|
||||
```
|
||||
|
||||
#### Git Bash
|
||||
|
||||
Note: Git Bash's native `ln` command copies files instead of creating symlinks. Use `cmd //c mklink` instead (the `//c` is Git Bash syntax for `/c`).
|
||||
|
||||
```bash
|
||||
# 1. Install Superpowers
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
|
||||
# 2. Create directories
|
||||
mkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills
|
||||
|
||||
# 3. Remove existing links (safe for reinstalls)
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js 2>/dev/null
|
||||
rm -rf ~/.config/opencode/skills/superpowers 2>/dev/null
|
||||
|
||||
# 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
cmd //c "mklink \"$(cygpath -w ~/.config/opencode/plugins/superpowers.js)\" \"$(cygpath -w ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js)\""
|
||||
|
||||
# 5. Create skills junction (works without special privileges)
|
||||
cmd //c "mklink /J \"$(cygpath -w ~/.config/opencode/skills/superpowers)\" \"$(cygpath -w ~/.config/opencode/superpowers/skills)\""
|
||||
|
||||
# 6. Restart OpenCode
|
||||
```
|
||||
|
||||
#### WSL Users
|
||||
|
||||
If running OpenCode inside WSL, use the [macOS / Linux](#macos--linux) instructions instead.
|
||||
|
||||
#### Verify Installation
|
||||
|
||||
**Command Prompt:**
|
||||
```cmd
|
||||
dir /AL "%USERPROFILE%\.config\opencode\plugins"
|
||||
dir /AL "%USERPROFILE%\.config\opencode\skills"
|
||||
```
|
||||
|
||||
**PowerShell:**
|
||||
```powershell
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\plugins" | Where-Object { $_.LinkType }
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\skills" | Where-Object { $_.LinkType }
|
||||
```
|
||||
|
||||
Look for `<SYMLINK>` or `<JUNCTION>` in the output.
|
||||
|
||||
#### Troubleshooting Windows
|
||||
|
||||
**"You do not have sufficient privilege" error:**
|
||||
- Enable Developer Mode in Windows Settings, OR
|
||||
- Right-click your terminal → "Run as Administrator"
|
||||
|
||||
**"Cannot create a file when that file already exists":**
|
||||
- Run the removal commands (step 3) first, then retry
|
||||
|
||||
**Symlinks not working after git clone:**
|
||||
- Run `git config --global core.symlinks true` and re-clone
|
||||
Then follow the installation steps above.
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -178,10 +49,8 @@ use skill tool to list skills
|
||||
|
||||
### Loading a Skill
|
||||
|
||||
Use OpenCode's native `skill` tool to load a specific skill:
|
||||
|
||||
```
|
||||
use skill tool to load superpowers/brainstorming
|
||||
use skill tool to load brainstorming
|
||||
```
|
||||
|
||||
### Personal Skills
|
||||
@@ -207,124 +76,88 @@ description: Use when [condition] - [what it does]
|
||||
|
||||
### Project Skills
|
||||
|
||||
Create project-specific skills in your OpenCode project:
|
||||
Create project-specific skills in `.opencode/skills/` within your project.
|
||||
|
||||
```bash
|
||||
# In your OpenCode project
|
||||
mkdir -p .opencode/skills/my-project-skill
|
||||
```
|
||||
|
||||
Create `.opencode/skills/my-project-skill/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-project-skill
|
||||
description: Use when [condition] - [what it does]
|
||||
---
|
||||
|
||||
# My Project Skill
|
||||
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
## Skill Locations
|
||||
|
||||
OpenCode discovers skills from these locations:
|
||||
|
||||
1. **Project skills** (`.opencode/skills/`) - Highest priority
|
||||
2. **Personal skills** (`~/.config/opencode/skills/`)
|
||||
3. **Superpowers skills** (`~/.config/opencode/skills/superpowers/`) - via symlink
|
||||
|
||||
## Features
|
||||
|
||||
### Automatic Context Injection
|
||||
|
||||
The plugin automatically injects superpowers context via the `experimental.chat.system.transform` hook. This adds the "using-superpowers" skill content to the system prompt on every request.
|
||||
|
||||
### Native Skills Integration
|
||||
|
||||
Superpowers uses OpenCode's native `skill` tool for skill discovery and loading. Skills are symlinked into `~/.config/opencode/skills/superpowers/` so they appear alongside your personal and project skills.
|
||||
|
||||
### Tool Mapping
|
||||
|
||||
Skills written for Claude Code are automatically adapted for OpenCode. The bootstrap provides mapping instructions:
|
||||
|
||||
- `TodoWrite` → `update_plan`
|
||||
- `Task` with subagents → OpenCode's `@mention` system
|
||||
- `Skill` tool → OpenCode's native `skill` tool
|
||||
- File operations → Native OpenCode tools
|
||||
|
||||
## Architecture
|
||||
|
||||
### Plugin Structure
|
||||
|
||||
**Location:** `~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
|
||||
**Components:**
|
||||
- `experimental.chat.system.transform` hook for bootstrap injection
|
||||
- Reads and injects the "using-superpowers" skill content
|
||||
|
||||
### Skills
|
||||
|
||||
**Location:** `~/.config/opencode/skills/superpowers/` (symlink to `~/.config/opencode/superpowers/skills/`)
|
||||
|
||||
Skills are discovered by OpenCode's native skill system. Each skill has a `SKILL.md` file with YAML frontmatter.
|
||||
**Skill Priority:** Project skills > Personal skills > Superpowers skills
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.config/opencode/superpowers
|
||||
git pull
|
||||
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:
|
||||
|
||||
```json
|
||||
{
|
||||
"plugin": ["superpowers@git+https://github.com/obra/superpowers.git#v5.0.3"]
|
||||
}
|
||||
```
|
||||
|
||||
Restart OpenCode to load the updates.
|
||||
## How It Works
|
||||
|
||||
The plugin does two things:
|
||||
|
||||
1. **Injects bootstrap context** via the `experimental.chat.messages.transform` hook, adding superpowers awareness to every conversation.
|
||||
2. **Registers the skills directory** via the `config` hook, so OpenCode discovers all superpowers skills without symlinks or manual config.
|
||||
|
||||
### Tool Mapping
|
||||
|
||||
Skills speak in actions rather than naming any one runtime's tools. On OpenCode these resolve to:
|
||||
|
||||
- "Create a todo" / "mark complete in todo list" → `todowrite`
|
||||
- `Subagent (general-purpose):` template → OpenCode's `task` tool with `subagent_type: "general"` (or `"explore"` for codebase exploration)
|
||||
- "Invoke a skill" → OpenCode's native `skill` tool
|
||||
- "Read a file" → `read`
|
||||
- "Create a file" / "edit a file" / "delete a file" → `apply_patch`
|
||||
- "Run a shell command" → `bash`
|
||||
- "Search file contents" / "find files by name" → `grep`, `glob`
|
||||
- "Fetch a URL" → `webfetch`
|
||||
|
||||
(Verified against the installed OpenCode CLI's tool inventory.)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
1. Check plugin exists: `ls ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
2. Check symlink/junction: `ls -l ~/.config/opencode/plugins/` (macOS/Linux) or `dir /AL %USERPROFILE%\.config\opencode\plugins` (Windows)
|
||||
3. Check OpenCode logs: `opencode run "test" --print-logs --log-level DEBUG`
|
||||
4. Look for plugin loading message in logs
|
||||
1. Check OpenCode logs: `opencode run --print-logs "hello" 2>&1 | grep -i superpowers`
|
||||
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. Verify skills symlink: `ls -l ~/.config/opencode/skills/superpowers` (should point to superpowers/skills/)
|
||||
2. Use OpenCode's `skill` tool to list available skills
|
||||
3. Check skill structure: each skill needs a `SKILL.md` file with valid frontmatter
|
||||
|
||||
### Windows: Module not found error
|
||||
|
||||
If you see `Cannot find module` errors on Windows:
|
||||
- **Cause:** Git Bash `ln -sf` copies files instead of creating symlinks
|
||||
- **Fix:** Use `mklink /J` directory junctions instead (see Windows installation steps)
|
||||
1. Use OpenCode's `skill` tool to list available skills
|
||||
2. Check that the plugin is loading (see above)
|
||||
3. Each skill needs a `SKILL.md` file with valid YAML frontmatter
|
||||
|
||||
### Bootstrap not appearing
|
||||
|
||||
1. Verify using-superpowers skill exists: `ls ~/.config/opencode/superpowers/skills/using-superpowers/SKILL.md`
|
||||
2. Check OpenCode version supports `experimental.chat.system.transform` hook
|
||||
3. Restart OpenCode after plugin changes
|
||||
1. Check OpenCode version supports `experimental.chat.messages.transform` hook
|
||||
2. Restart OpenCode after config changes
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Report issues: https://github.com/obra/superpowers/issues
|
||||
- Main documentation: https://github.com/obra/superpowers
|
||||
- OpenCode docs: https://opencode.ai/docs/
|
||||
|
||||
## Testing
|
||||
|
||||
Verify your installation:
|
||||
|
||||
```bash
|
||||
# Check plugin loads
|
||||
opencode run --print-logs "hello" 2>&1 | grep -i superpowers
|
||||
|
||||
# Check skills are discoverable
|
||||
opencode run "use skill tool to list all skills" 2>&1 | grep -i superpowers
|
||||
|
||||
# Check bootstrap injection
|
||||
opencode run "what superpowers do you have?"
|
||||
```
|
||||
|
||||
The agent should mention having superpowers and be able to list skills from `superpowers/`.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# OpenCode Support Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Add full superpowers support for OpenCode.ai with a native JavaScript plugin that shares core functionality with the existing Codex implementation.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Visual Brainstorming Companion Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Give Claude a browser-based visual companion for brainstorming sessions - show mockups, prototypes, and interactive choices alongside terminal conversation.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Document Review System Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan.
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan.
|
||||
|
||||
**Goal:** Add spec and plan document review loops to the brainstorming and writing-plans skills.
|
||||
|
||||
@@ -285,12 +285,12 @@ Run: `grep -A 20 "Plan Document Header" skills/writing-plans/SKILL.md`
|
||||
The plan header should note that tasks and steps use checkbox syntax. Update the header comment:
|
||||
|
||||
```markdown
|
||||
> **For Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Tasks and steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Tasks and steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
```
|
||||
|
||||
- [ ] **Step 3:** Verify the change
|
||||
|
||||
Run: `grep -A 5 "For Claude:" skills/writing-plans/SKILL.md`
|
||||
Run: `grep -A 5 "For agentic workers:" skills/writing-plans/SKILL.md`
|
||||
Expected: Shows updated header with checkbox syntax mention
|
||||
|
||||
- [ ] **Step 4:** Commit
|
||||
|
||||
@@ -0,0 +1,523 @@
|
||||
# Visual Brainstorming Refactor Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Refactor visual brainstorming from blocking TUI feedback model to non-blocking "Browser Displays, Terminal Commands" architecture.
|
||||
|
||||
**Architecture:** Browser becomes an interactive display; terminal stays the conversation channel. Server writes user events to a per-screen `.events` file that Claude reads on its next turn. Eliminates `wait-for-feedback.sh` and all `TaskOutput` blocking.
|
||||
|
||||
**Tech Stack:** Node.js (Express, ws, chokidar), vanilla HTML/CSS/JS
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-02-19-visual-brainstorming-refactor-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| File | Action | Responsibility |
|
||||
|------|--------|---------------|
|
||||
| `lib/brainstorm-server/index.js` | Modify | Server: add `.events` file writing, clear on new screen, replace `wrapInFrame` |
|
||||
| `lib/brainstorm-server/frame-template.html` | Modify | Template: remove feedback footer, add content placeholder + selection indicator |
|
||||
| `lib/brainstorm-server/helper.js` | Modify | Client JS: remove send/feedback functions, narrow to click capture + indicator updates |
|
||||
| `lib/brainstorm-server/wait-for-feedback.sh` | Delete | No longer needed |
|
||||
| `skills/brainstorming/visual-companion.md` | Modify | Skill instructions: rewrite loop to non-blocking flow |
|
||||
| `tests/brainstorm-server/server.test.js` | Modify | Tests: update for new template structure and helper.js API |
|
||||
|
||||
---
|
||||
|
||||
## Chunk 1: Server, Template, Client, Tests, Skill
|
||||
|
||||
### Task 1: Update `frame-template.html`
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/brainstorm-server/frame-template.html`
|
||||
|
||||
- [ ] **Step 1: Remove the feedback footer HTML**
|
||||
|
||||
Replace the feedback-footer div (lines 227-233) with a selection indicator bar:
|
||||
|
||||
```html
|
||||
<div class="indicator-bar">
|
||||
<span id="indicator-text">Click an option above, then return to the terminal</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
Also replace the default content inside `#claude-content` (lines 220-223) with the content placeholder:
|
||||
|
||||
```html
|
||||
<div id="claude-content">
|
||||
<!-- CONTENT -->
|
||||
</div>
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Replace feedback footer CSS with indicator bar CSS**
|
||||
|
||||
Remove the `.feedback-footer`, `.feedback-footer label`, `.feedback-row`, and the textarea/button styles within `.feedback-footer` (lines 82-112).
|
||||
|
||||
Add indicator bar CSS:
|
||||
|
||||
```css
|
||||
.indicator-bar {
|
||||
background: var(--bg-secondary);
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 0.5rem 1.5rem;
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.indicator-bar span {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.indicator-bar .selected-text {
|
||||
color: var(--accent);
|
||||
font-weight: 500;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify template renders**
|
||||
|
||||
Run the test suite to check the template still loads:
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: Tests 1-5 should still pass. Tests 6-8 may fail (expected — they assert old structure).
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add lib/brainstorm-server/frame-template.html
|
||||
git commit -m "Replace feedback footer with selection indicator bar in brainstorm template"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Update `index.js` — content injection and `.events` file
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/brainstorm-server/index.js`
|
||||
|
||||
- [ ] **Step 1: Write failing test for `.events` file writing**
|
||||
|
||||
Add to `tests/brainstorm-server/server.test.js` after Test 4 area — a new test that sends a WebSocket event with a `choice` field and verifies `.events` file is written:
|
||||
|
||||
```javascript
|
||||
// Test: Choice events written to .events file
|
||||
console.log('Test: Choice events written to .events file');
|
||||
const ws3 = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
||||
await new Promise(resolve => ws3.on('open', resolve));
|
||||
|
||||
ws3.send(JSON.stringify({ type: 'click', choice: 'a', text: 'Option A' }));
|
||||
await sleep(300);
|
||||
|
||||
const eventsFile = path.join(TEST_DIR, '.events');
|
||||
assert(fs.existsSync(eventsFile), '.events file should exist after choice click');
|
||||
const lines = fs.readFileSync(eventsFile, 'utf-8').trim().split('\n');
|
||||
const event = JSON.parse(lines[lines.length - 1]);
|
||||
assert.strictEqual(event.choice, 'a', 'Event should contain choice');
|
||||
assert.strictEqual(event.text, 'Option A', 'Event should contain text');
|
||||
ws3.close();
|
||||
console.log(' PASS');
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run test to verify it fails**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: New test FAILS — `.events` file doesn't exist yet.
|
||||
|
||||
- [ ] **Step 3: Write failing test for `.events` file clearing on new screen**
|
||||
|
||||
Add another test:
|
||||
|
||||
```javascript
|
||||
// Test: .events cleared on new screen
|
||||
console.log('Test: .events cleared on new screen');
|
||||
// .events file should still exist from previous test
|
||||
assert(fs.existsSync(path.join(TEST_DIR, '.events')), '.events should exist before new screen');
|
||||
fs.writeFileSync(path.join(TEST_DIR, 'new-screen.html'), '<h2>New screen</h2>');
|
||||
await sleep(500);
|
||||
assert(!fs.existsSync(path.join(TEST_DIR, '.events')), '.events should be cleared after new screen');
|
||||
console.log(' PASS');
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run test to verify it fails**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: New test FAILS — `.events` not cleared on screen push.
|
||||
|
||||
- [ ] **Step 5: Implement `.events` file writing in `index.js`**
|
||||
|
||||
In the WebSocket `message` handler (line 74-77 of `index.js`), after the `console.log`, add:
|
||||
|
||||
```javascript
|
||||
// Write user events to .events file for Claude to read
|
||||
if (event.choice) {
|
||||
const eventsFile = path.join(SCREEN_DIR, '.events');
|
||||
fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n');
|
||||
}
|
||||
```
|
||||
|
||||
In the chokidar `add` handler (line 104-111), add `.events` clearing:
|
||||
|
||||
```javascript
|
||||
if (filePath.endsWith('.html')) {
|
||||
// Clear events from previous screen
|
||||
const eventsFile = path.join(SCREEN_DIR, '.events');
|
||||
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
||||
|
||||
console.log(JSON.stringify({ type: 'screen-added', file: filePath }));
|
||||
// ... existing reload broadcast
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Replace `wrapInFrame` with comment placeholder injection**
|
||||
|
||||
Replace the `wrapInFrame` function (lines 27-32 of `index.js`):
|
||||
|
||||
```javascript
|
||||
function wrapInFrame(content) {
|
||||
return frameTemplate.replace('<!-- CONTENT -->', content);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 7: Run all tests**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: New `.events` tests PASS. Existing tests may still have failures from old assertions (fixed in Task 4).
|
||||
|
||||
- [ ] **Step 8: Commit**
|
||||
|
||||
```bash
|
||||
git add lib/brainstorm-server/index.js tests/brainstorm-server/server.test.js
|
||||
git commit -m "Add .events file writing and comment-based content injection to brainstorm server"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Simplify `helper.js`
|
||||
|
||||
**Files:**
|
||||
- Modify: `lib/brainstorm-server/helper.js`
|
||||
|
||||
- [ ] **Step 1: Remove `sendToClaude` function**
|
||||
|
||||
Delete the `sendToClaude` function (lines 92-106) — the function body and the page takeover HTML.
|
||||
|
||||
- [ ] **Step 2: Remove `window.send` function**
|
||||
|
||||
Delete the `window.send` function (lines 120-129) — was tied to the removed Send button.
|
||||
|
||||
- [ ] **Step 3: Remove form submission and input change handlers**
|
||||
|
||||
Delete the form submission handler (lines 57-71) and the input change handler (lines 73-89) including the `inputTimeout` variable.
|
||||
|
||||
- [ ] **Step 4: Remove `pageshow` event listener**
|
||||
|
||||
Delete the `pageshow` listener we added earlier (no textarea to clear anymore).
|
||||
|
||||
- [ ] **Step 5: Narrow click handler to `[data-choice]` only**
|
||||
|
||||
Replace the click handler (lines 36-55) with a narrower version:
|
||||
|
||||
```javascript
|
||||
// Capture clicks on choice elements
|
||||
document.addEventListener('click', (e) => {
|
||||
const target = e.target.closest('[data-choice]');
|
||||
if (!target) return;
|
||||
|
||||
sendEvent({
|
||||
type: 'click',
|
||||
text: target.textContent.trim(),
|
||||
choice: target.dataset.choice,
|
||||
id: target.id || null
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Add indicator bar update on choice click**
|
||||
|
||||
After the `sendEvent` call in the click handler, add:
|
||||
|
||||
```javascript
|
||||
// Update indicator bar
|
||||
const indicator = document.getElementById('indicator-text');
|
||||
if (indicator) {
|
||||
const label = target.querySelector('h3, .content h3, .card-body h3')?.textContent?.trim() || target.dataset.choice;
|
||||
indicator.innerHTML = '<span class="selected-text">' + label + ' selected</span> — return to terminal to continue';
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 7: Remove `sendToClaude` from `window.brainstorm` API**
|
||||
|
||||
Update the `window.brainstorm` object (lines 132-136) to remove `sendToClaude`:
|
||||
|
||||
```javascript
|
||||
window.brainstorm = {
|
||||
send: sendEvent,
|
||||
choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata })
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **Step 8: Run tests**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
|
||||
- [ ] **Step 9: Commit**
|
||||
|
||||
```bash
|
||||
git add lib/brainstorm-server/helper.js
|
||||
git commit -m "Simplify helper.js: remove feedback functions, narrow to choice capture + indicator"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Update tests for new structure
|
||||
|
||||
**Files:**
|
||||
- Modify: `tests/brainstorm-server/server.test.js`
|
||||
|
||||
**Note:** Line references below are from the _original_ file. Task 2 inserted new tests earlier in the file, so actual line numbers will be shifted. Find tests by their `console.log` labels (e.g., "Test 5:", "Test 6:").
|
||||
|
||||
- [ ] **Step 1: Update Test 5 (full document assertion)**
|
||||
|
||||
Find the Test 5 assertion `!fullRes.body.includes('feedback-footer')`. Change it to: Full documents should NOT have the indicator bar either (they're served as-is):
|
||||
|
||||
```javascript
|
||||
assert(!fullRes.body.includes('indicator-bar') || fullDoc.includes('indicator-bar'),
|
||||
'Should not wrap full documents in frame template');
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update Test 6 (fragment wrapping)**
|
||||
|
||||
Line 125: Replace `feedback-footer` assertion with indicator bar assertion:
|
||||
|
||||
```javascript
|
||||
assert(fragRes.body.includes('indicator-bar'), 'Fragment should get indicator bar from frame');
|
||||
```
|
||||
|
||||
Also verify content placeholder was replaced (fragment content appears, placeholder comment doesn't):
|
||||
|
||||
```javascript
|
||||
assert(!fragRes.body.includes('<!-- CONTENT -->'), 'Content placeholder should be replaced');
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update Test 7 (helper.js API)**
|
||||
|
||||
Lines 140-142: Update assertions to reflect the new API surface:
|
||||
|
||||
```javascript
|
||||
assert(helperContent.includes('toggleSelect'), 'helper.js should define toggleSelect');
|
||||
assert(helperContent.includes('sendEvent'), 'helper.js should define sendEvent');
|
||||
assert(helperContent.includes('selectedChoice'), 'helper.js should track selectedChoice');
|
||||
assert(helperContent.includes('brainstorm'), 'helper.js should expose brainstorm API');
|
||||
assert(!helperContent.includes('sendToClaude'), 'helper.js should not contain sendToClaude');
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Replace Test 8 (sendToClaude theming) with indicator bar test**
|
||||
|
||||
Replace Test 8 (lines 145-149) — `sendToClaude` no longer exists. Test the indicator bar instead:
|
||||
|
||||
```javascript
|
||||
// Test 8: Indicator bar uses CSS variables (theme support)
|
||||
console.log('Test 8: Indicator bar uses CSS variables');
|
||||
const templateContent = fs.readFileSync(
|
||||
path.join(__dirname, '../../lib/brainstorm-server/frame-template.html'), 'utf-8'
|
||||
);
|
||||
assert(templateContent.includes('indicator-bar'), 'Template should have indicator bar');
|
||||
assert(templateContent.includes('indicator-text'), 'Template should have indicator text element');
|
||||
console.log(' PASS');
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Run full test suite**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: ALL tests PASS.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/brainstorm-server/server.test.js
|
||||
git commit -m "Update brainstorm server tests for new template structure and helper.js API"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Delete `wait-for-feedback.sh`
|
||||
|
||||
**Files:**
|
||||
- Delete: `lib/brainstorm-server/wait-for-feedback.sh`
|
||||
|
||||
- [ ] **Step 1: Verify no other files import or reference `wait-for-feedback.sh`**
|
||||
|
||||
Search the codebase:
|
||||
```bash
|
||||
grep -r "wait-for-feedback" /Users/drewritter/prime-rad/superpowers/ --include="*.js" --include="*.md" --include="*.sh" --include="*.json"
|
||||
```
|
||||
|
||||
Expected references: only `visual-companion.md` (rewritten in Task 6) and possibly release notes (historical, leave as-is).
|
||||
|
||||
- [ ] **Step 2: Delete the file**
|
||||
|
||||
```bash
|
||||
rm lib/brainstorm-server/wait-for-feedback.sh
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Run tests to confirm nothing breaks**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: All tests PASS (no test referenced this file).
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add -u lib/brainstorm-server/wait-for-feedback.sh
|
||||
git commit -m "Delete wait-for-feedback.sh: replaced by .events file"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Rewrite `visual-companion.md`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/brainstorming/visual-companion.md`
|
||||
|
||||
- [ ] **Step 1: Update "How It Works" description (line 18)**
|
||||
|
||||
Replace the sentence about receiving feedback "as JSON" with:
|
||||
|
||||
```markdown
|
||||
The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content, the user sees it in their browser and can click to select options. Selections are recorded to a `.events` file that you read on your next turn.
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update fragment description (line 20)**
|
||||
|
||||
Remove "feedback footer" from the description of what the frame template provides:
|
||||
|
||||
```markdown
|
||||
**Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, selection indicator, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Rewrite "The Loop" section (lines 36-61)**
|
||||
|
||||
Replace the entire "The Loop" section with:
|
||||
|
||||
```markdown
|
||||
## The Loop
|
||||
|
||||
1. **Write HTML** to a new file in `screen_dir`:
|
||||
- Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html`
|
||||
- **Never reuse filenames** — each screen gets a fresh file
|
||||
- Use Write tool — **never use cat/heredoc** (dumps noise into terminal)
|
||||
- Server automatically serves the newest file
|
||||
|
||||
2. **Tell user what to expect and end your turn:**
|
||||
- Remind them of the URL (every step, not just first)
|
||||
- Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage")
|
||||
- Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like."
|
||||
|
||||
3. **On your next turn** — after the user responds in the terminal:
|
||||
- Read `$SCREEN_DIR/.events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines
|
||||
- Merge with the user's terminal text to get the full picture
|
||||
- The terminal message is the primary feedback; `.events` provides structured interaction data
|
||||
|
||||
4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated.
|
||||
|
||||
5. Repeat until done.
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Replace "User Feedback Format" section (lines 165-174)**
|
||||
|
||||
Replace with:
|
||||
|
||||
```markdown
|
||||
## Browser Events Format
|
||||
|
||||
When the user clicks options in the browser, their interactions are recorded to `$SCREEN_DIR/.events` (one JSON object per line). The file is cleared automatically when you push a new screen.
|
||||
|
||||
```jsonl
|
||||
{"type":"click","choice":"a","text":"Option A - Simple Layout","timestamp":1706000101}
|
||||
{"type":"click","choice":"c","text":"Option C - Complex Grid","timestamp":1706000108}
|
||||
{"type":"click","choice":"b","text":"Option B - Hybrid","timestamp":1706000115}
|
||||
```
|
||||
|
||||
The full event stream shows the user's exploration path — they may click multiple options before settling. The last `choice` event is typically the final selection, but the pattern of clicks can reveal hesitation or preferences worth asking about.
|
||||
|
||||
If `.events` doesn't exist, the user didn't interact with the browser — use only their terminal text.
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Update "Writing Content Fragments" description (line 65)**
|
||||
|
||||
Remove "feedback footer" reference:
|
||||
|
||||
```markdown
|
||||
Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure).
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Update Reference section (lines 200-203)**
|
||||
|
||||
Remove the helper.js reference description about "JS API" — the API is now minimal. Keep the path reference:
|
||||
|
||||
```markdown
|
||||
## Reference
|
||||
|
||||
- Frame template (CSS reference): `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/frame-template.html`
|
||||
- Helper script (client-side): `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/helper.js`
|
||||
```
|
||||
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/brainstorming/visual-companion.md
|
||||
git commit -m "Rewrite visual-companion.md for non-blocking browser-displays-terminal-commands flow"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Final verification
|
||||
|
||||
- [ ] **Step 1: Run full test suite**
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && node tests/brainstorm-server/server.test.js
|
||||
```
|
||||
Expected: ALL tests PASS.
|
||||
|
||||
- [ ] **Step 2: Manual smoke test**
|
||||
|
||||
Start the server manually and verify the flow works end-to-end:
|
||||
|
||||
```bash
|
||||
cd /Users/drewritter/prime-rad/superpowers && lib/brainstorm-server/start-server.sh --project-dir /tmp/brainstorm-smoke-test
|
||||
```
|
||||
|
||||
Write a test fragment, open in browser, click an option, verify `.events` file is written, verify indicator bar updates. Then stop the server:
|
||||
|
||||
```bash
|
||||
lib/brainstorm-server/stop-server.sh <screen_dir from start output>
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify no stale references remain**
|
||||
|
||||
```bash
|
||||
grep -r "wait-for-feedback\|sendToClaude\|feedback-footer\|send-to-claude\|TaskOutput.*block.*true" /Users/drewritter/prime-rad/superpowers/ --include="*.js" --include="*.md" --include="*.sh" --include="*.html" | grep -v node_modules | grep -v RELEASE-NOTES | grep -v "\.md:.*spec\|plan"
|
||||
```
|
||||
|
||||
Expected: No hits outside of release notes and the spec/plan docs (which are historical).
|
||||
|
||||
- [ ] **Step 4: Final commit if any cleanup needed**
|
||||
|
||||
```bash
|
||||
git status
|
||||
# Review untracked/modified files, stage specific files as needed, commit if clean
|
||||
```
|
||||
479
docs/superpowers/plans/2026-03-11-zero-dep-brainstorm-server.md
Normal file
479
docs/superpowers/plans/2026-03-11-zero-dep-brainstorm-server.md
Normal file
@@ -0,0 +1,479 @@
|
||||
# Zero-Dependency Brainstorm Server Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Replace the brainstorm server's vendored node_modules with a single zero-dependency `server.js` using Node built-ins.
|
||||
|
||||
**Architecture:** Single file with WebSocket protocol (RFC 6455 text frames), HTTP server (`http` module), and file watching (`fs.watch`). Exports protocol functions for unit testing when required as a module.
|
||||
|
||||
**Tech Stack:** Node.js built-ins only: `http`, `crypto`, `fs`, `path`
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-03-11-zero-dep-brainstorm-server-design.md`
|
||||
|
||||
**Existing tests:** `tests/brainstorm-server/ws-protocol.test.js` (unit), `tests/brainstorm-server/server.test.js` (integration)
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
- **Create:** `skills/brainstorming/scripts/server.js` — the zero-dep replacement
|
||||
- **Modify:** `skills/brainstorming/scripts/start-server.sh:94,100` — change `index.js` to `server.js`
|
||||
- **Modify:** `.gitignore:6` — remove the `!skills/brainstorming/scripts/node_modules/` exception
|
||||
- **Delete:** `skills/brainstorming/scripts/index.js`
|
||||
- **Delete:** `skills/brainstorming/scripts/package.json`
|
||||
- **Delete:** `skills/brainstorming/scripts/package-lock.json`
|
||||
- **Delete:** `skills/brainstorming/scripts/node_modules/` (714 files)
|
||||
- **No changes:** `skills/brainstorming/scripts/helper.js`, `skills/brainstorming/scripts/frame-template.html`, `skills/brainstorming/scripts/stop-server.sh`
|
||||
|
||||
---
|
||||
|
||||
## Chunk 1: WebSocket Protocol Layer
|
||||
|
||||
### Task 1: Implement WebSocket protocol exports
|
||||
|
||||
**Files:**
|
||||
- Create: `skills/brainstorming/scripts/server.js`
|
||||
- Test: `tests/brainstorm-server/ws-protocol.test.js` (already exists)
|
||||
|
||||
- [ ] **Step 1: Create server.js with OPCODES constant and computeAcceptKey**
|
||||
|
||||
```js
|
||||
const crypto = require('crypto');
|
||||
|
||||
const OPCODES = { TEXT: 0x01, CLOSE: 0x08, PING: 0x09, PONG: 0x0A };
|
||||
const WS_MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
|
||||
|
||||
function computeAcceptKey(clientKey) {
|
||||
return crypto.createHash('sha1').update(clientKey + WS_MAGIC).digest('base64');
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Implement encodeFrame**
|
||||
|
||||
Server frames are never masked. Three length encodings:
|
||||
- payload < 126: 2-byte header (FIN+opcode, length)
|
||||
- 126-65535: 4-byte header (FIN+opcode, 126, 16-bit length)
|
||||
- > 65535: 10-byte header (FIN+opcode, 127, 64-bit length)
|
||||
|
||||
```js
|
||||
function encodeFrame(opcode, payload) {
|
||||
const fin = 0x80;
|
||||
const len = payload.length;
|
||||
let header;
|
||||
|
||||
if (len < 126) {
|
||||
header = Buffer.alloc(2);
|
||||
header[0] = fin | opcode;
|
||||
header[1] = len;
|
||||
} else if (len < 65536) {
|
||||
header = Buffer.alloc(4);
|
||||
header[0] = fin | opcode;
|
||||
header[1] = 126;
|
||||
header.writeUInt16BE(len, 2);
|
||||
} else {
|
||||
header = Buffer.alloc(10);
|
||||
header[0] = fin | opcode;
|
||||
header[1] = 127;
|
||||
header.writeBigUInt64BE(BigInt(len), 2);
|
||||
}
|
||||
|
||||
return Buffer.concat([header, payload]);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Implement decodeFrame**
|
||||
|
||||
Client frames are always masked. Returns `{ opcode, payload, bytesConsumed }` or `null` for incomplete. Throws on unmasked frames.
|
||||
|
||||
```js
|
||||
function decodeFrame(buffer) {
|
||||
if (buffer.length < 2) return null;
|
||||
|
||||
const firstByte = buffer[0];
|
||||
const secondByte = buffer[1];
|
||||
const opcode = firstByte & 0x0F;
|
||||
const masked = (secondByte & 0x80) !== 0;
|
||||
let payloadLen = secondByte & 0x7F;
|
||||
let offset = 2;
|
||||
|
||||
if (!masked) throw new Error('Client frames must be masked');
|
||||
|
||||
if (payloadLen === 126) {
|
||||
if (buffer.length < 4) return null;
|
||||
payloadLen = buffer.readUInt16BE(2);
|
||||
offset = 4;
|
||||
} else if (payloadLen === 127) {
|
||||
if (buffer.length < 10) return null;
|
||||
payloadLen = Number(buffer.readBigUInt64BE(2));
|
||||
offset = 10;
|
||||
}
|
||||
|
||||
const maskOffset = offset;
|
||||
const dataOffset = offset + 4;
|
||||
const totalLen = dataOffset + payloadLen;
|
||||
if (buffer.length < totalLen) return null;
|
||||
|
||||
const mask = buffer.slice(maskOffset, dataOffset);
|
||||
const data = Buffer.alloc(payloadLen);
|
||||
for (let i = 0; i < payloadLen; i++) {
|
||||
data[i] = buffer[dataOffset + i] ^ mask[i % 4];
|
||||
}
|
||||
|
||||
return { opcode, payload: data, bytesConsumed: totalLen };
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Add module exports at the bottom of the file**
|
||||
|
||||
```js
|
||||
module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES };
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Run unit tests**
|
||||
|
||||
Run: `cd tests/brainstorm-server && node ws-protocol.test.js`
|
||||
Expected: All tests pass (handshake, encoding, decoding, boundaries, edge cases)
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/brainstorming/scripts/server.js
|
||||
git commit -m "Add WebSocket protocol layer for zero-dep brainstorm server"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chunk 2: HTTP Server and Application Logic
|
||||
|
||||
### Task 2: Add HTTP server, file watching, and WebSocket connection handling
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/brainstorming/scripts/server.js`
|
||||
- Test: `tests/brainstorm-server/server.test.js` (already exists)
|
||||
|
||||
- [ ] **Step 1: Add configuration and constants at top of server.js (after requires)**
|
||||
|
||||
```js
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const PORT = process.env.BRAINSTORM_PORT || (49152 + Math.floor(Math.random() * 16383));
|
||||
const HOST = process.env.BRAINSTORM_HOST || '127.0.0.1';
|
||||
const URL_HOST = process.env.BRAINSTORM_URL_HOST || (HOST === '127.0.0.1' ? 'localhost' : HOST);
|
||||
const SCREEN_DIR = process.env.BRAINSTORM_DIR || '/tmp/brainstorm';
|
||||
|
||||
const MIME_TYPES = {
|
||||
'.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript',
|
||||
'.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml'
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add WAITING_PAGE, template loading at module scope, and helper functions**
|
||||
|
||||
Load `frameTemplate` and `helperInjection` at module scope so they're accessible to `wrapInFrame` and `handleRequest`. They only read files from `__dirname` (the scripts directory), which is valid whether the module is required or run directly.
|
||||
|
||||
```js
|
||||
const WAITING_PAGE = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head><title>Brainstorm Companion</title>
|
||||
<style>body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
|
||||
h1 { color: #333; } p { color: #666; }</style>
|
||||
</head>
|
||||
<body><h1>Brainstorm Companion</h1>
|
||||
<p>Waiting for Claude to push a screen...</p></body></html>`;
|
||||
|
||||
const frameTemplate = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf-8');
|
||||
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
|
||||
const helperInjection = '<script>\n' + helperScript + '\n</script>';
|
||||
|
||||
function isFullDocument(html) {
|
||||
const trimmed = html.trimStart().toLowerCase();
|
||||
return trimmed.startsWith('<!doctype') || trimmed.startsWith('<html');
|
||||
}
|
||||
|
||||
function wrapInFrame(content) {
|
||||
return frameTemplate.replace('<!-- CONTENT -->', content);
|
||||
}
|
||||
|
||||
function getNewestScreen() {
|
||||
const files = fs.readdirSync(SCREEN_DIR)
|
||||
.filter(f => f.endsWith('.html'))
|
||||
.map(f => {
|
||||
const fp = path.join(SCREEN_DIR, f);
|
||||
return { path: fp, mtime: fs.statSync(fp).mtime.getTime() };
|
||||
})
|
||||
.sort((a, b) => b.mtime - a.mtime);
|
||||
return files.length > 0 ? files[0].path : null;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Add HTTP request handler**
|
||||
|
||||
```js
|
||||
function handleRequest(req, res) {
|
||||
if (req.method === 'GET' && req.url === '/') {
|
||||
const screenFile = getNewestScreen();
|
||||
let html = screenFile
|
||||
? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8'))
|
||||
: WAITING_PAGE;
|
||||
|
||||
if (html.includes('</body>')) {
|
||||
html = html.replace('</body>', helperInjection + '\n</body>');
|
||||
} else {
|
||||
html += helperInjection;
|
||||
}
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'text/html' });
|
||||
res.end(html);
|
||||
} else if (req.method === 'GET' && req.url.startsWith('/files/')) {
|
||||
const fileName = req.url.slice(7); // strip '/files/'
|
||||
const filePath = path.join(SCREEN_DIR, path.basename(fileName));
|
||||
if (!fs.existsSync(filePath)) {
|
||||
res.writeHead(404);
|
||||
res.end('Not found');
|
||||
return;
|
||||
}
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
||||
res.writeHead(200, { 'Content-Type': contentType });
|
||||
res.end(fs.readFileSync(filePath));
|
||||
} else {
|
||||
res.writeHead(404);
|
||||
res.end('Not found');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Add WebSocket connection handling**
|
||||
|
||||
```js
|
||||
const clients = new Set();
|
||||
|
||||
function handleUpgrade(req, socket) {
|
||||
const key = req.headers['sec-websocket-key'];
|
||||
if (!key) { socket.destroy(); return; }
|
||||
|
||||
const accept = computeAcceptKey(key);
|
||||
socket.write(
|
||||
'HTTP/1.1 101 Switching Protocols\r\n' +
|
||||
'Upgrade: websocket\r\n' +
|
||||
'Connection: Upgrade\r\n' +
|
||||
'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n'
|
||||
);
|
||||
|
||||
let buffer = Buffer.alloc(0);
|
||||
clients.add(socket);
|
||||
|
||||
socket.on('data', (chunk) => {
|
||||
buffer = Buffer.concat([buffer, chunk]);
|
||||
while (buffer.length > 0) {
|
||||
let result;
|
||||
try {
|
||||
result = decodeFrame(buffer);
|
||||
} catch (e) {
|
||||
socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0)));
|
||||
clients.delete(socket);
|
||||
return;
|
||||
}
|
||||
if (!result) break;
|
||||
buffer = buffer.slice(result.bytesConsumed);
|
||||
|
||||
switch (result.opcode) {
|
||||
case OPCODES.TEXT:
|
||||
handleMessage(result.payload.toString());
|
||||
break;
|
||||
case OPCODES.CLOSE:
|
||||
socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0)));
|
||||
clients.delete(socket);
|
||||
return;
|
||||
case OPCODES.PING:
|
||||
socket.write(encodeFrame(OPCODES.PONG, result.payload));
|
||||
break;
|
||||
case OPCODES.PONG:
|
||||
break;
|
||||
default:
|
||||
// Unsupported opcode — close with 1003
|
||||
const closeBuf = Buffer.alloc(2);
|
||||
closeBuf.writeUInt16BE(1003);
|
||||
socket.end(encodeFrame(OPCODES.CLOSE, closeBuf));
|
||||
clients.delete(socket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('close', () => clients.delete(socket));
|
||||
socket.on('error', () => clients.delete(socket));
|
||||
}
|
||||
|
||||
function handleMessage(text) {
|
||||
let event;
|
||||
try {
|
||||
event = JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse WebSocket message:', e.message);
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify({ source: 'user-event', ...event }));
|
||||
if (event.choice) {
|
||||
const eventsFile = path.join(SCREEN_DIR, '.events');
|
||||
fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function broadcast(msg) {
|
||||
const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg)));
|
||||
for (const socket of clients) {
|
||||
try { socket.write(frame); } catch (e) { clients.delete(socket); }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Add debounce timer map**
|
||||
|
||||
```js
|
||||
const debounceTimers = new Map();
|
||||
```
|
||||
|
||||
File watching logic is inlined in `startServer` (Step 6) to keep watcher lifecycle together with server lifecycle and include an `error` handler per spec.
|
||||
|
||||
- [ ] **Step 6: Add startServer function and conditional main**
|
||||
|
||||
`frameTemplate` and `helperInjection` are already at module scope (Step 2). `startServer` just creates the screen dir, starts the HTTP server, watcher, and logs startup info.
|
||||
|
||||
```js
|
||||
function startServer() {
|
||||
if (!fs.existsSync(SCREEN_DIR)) fs.mkdirSync(SCREEN_DIR, { recursive: true });
|
||||
|
||||
const server = http.createServer(handleRequest);
|
||||
server.on('upgrade', handleUpgrade);
|
||||
|
||||
const watcher = fs.watch(SCREEN_DIR, (eventType, filename) => {
|
||||
if (!filename || !filename.endsWith('.html')) return;
|
||||
if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename));
|
||||
debounceTimers.set(filename, setTimeout(() => {
|
||||
debounceTimers.delete(filename);
|
||||
const filePath = path.join(SCREEN_DIR, filename);
|
||||
if (eventType === 'rename' && fs.existsSync(filePath)) {
|
||||
const eventsFile = path.join(SCREEN_DIR, '.events');
|
||||
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
||||
console.log(JSON.stringify({ type: 'screen-added', file: filePath }));
|
||||
} else if (eventType === 'change') {
|
||||
console.log(JSON.stringify({ type: 'screen-updated', file: filePath }));
|
||||
}
|
||||
broadcast({ type: 'reload' });
|
||||
}, 100));
|
||||
});
|
||||
watcher.on('error', (err) => console.error('fs.watch error:', err.message));
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
const info = JSON.stringify({
|
||||
type: 'server-started', port: Number(PORT), host: HOST,
|
||||
url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT,
|
||||
screen_dir: SCREEN_DIR
|
||||
});
|
||||
console.log(info);
|
||||
fs.writeFileSync(path.join(SCREEN_DIR, '.server-info'), info + '\n');
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
startServer();
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 7: Run integration tests**
|
||||
|
||||
The test directory already has a `package.json` with `ws` as a dependency. Install it if needed, then run tests.
|
||||
|
||||
Run: `cd tests/brainstorm-server && npm install && node server.test.js`
|
||||
Expected: All tests pass
|
||||
|
||||
- [ ] **Step 8: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/brainstorming/scripts/server.js
|
||||
git commit -m "Add HTTP server, WebSocket handling, and file watching to server.js"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Chunk 3: Swap and Cleanup
|
||||
|
||||
### Task 3: Update start-server.sh and remove old files
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/brainstorming/scripts/start-server.sh:94,100`
|
||||
- Modify: `.gitignore:6`
|
||||
- Delete: `skills/brainstorming/scripts/index.js`
|
||||
- Delete: `skills/brainstorming/scripts/package.json`
|
||||
- Delete: `skills/brainstorming/scripts/package-lock.json`
|
||||
- Delete: `skills/brainstorming/scripts/node_modules/` (entire directory)
|
||||
|
||||
- [ ] **Step 1: Update start-server.sh — change `index.js` to `server.js`**
|
||||
|
||||
Two lines to change:
|
||||
|
||||
Line 94: `env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" node server.js`
|
||||
|
||||
Line 100: `nohup env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" node server.js > "$LOG_FILE" 2>&1 &`
|
||||
|
||||
- [ ] **Step 2: Remove the gitignore exception for node_modules**
|
||||
|
||||
In `.gitignore`, delete line 6: `!skills/brainstorming/scripts/node_modules/`
|
||||
|
||||
- [ ] **Step 3: Delete old files**
|
||||
|
||||
```bash
|
||||
git rm skills/brainstorming/scripts/index.js
|
||||
git rm skills/brainstorming/scripts/package.json
|
||||
git rm skills/brainstorming/scripts/package-lock.json
|
||||
git rm -r skills/brainstorming/scripts/node_modules/
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run both test suites**
|
||||
|
||||
Run: `cd tests/brainstorm-server && node ws-protocol.test.js && node server.test.js`
|
||||
Expected: All tests pass
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/brainstorming/scripts/ .gitignore
|
||||
git commit -m "Remove vendored node_modules, swap to zero-dep server.js"
|
||||
```
|
||||
|
||||
### Task 4: Manual smoke test
|
||||
|
||||
- [ ] **Step 1: Start the server manually**
|
||||
|
||||
```bash
|
||||
cd skills/brainstorming/scripts
|
||||
BRAINSTORM_DIR=/tmp/brainstorm-smoke BRAINSTORM_PORT=9876 node server.js
|
||||
```
|
||||
|
||||
Expected: `server-started` JSON printed with port 9876
|
||||
|
||||
- [ ] **Step 2: Open browser to http://localhost:9876**
|
||||
|
||||
Expected: Waiting page with "Waiting for Claude to push a screen..."
|
||||
|
||||
- [ ] **Step 3: Write an HTML file to the screen directory**
|
||||
|
||||
```bash
|
||||
echo '<h2>Hello from smoke test</h2>' > /tmp/brainstorm-smoke/test.html
|
||||
```
|
||||
|
||||
Expected: Browser reloads and shows "Hello from smoke test" wrapped in frame template
|
||||
|
||||
- [ ] **Step 4: Verify WebSocket works — check browser console**
|
||||
|
||||
Open browser dev tools. The WebSocket connection should show as connected (no errors in console). The frame template's status indicator should show "Connected".
|
||||
|
||||
- [ ] **Step 5: Stop server with Ctrl-C, clean up**
|
||||
|
||||
```bash
|
||||
rm -rf /tmp/brainstorm-smoke
|
||||
```
|
||||
566
docs/superpowers/plans/2026-03-23-codex-app-compatibility.md
Normal file
566
docs/superpowers/plans/2026-03-23-codex-app-compatibility.md
Normal file
@@ -0,0 +1,566 @@
|
||||
# Codex App Compatibility 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 `using-git-worktrees`, `finishing-a-development-branch`, and related skills work in the Codex App's sandboxed worktree environment without breaking existing behavior.
|
||||
|
||||
**Architecture:** Read-only environment detection (`git-dir` vs `git-common-dir`) at the start of two skills. If already in a linked worktree, skip creation. If on detached HEAD, emit a handoff payload instead of the 4-option menu. Sandbox fallback catches permission errors during worktree creation.
|
||||
|
||||
**Tech Stack:** Git, Markdown (skill files are instruction documents, not executable code)
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-03-23-codex-app-compatibility-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| File | Responsibility | Action |
|
||||
|---|---|---|
|
||||
| `skills/using-git-worktrees/SKILL.md` | Worktree creation + isolation | Add Step 0 detection + sandbox fallback |
|
||||
| `skills/finishing-a-development-branch/SKILL.md` | Branch finishing workflow | Add Step 1.5 detection + cleanup guard |
|
||||
| `skills/subagent-driven-development/SKILL.md` | Plan execution with subagents | Update Integration description |
|
||||
| `skills/executing-plans/SKILL.md` | Plan execution inline | Update Integration description |
|
||||
| `skills/using-superpowers/references/codex-tools.md` | Codex platform reference | Add detection + finishing docs |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add Step 0 to `using-git-worktrees`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-git-worktrees/SKILL.md:14-15` (insert after Overview, before Directory Selection Process)
|
||||
|
||||
- [ ] **Step 1: Read the current skill file**
|
||||
|
||||
Read `skills/using-git-worktrees/SKILL.md` in full. Identify the exact insertion point: after the "Announce at start" line (line 14) and before "## Directory Selection Process" (line 16).
|
||||
|
||||
- [ ] **Step 2: Insert Step 0 section**
|
||||
|
||||
Insert the following between the Overview section and "## Directory Selection Process":
|
||||
|
||||
```markdown
|
||||
## Step 0: Check if Already in an Isolated Workspace
|
||||
|
||||
Before creating a worktree, check if one already exists:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
**If `GIT_DIR` differs from `GIT_COMMON`:** You are already inside a linked worktree (created by the Codex App, Claude Code's Agent tool, a previous skill run, or the user). Do NOT create another worktree. Instead:
|
||||
|
||||
1. Run project setup (auto-detect package manager as in "Run Project Setup" below)
|
||||
2. Verify clean baseline (run tests as in "Verify Clean Baseline" below)
|
||||
3. Report with branch state:
|
||||
- On a branch: "Already in an isolated workspace at `<path>` on branch `<name>`. Tests passing. Ready to implement."
|
||||
- Detached HEAD: "Already in an isolated workspace at `<path>` (detached HEAD, externally managed). Tests passing. Note: branch creation needed at finish time. Ready to implement."
|
||||
|
||||
After reporting, STOP. Do not continue to Directory Selection or Creation Steps.
|
||||
|
||||
**If `GIT_DIR` equals `GIT_COMMON`:** Proceed with the full worktree creation flow below.
|
||||
|
||||
**Sandbox fallback:** If you proceed to Creation Steps but `git worktree add -b` fails with a permission error (e.g., "Operation not permitted"), treat this as a late-detected restricted environment. Fall back to the behavior above — run setup and baseline tests in the current directory, report accordingly, and STOP.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the insertion**
|
||||
|
||||
Read the file again. Confirm:
|
||||
- Step 0 appears between Overview and Directory Selection Process
|
||||
- The rest of the file (Directory Selection, Safety Verification, Creation Steps, etc.) is unchanged
|
||||
- No duplicate sections or broken markdown
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-git-worktrees/SKILL.md
|
||||
git commit -m "feat(using-git-worktrees): add Step 0 environment detection (PRI-823)
|
||||
|
||||
Skip worktree creation when already in a linked worktree. Includes
|
||||
sandbox fallback for permission errors on git worktree add."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Update `using-git-worktrees` Integration section
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-git-worktrees/SKILL.md:211-215` (Integration > Called by)
|
||||
|
||||
- [ ] **Step 1: Update the three "Called by" entries**
|
||||
|
||||
Change lines 212-214 from:
|
||||
|
||||
```markdown
|
||||
- **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
|
||||
```
|
||||
|
||||
To:
|
||||
|
||||
```markdown
|
||||
- **brainstorming** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **subagent-driven-development** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
- **executing-plans** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the Integration section**
|
||||
|
||||
Read the Integration section. Confirm all three entries are updated, "Pairs with" is unchanged.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-git-worktrees/SKILL.md
|
||||
git commit -m "docs(using-git-worktrees): update Integration descriptions (PRI-823)
|
||||
|
||||
Clarify that skill ensures a workspace exists, not that it always creates one."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Add Step 1.5 to `finishing-a-development-branch`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/finishing-a-development-branch/SKILL.md:38` (insert after Step 1, before Step 2)
|
||||
|
||||
- [ ] **Step 1: Read the current skill file**
|
||||
|
||||
Read `skills/finishing-a-development-branch/SKILL.md` in full. Identify the insertion point: after "**If tests pass:** Continue to Step 2." (line 38) and before "### Step 2: Determine Base Branch" (line 40).
|
||||
|
||||
- [ ] **Step 2: Insert Step 1.5 section**
|
||||
|
||||
Insert the following between Step 1 and Step 2:
|
||||
|
||||
```markdown
|
||||
### Step 1.5: Detect Environment
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
**Path A — `GIT_DIR` differs from `GIT_COMMON` AND `BRANCH` is empty (externally managed worktree, detached HEAD):**
|
||||
|
||||
First, ensure all work is staged and committed (`git add` + `git commit`).
|
||||
|
||||
Then present this to the user (do NOT present the 4-option menu):
|
||||
|
||||
```
|
||||
Implementation complete. All tests passing.
|
||||
Current HEAD: <full-commit-sha>
|
||||
|
||||
This workspace is externally managed (detached HEAD).
|
||||
I cannot create branches, push, or open PRs from here.
|
||||
|
||||
⚠ These commits are on a detached HEAD. If you do not create a branch,
|
||||
they may be lost when this workspace is cleaned up.
|
||||
|
||||
If your host application provides these controls:
|
||||
- "Create branch" — to name a branch, then commit/push/PR
|
||||
- "Hand off to local" — to move changes to your local checkout
|
||||
|
||||
Suggested branch name: <ticket-id/short-description>
|
||||
Suggested commit message: <summary-of-work>
|
||||
```
|
||||
|
||||
Branch name: use ticket ID if available (e.g., `pri-823/codex-compat`), otherwise slugify the first 5 words of the plan title, otherwise omit. Avoid sensitive content in branch names.
|
||||
|
||||
Skip to Step 5 (cleanup is a no-op — see guard below).
|
||||
|
||||
**Path B — `GIT_DIR` differs from `GIT_COMMON` AND `BRANCH` exists (externally managed worktree, named branch):**
|
||||
|
||||
Proceed to Step 2 and present the 4-option menu as normal.
|
||||
|
||||
**Path C — `GIT_DIR` equals `GIT_COMMON` (normal environment):**
|
||||
|
||||
Proceed to Step 2 and present the 4-option menu as normal.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the insertion**
|
||||
|
||||
Read the file again. Confirm:
|
||||
- Step 1.5 appears between Step 1 and Step 2
|
||||
- Steps 2-5 are unchanged
|
||||
- Path A handoff includes commit SHA and data loss warning
|
||||
- Paths B and C proceed to Step 2 normally
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/finishing-a-development-branch/SKILL.md
|
||||
git commit -m "feat(finishing-a-development-branch): add Step 1.5 environment detection (PRI-823)
|
||||
|
||||
Detect externally managed worktrees with detached HEAD and emit handoff
|
||||
payload instead of 4-option menu. Includes commit SHA and data loss warning."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Add Step 5 cleanup guard to `finishing-a-development-branch`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/finishing-a-development-branch/SKILL.md` (Step 5: Cleanup Worktree — find by section heading, line numbers will have shifted after Task 3)
|
||||
|
||||
- [ ] **Step 1: Read the current Step 5 section**
|
||||
|
||||
Find the "### Step 5: Cleanup Worktree" section in `skills/finishing-a-development-branch/SKILL.md` (line numbers will have shifted after Task 3's insertion). The current Step 5 is:
|
||||
|
||||
```markdown
|
||||
### Step 5: Cleanup Worktree
|
||||
|
||||
**For Options 1, 2, 4:**
|
||||
|
||||
Check if in worktree:
|
||||
```bash
|
||||
git worktree list | grep $(git branch --show-current)
|
||||
```
|
||||
|
||||
If yes:
|
||||
```bash
|
||||
git worktree remove <worktree-path>
|
||||
```
|
||||
|
||||
**For Option 3:** Keep worktree.
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add the cleanup guard before existing logic**
|
||||
|
||||
Replace the Step 5 section with:
|
||||
|
||||
```markdown
|
||||
### Step 5: Cleanup Worktree
|
||||
|
||||
**First, check if worktree is externally managed:**
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
If `GIT_DIR` differs from `GIT_COMMON`: skip worktree removal — the host environment owns this workspace.
|
||||
|
||||
**Otherwise, for Options 1 and 4:**
|
||||
|
||||
Check if in worktree:
|
||||
```bash
|
||||
git worktree list | grep $(git branch --show-current)
|
||||
```
|
||||
|
||||
If yes:
|
||||
```bash
|
||||
git worktree remove <worktree-path>
|
||||
```
|
||||
|
||||
**For Option 3:** Keep worktree.
|
||||
```
|
||||
|
||||
Note: the original text said "For Options 1, 2, 4" but the Quick Reference table and Common Mistakes section say "Options 1 & 4 only." This edit aligns Step 5 with those sections.
|
||||
|
||||
- [ ] **Step 3: Verify the replacement**
|
||||
|
||||
Read Step 5. Confirm:
|
||||
- Cleanup guard (re-detection) appears first
|
||||
- Existing removal logic preserved for non-externally-managed worktrees
|
||||
- "Options 1 and 4" (not "1, 2, 4") matches Quick Reference and Common Mistakes
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/finishing-a-development-branch/SKILL.md
|
||||
git commit -m "feat(finishing-a-development-branch): add Step 5 cleanup guard (PRI-823)
|
||||
|
||||
Re-detect externally managed worktree at cleanup time and skip removal.
|
||||
Also fixes pre-existing inconsistency: cleanup now correctly says
|
||||
Options 1 and 4 only, matching Quick Reference and Common Mistakes."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: Update Integration lines in `subagent-driven-development` and `executing-plans`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/subagent-driven-development/SKILL.md:268`
|
||||
- Modify: `skills/executing-plans/SKILL.md:68`
|
||||
|
||||
- [ ] **Step 1: Update `subagent-driven-development`**
|
||||
|
||||
Change line 268 from:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
To:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update `executing-plans`**
|
||||
|
||||
Change line 68 from:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
To:
|
||||
```
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify both files**
|
||||
|
||||
Read line 268 of `skills/subagent-driven-development/SKILL.md` and line 68 of `skills/executing-plans/SKILL.md`. Confirm both say "Ensures isolated workspace (creates one or verifies existing)".
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/subagent-driven-development/SKILL.md skills/executing-plans/SKILL.md
|
||||
git commit -m "docs(sdd, executing-plans): update worktree Integration descriptions (PRI-823)
|
||||
|
||||
Clarify that using-git-worktrees ensures a workspace exists rather than
|
||||
always creating one."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 6: Add environment detection docs to `codex-tools.md`
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-superpowers/references/codex-tools.md:25` (append at end)
|
||||
|
||||
- [ ] **Step 1: Read the current file**
|
||||
|
||||
Read `skills/using-superpowers/references/codex-tools.md` in full. Confirm it ends at line 25-26 after the multi_agent section.
|
||||
|
||||
- [ ] **Step 2: Append two new sections**
|
||||
|
||||
Add at the end of the file:
|
||||
|
||||
```markdown
|
||||
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1.5 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Verify the additions**
|
||||
|
||||
Read the full file. Confirm:
|
||||
- Two new sections appear after the existing content
|
||||
- Bash code block renders correctly (not escaped)
|
||||
- Cross-references to Step 0 and Step 1.5 are present
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-superpowers/references/codex-tools.md
|
||||
git commit -m "docs(codex-tools): add environment detection and App finishing docs (PRI-823)
|
||||
|
||||
Document the git-dir vs git-common-dir detection pattern and the Codex
|
||||
App's native finishing flow for skills that need to adapt."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 7: Automated test — environment detection
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/codex-app-compat/test-environment-detection.sh`
|
||||
|
||||
- [ ] **Step 1: Create test directory**
|
||||
|
||||
```bash
|
||||
mkdir -p tests/codex-app-compat
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Write the detection test script**
|
||||
|
||||
Create `tests/codex-app-compat/test-environment-detection.sh`:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Test environment detection logic from PRI-823
|
||||
# Tests the git-dir vs git-common-dir comparison used by
|
||||
# using-git-worktrees Step 0 and finishing-a-development-branch Step 1.5
|
||||
|
||||
PASS=0
|
||||
FAIL=0
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
|
||||
log_pass() { echo " PASS: $1"; PASS=$((PASS + 1)); }
|
||||
log_fail() { echo " FAIL: $1"; FAIL=$((FAIL + 1)); }
|
||||
|
||||
# Helper: run detection and return "linked" or "normal"
|
||||
detect_worktree() {
|
||||
local git_dir git_common
|
||||
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)
|
||||
if [ "$git_dir" != "$git_common" ]; then
|
||||
echo "linked"
|
||||
else
|
||||
echo "normal"
|
||||
fi
|
||||
}
|
||||
|
||||
echo "=== Test 1: Normal repo detection ==="
|
||||
cd "$TEMP_DIR"
|
||||
git init test-repo > /dev/null 2>&1
|
||||
cd test-repo
|
||||
git commit --allow-empty -m "init" > /dev/null 2>&1
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "normal" ]; then
|
||||
log_pass "Normal repo detected as normal"
|
||||
else
|
||||
log_fail "Normal repo detected as '$result' (expected 'normal')"
|
||||
fi
|
||||
|
||||
echo "=== Test 2: Linked worktree detection ==="
|
||||
git worktree add "$TEMP_DIR/test-wt" -b test-branch > /dev/null 2>&1
|
||||
cd "$TEMP_DIR/test-wt"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "linked" ]; then
|
||||
log_pass "Linked worktree detected as linked"
|
||||
else
|
||||
log_fail "Linked worktree detected as '$result' (expected 'linked')"
|
||||
fi
|
||||
|
||||
echo "=== Test 3: Detached HEAD detection ==="
|
||||
git checkout --detach HEAD > /dev/null 2>&1
|
||||
branch=$(git branch --show-current)
|
||||
if [ -z "$branch" ]; then
|
||||
log_pass "Detached HEAD: branch is empty"
|
||||
else
|
||||
log_fail "Detached HEAD: branch is '$branch' (expected empty)"
|
||||
fi
|
||||
|
||||
echo "=== Test 4: Linked worktree + detached HEAD (Codex App simulation) ==="
|
||||
result=$(detect_worktree)
|
||||
branch=$(git branch --show-current)
|
||||
if [ "$result" = "linked" ] && [ -z "$branch" ]; then
|
||||
log_pass "Codex App simulation: linked + detached HEAD"
|
||||
else
|
||||
log_fail "Codex App simulation: result='$result', branch='$branch'"
|
||||
fi
|
||||
|
||||
echo "=== Test 5: Cleanup guard — linked worktree should NOT remove ==="
|
||||
cd "$TEMP_DIR/test-wt"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "linked" ]; then
|
||||
log_pass "Cleanup guard: linked worktree correctly detected (would skip removal)"
|
||||
else
|
||||
log_fail "Cleanup guard: expected 'linked', got '$result'"
|
||||
fi
|
||||
|
||||
echo "=== Test 6: Cleanup guard — main repo SHOULD remove ==="
|
||||
cd "$TEMP_DIR/test-repo"
|
||||
result=$(detect_worktree)
|
||||
if [ "$result" = "normal" ]; then
|
||||
log_pass "Cleanup guard: main repo correctly detected (would proceed with removal)"
|
||||
else
|
||||
log_fail "Cleanup guard: expected 'normal', got '$result'"
|
||||
fi
|
||||
|
||||
# Cleanup worktree before temp dir removal
|
||||
cd "$TEMP_DIR/test-repo"
|
||||
git worktree remove "$TEMP_DIR/test-wt" > /dev/null 2>&1 || true
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $PASS passed, $FAIL failed ==="
|
||||
if [ "$FAIL" -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Make it executable and run it**
|
||||
|
||||
```bash
|
||||
chmod +x tests/codex-app-compat/test-environment-detection.sh
|
||||
./tests/codex-app-compat/test-environment-detection.sh
|
||||
```
|
||||
|
||||
Expected output: 6 passed, 0 failed.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
git add tests/codex-app-compat/test-environment-detection.sh
|
||||
git commit -m "test: add environment detection tests for Codex App compat (PRI-823)
|
||||
|
||||
Tests git-dir vs git-common-dir comparison in normal repo, linked
|
||||
worktree, detached HEAD, and cleanup guard scenarios."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 8: Final verification
|
||||
|
||||
**Files:**
|
||||
- Read: all 5 modified skill files
|
||||
|
||||
- [ ] **Step 1: Run the automated detection tests**
|
||||
|
||||
```bash
|
||||
./tests/codex-app-compat/test-environment-detection.sh
|
||||
```
|
||||
|
||||
Expected: 6 passed, 0 failed.
|
||||
|
||||
- [ ] **Step 2: Read each modified file and verify changes**
|
||||
|
||||
Read each file end-to-end:
|
||||
- `skills/using-git-worktrees/SKILL.md` — Step 0 present, rest unchanged
|
||||
- `skills/finishing-a-development-branch/SKILL.md` — Step 1.5 present, cleanup guard present, rest unchanged
|
||||
- `skills/subagent-driven-development/SKILL.md` — line 268 updated
|
||||
- `skills/executing-plans/SKILL.md` — line 68 updated
|
||||
- `skills/using-superpowers/references/codex-tools.md` — two new sections at end
|
||||
|
||||
- [ ] **Step 3: Verify no unintended changes**
|
||||
|
||||
```bash
|
||||
git diff --stat HEAD~7
|
||||
```
|
||||
|
||||
Should show exactly 6 files changed (5 skill files + 1 test file). No other files modified.
|
||||
|
||||
- [ ] **Step 4: Run existing test suite**
|
||||
|
||||
If test runner exists:
|
||||
```bash
|
||||
# Run skill-triggering tests
|
||||
# Note: tests/skill-triggering/ was lifted into drill scenarios on 2026-05-06.
|
||||
# See evals/scenarios/triggering-*.yaml. The reference below is a dated artifact.
|
||||
./tests/skill-triggering/run-all.sh 2>/dev/null || echo "Skill triggering tests not available in this environment"
|
||||
|
||||
# Run SDD integration test
|
||||
./tests/claude-code/test-subagent-driven-development-integration.sh 2>/dev/null || echo "SDD integration test not available in this environment"
|
||||
```
|
||||
|
||||
Note: these tests require Claude Code with `--dangerously-skip-permissions`. If not available, document that regression tests should be run manually.
|
||||
866
docs/superpowers/plans/2026-04-06-worktree-rototill.md
Normal file
866
docs/superpowers/plans/2026-04-06-worktree-rototill.md
Normal file
@@ -0,0 +1,866 @@
|
||||
# Worktree Rototill Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Make superpowers defer to native harness worktree systems when available, fall back to manual git worktrees when not, and fix three known finishing bugs.
|
||||
|
||||
**Architecture:** Two skill files are rewritten (`using-git-worktrees`, `finishing-a-development-branch`), three files get one-line integration updates (`executing-plans`, `subagent-driven-development`, `writing-plans`). The core change is adding detection (`GIT_DIR != GIT_COMMON`) and a native-tool-first creation path. These are markdown skill instruction files, not application code — "tests" are agent behavior tests using the testing-skills-with-subagents TDD framework.
|
||||
|
||||
**Tech Stack:** Markdown (skill files), bash (test scripts), Claude Code CLI (`claude -p` for headless testing)
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-04-06-worktree-rototill-design.md`
|
||||
|
||||
---
|
||||
|
||||
### Task 1: GATE — TDD Validation of Step 1a (Native Tool Preference)
|
||||
|
||||
Step 1a is the load-bearing assumption of the entire design. If agents don't prefer native worktree tools over `git worktree add`, the spec fails. Validate this FIRST, before touching any skill files.
|
||||
|
||||
**Files:**
|
||||
- Create: `tests/claude-code/test-worktree-native-preference.sh`
|
||||
- Read: `skills/using-git-worktrees/SKILL.md` (current version, for RED baseline)
|
||||
- Read: `tests/claude-code/test-helpers.sh` (for `run_claude`, `assert_contains`, etc.)
|
||||
- Read: `skills/writing-skills/testing-skills-with-subagents.md` (TDD framework)
|
||||
|
||||
**This task is a gate.** If the GREEN phase fails after 2 REFACTOR iterations, STOP. Do not proceed to Task 2. Report back — the creation approach needs redesign.
|
||||
|
||||
- [ ] **Step 1: Write the RED baseline test script**
|
||||
|
||||
Create the test script that will run scenarios both WITHOUT and WITH the updated skill text. The RED phase runs against the current skill (which has no Step 1a).
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Test: Does the agent prefer native worktree tools (EnterWorktree) over git worktree add?
|
||||
# Framework: RED-GREEN-REFACTOR per testing-skills-with-subagents.md
|
||||
#
|
||||
# RED: Current skill has no native tool preference. Agent should use git worktree add.
|
||||
# GREEN: Updated skill has Step 1a. Agent should use EnterWorktree on Claude Code.
|
||||
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/test-helpers.sh"
|
||||
|
||||
# Pressure scenario: realistic implementation task where agent needs isolation
|
||||
SCENARIO='IMPORTANT: This is a real task. Choose and act.
|
||||
|
||||
You need to implement a small feature (add a "version" field to package.json).
|
||||
This should be done in an isolated workspace to protect the main branch.
|
||||
|
||||
You have the using-git-worktrees skill available. Set up the isolated workspace now.
|
||||
Do NOT actually implement the feature — just set up the workspace and report what you did.
|
||||
|
||||
Respond with EXACTLY what tool/command you used to create the workspace.'
|
||||
|
||||
echo "=== Worktree Native Preference Test ==="
|
||||
echo ""
|
||||
|
||||
# Phase selection
|
||||
PHASE="${1:-red}"
|
||||
|
||||
if [ "$PHASE" = "red" ]; then
|
||||
echo "--- RED PHASE: Running WITHOUT Step 1a (current skill) ---"
|
||||
echo "Expected: Agent uses 'git worktree add' (no native tool awareness)"
|
||||
echo ""
|
||||
|
||||
test_dir=$(create_test_project)
|
||||
cd "$test_dir"
|
||||
git init && git commit --allow-empty -m "init"
|
||||
mkdir -p .worktrees
|
||||
|
||||
output=$(run_claude "$SCENARIO" 120)
|
||||
|
||||
echo "Agent output:"
|
||||
echo "$output"
|
||||
echo ""
|
||||
|
||||
# RED expectation: agent uses git worktree add (current behavior)
|
||||
if echo "$output" | grep -qi "EnterWorktree"; then
|
||||
echo "[UNEXPECTED] Agent used EnterWorktree WITHOUT Step 1a — skill may not be needed"
|
||||
echo "Investigate: is Claude Code's default behavior already correct?"
|
||||
else
|
||||
echo "[RED CONFIRMED] Agent did NOT use EnterWorktree"
|
||||
assert_contains "$output" "git worktree" "Agent used git worktree (expected in RED)"
|
||||
fi
|
||||
|
||||
cleanup_test_project "$test_dir"
|
||||
|
||||
elif [ "$PHASE" = "green" ]; then
|
||||
echo "--- GREEN PHASE: Running WITH Step 1a (updated skill) ---"
|
||||
echo "Expected: Agent uses EnterWorktree instead of git worktree add"
|
||||
echo ""
|
||||
|
||||
test_dir=$(create_test_project)
|
||||
cd "$test_dir"
|
||||
git init && git commit --allow-empty -m "init"
|
||||
|
||||
output=$(run_claude "$SCENARIO" 120)
|
||||
|
||||
echo "Agent output:"
|
||||
echo "$output"
|
||||
echo ""
|
||||
|
||||
# GREEN expectation: agent uses EnterWorktree
|
||||
assert_contains "$output" "EnterWorktree" "Agent used native EnterWorktree tool"
|
||||
assert_not_contains "$output" "git worktree add" "Agent did NOT fall back to git worktree add"
|
||||
|
||||
cleanup_test_project "$test_dir"
|
||||
|
||||
elif [ "$PHASE" = "pressure" ]; then
|
||||
echo "--- PRESSURE PHASE: Multiple pressures to skip native tools ---"
|
||||
echo ""
|
||||
|
||||
PRESSURE_SCENARIO='IMPORTANT: This is a real task. Choose and act.
|
||||
|
||||
You need to set up an isolated workspace URGENTLY. Production is impacted and
|
||||
the fix needs to go in a worktree. You know git worktree add works reliably.
|
||||
The .worktrees/ directory already exists and is gitignored.
|
||||
|
||||
You have the using-git-worktrees skill. Set up the workspace NOW.
|
||||
Speed matters. Report EXACTLY what tool/command you used.'
|
||||
|
||||
test_dir=$(create_test_project)
|
||||
cd "$test_dir"
|
||||
git init && git commit --allow-empty -m "init"
|
||||
mkdir -p .worktrees
|
||||
echo ".worktrees/" >> .gitignore
|
||||
|
||||
output=$(run_claude "$PRESSURE_SCENARIO" 120)
|
||||
|
||||
echo "Agent output:"
|
||||
echo "$output"
|
||||
echo ""
|
||||
|
||||
# Should STILL use EnterWorktree even under pressure
|
||||
assert_contains "$output" "EnterWorktree" "Agent used native tool even under time pressure"
|
||||
assert_not_contains "$output" "git worktree add" "Agent resisted falling back to git despite pressure"
|
||||
|
||||
cleanup_test_project "$test_dir"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Test Complete ==="
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run RED phase — confirm agent uses git worktree add today**
|
||||
|
||||
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh red`
|
||||
|
||||
Expected: `[RED CONFIRMED] Agent did NOT use EnterWorktree` — agent uses `git worktree add` because current skill has no native tool preference.
|
||||
|
||||
Document the agent's exact output and any rationalizations verbatim. This is the baseline failure the skill must fix.
|
||||
|
||||
- [ ] **Step 3: If RED confirmed, proceed. Write the Step 1a skill text.**
|
||||
|
||||
Create a temporary test version of the skill with ONLY the Step 1a addition (minimal change to isolate the variable). Add this section to the top of the skill's creation instructions, BEFORE the existing directory selection process:
|
||||
|
||||
```markdown
|
||||
## Step 1: Create Isolated Workspace
|
||||
|
||||
**You have two mechanisms. Try them in this order.**
|
||||
|
||||
### 1a. Native Worktree Tools (preferred)
|
||||
|
||||
If your platform provides a worktree or workspace-isolation tool, use it. You know your own toolkit — the skill does not need to name specific tools. Native tools handle directory placement, branch creation, and cleanup automatically.
|
||||
|
||||
After using a native tool, skip to Step 3 (Project Setup).
|
||||
|
||||
### 1b. Git Worktree Fallback
|
||||
|
||||
If no native tool is available, create a worktree manually using git.
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Run GREEN phase — confirm agent now uses EnterWorktree**
|
||||
|
||||
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh green`
|
||||
|
||||
Expected: `[PASS] Agent used native EnterWorktree tool`
|
||||
|
||||
If FAIL: Document the agent's exact output and rationalizations. This is a REFACTOR signal — the Step 1a text needs revision. Try up to 2 REFACTOR iterations. If still failing after 2 iterations, STOP and report back.
|
||||
|
||||
- [ ] **Step 5: Run PRESSURE phase — confirm agent resists fallback under pressure**
|
||||
|
||||
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh pressure`
|
||||
|
||||
Expected: `[PASS] Agent used native tool even under time pressure`
|
||||
|
||||
If FAIL: Document rationalizations verbatim. Add explicit counters to Step 1a text (e.g., a Red Flag entry: "Never use git worktree add when your platform provides a native worktree tool"). Re-run.
|
||||
|
||||
- [ ] **Step 6: Commit test script**
|
||||
|
||||
```bash
|
||||
git add tests/claude-code/test-worktree-native-preference.sh
|
||||
git commit -m "test: add RED/GREEN validation for native worktree preference (PRI-974)
|
||||
|
||||
Gate test for Step 1a — validates agents prefer EnterWorktree over
|
||||
git worktree add on Claude Code. Must pass before skill rewrite."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 2: Rewrite `using-git-worktrees` SKILL.md
|
||||
|
||||
Full rewrite of the creation skill. Replaces the existing file entirely.
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/using-git-worktrees/SKILL.md` (full rewrite, 219 lines → ~210 lines)
|
||||
|
||||
**Depends on:** Task 1 GREEN passing.
|
||||
|
||||
- [ ] **Step 1: Write the complete new SKILL.md**
|
||||
|
||||
Replace the entire contents of `skills/using-git-worktrees/SKILL.md` with:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: using-git-worktrees
|
||||
description: Use when starting feature work that needs isolation from current workspace or before executing implementation plans - ensures an isolated workspace exists via native tools or git worktree fallback
|
||||
---
|
||||
|
||||
# Using Git Worktrees
|
||||
|
||||
## Overview
|
||||
|
||||
Ensure work happens in an isolated workspace. Prefer your platform's native worktree tools. Fall back to manual git worktrees only when no native tool is available.
|
||||
|
||||
**Core principle:** Detect existing isolation first. Then use native tools. Then fall back to git. Never fight the harness.
|
||||
|
||||
**Announce at start:** "I'm using the using-git-worktrees skill to set up an isolated workspace."
|
||||
|
||||
## Step 0: Detect Existing Isolation
|
||||
|
||||
**Before creating anything, check if you are already in an isolated workspace.**
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
**Submodule guard:** `GIT_DIR != GIT_COMMON` is also true inside git submodules. Before concluding "already in a worktree," verify you are not in a submodule:
|
||||
|
||||
```bash
|
||||
# If this returns a path, you're in a submodule, not a worktree — proceed to Step 1
|
||||
git rev-parse --show-superproject-working-tree 2>/dev/null
|
||||
```
|
||||
|
||||
**If `GIT_DIR != GIT_COMMON` (and not a submodule):** You are already in a linked worktree. Skip to Step 3 (Project Setup). Do NOT create another worktree.
|
||||
|
||||
Report with branch state:
|
||||
- On a branch: "Already in isolated workspace at `<path>` on branch `<name>`."
|
||||
- Detached HEAD: "Already in isolated workspace at `<path>` (detached HEAD, externally managed). Branch creation needed at finish time."
|
||||
|
||||
**If `GIT_DIR == GIT_COMMON` (or in a submodule):** You are in a normal repo checkout.
|
||||
|
||||
Has the user already indicated their worktree preference in your instructions? If not, ask for consent before creating a worktree:
|
||||
|
||||
> "Would you like me to set up an isolated worktree? It protects your current branch from changes."
|
||||
|
||||
Honor any existing declared preference without asking. If the user declines consent, work in place and skip to Step 3.
|
||||
|
||||
## Step 1: Create Isolated Workspace
|
||||
|
||||
**You have two mechanisms. Try them in this order.**
|
||||
|
||||
### 1a. Native Worktree Tools (preferred)
|
||||
|
||||
If your platform provides a worktree or workspace-isolation tool, use it. You know your own toolkit — the skill does not need to name specific tools. Native tools handle directory placement, branch creation, and cleanup automatically.
|
||||
|
||||
After using a native tool, skip to Step 3 (Project Setup).
|
||||
|
||||
### 1b. Git Worktree Fallback
|
||||
|
||||
If no native tool is available, create a worktree manually using git.
|
||||
|
||||
#### Directory Selection
|
||||
|
||||
Follow this priority order:
|
||||
|
||||
1. **Check your instructions for a worktree directory preference.** If specified, use it without asking.
|
||||
|
||||
2. **Check existing project-local directories:**
|
||||
```bash
|
||||
ls -d .worktrees 2>/dev/null # Preferred (hidden)
|
||||
ls -d worktrees 2>/dev/null # Alternative
|
||||
```
|
||||
If found, use that directory. If both exist, `.worktrees` wins.
|
||||
|
||||
3. **Default to `.worktrees/`.**
|
||||
|
||||
#### Safety Verification (project-local directories only)
|
||||
|
||||
**MUST verify directory is ignored before creating worktree:**
|
||||
|
||||
```bash
|
||||
git check-ignore -q .worktrees 2>/dev/null || git check-ignore -q worktrees 2>/dev/null
|
||||
```
|
||||
|
||||
**If NOT ignored:** Add to .gitignore, commit the change, then proceed.
|
||||
|
||||
**Why critical:** Prevents accidentally committing worktree contents to repository.
|
||||
|
||||
#### Create the Worktree
|
||||
|
||||
```bash
|
||||
# Determine path based on chosen location
|
||||
path="$LOCATION/$BRANCH_NAME"
|
||||
|
||||
git worktree add "$path" -b "$BRANCH_NAME"
|
||||
cd "$path"
|
||||
```
|
||||
|
||||
#### Hooks Awareness
|
||||
|
||||
Git worktrees do not inherit the parent repo's hooks directory. After creating the worktree, symlink hooks from the main repo if they exist:
|
||||
|
||||
```bash
|
||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||
if [ -d "$MAIN_ROOT/.git/hooks" ]; then
|
||||
ln -sf "$MAIN_ROOT/.git/hooks" "$path/.git/hooks"
|
||||
fi
|
||||
```
|
||||
|
||||
This prevents pre-commit checks, linters, and other hooks from silently stopping when work moves to a worktree.
|
||||
|
||||
**Sandbox fallback:** If `git worktree add` fails with a permission error (sandbox denial), treat this as a restricted environment. Skip creation, run setup and baseline tests in the current directory, report accordingly.
|
||||
|
||||
## Step 3: Project Setup
|
||||
|
||||
Auto-detect and run appropriate setup:
|
||||
|
||||
```bash
|
||||
# Node.js
|
||||
if [ -f package.json ]; then npm install; fi
|
||||
|
||||
# Rust
|
||||
if [ -f Cargo.toml ]; then cargo build; fi
|
||||
|
||||
# Python
|
||||
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||
if [ -f pyproject.toml ]; then poetry install; fi
|
||||
|
||||
# Go
|
||||
if [ -f go.mod ]; then go mod download; fi
|
||||
```
|
||||
|
||||
## Step 4: Verify Clean Baseline
|
||||
|
||||
Run tests to ensure workspace starts clean:
|
||||
|
||||
```bash
|
||||
# Use project-appropriate command
|
||||
npm test / cargo test / pytest / go test ./...
|
||||
```
|
||||
|
||||
**If tests fail:** Report failures, ask whether to proceed or investigate.
|
||||
|
||||
**If tests pass:** Report ready.
|
||||
|
||||
### Report
|
||||
|
||||
```
|
||||
Worktree ready at <full-path>
|
||||
Tests passing (<N> tests, 0 failures)
|
||||
Ready to implement <feature-name>
|
||||
```
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Situation | Action |
|
||||
|-----------|--------|
|
||||
| Already in linked worktree | Skip creation (Step 0) |
|
||||
| In a submodule | Treat as normal repo (Step 0 guard) |
|
||||
| Native worktree tool available | Use it (Step 1a) |
|
||||
| No native tool | Git worktree fallback (Step 1b) |
|
||||
| `.worktrees/` exists | Use it (verify ignored) |
|
||||
| `worktrees/` exists | Use it (verify ignored) |
|
||||
| Both exist | Use `.worktrees/` |
|
||||
| Neither exists | Check instruction file, then default `.worktrees/` |
|
||||
| Directory not ignored | Add to .gitignore + commit |
|
||||
| Permission error on create | Sandbox fallback, work in place |
|
||||
| Tests fail during baseline | Report failures + ask |
|
||||
| No package.json/Cargo.toml | Skip dependency install |
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
### Fighting the harness
|
||||
|
||||
- **Problem:** Using `git worktree add` when the platform already provides isolation
|
||||
- **Fix:** Step 0 detects existing isolation. Step 1a defers to native tools.
|
||||
|
||||
### Skipping detection
|
||||
|
||||
- **Problem:** Creating a nested worktree inside an existing one
|
||||
- **Fix:** Always run Step 0 before creating anything
|
||||
|
||||
### Skipping ignore verification
|
||||
|
||||
- **Problem:** Worktree contents get tracked, pollute git status
|
||||
- **Fix:** Always use `git check-ignore` before creating project-local worktree
|
||||
|
||||
### Assuming directory location
|
||||
|
||||
- **Problem:** Creates inconsistency, violates project conventions
|
||||
- **Fix:** Follow priority: existing > instruction file > default
|
||||
|
||||
### Proceeding with failing tests
|
||||
|
||||
- **Problem:** Can't distinguish new bugs from pre-existing issues
|
||||
- **Fix:** Report failures, get explicit permission to proceed
|
||||
|
||||
## Red Flags
|
||||
|
||||
**Never:**
|
||||
- Create a worktree when Step 0 detects existing isolation
|
||||
- Use git commands when a native worktree tool is available
|
||||
- Create worktree without verifying it's ignored (project-local)
|
||||
- Skip baseline test verification
|
||||
- Proceed with failing tests without asking
|
||||
|
||||
**Always:**
|
||||
- Run Step 0 detection first
|
||||
- Prefer native tools over git fallback
|
||||
- Follow directory priority: existing > instruction file > default
|
||||
- Verify directory is ignored for project-local
|
||||
- Auto-detect and run project setup
|
||||
- Verify clean test baseline
|
||||
- Symlink hooks after creating worktree via 1b
|
||||
|
||||
## Integration
|
||||
|
||||
**Called by:**
|
||||
- **subagent-driven-development** - Ensures isolated workspace (creates one or verifies existing)
|
||||
- **executing-plans** - Ensures isolated workspace (creates one or verifies existing)
|
||||
- Any skill needing isolated workspace
|
||||
|
||||
**Pairs with:**
|
||||
- **finishing-a-development-branch** - REQUIRED for cleanup after work complete
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the file reads correctly**
|
||||
|
||||
Run: `wc -l skills/using-git-worktrees/SKILL.md`
|
||||
|
||||
Expected: Approximately 200-220 lines. Scan for any markdown formatting issues.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/using-git-worktrees/SKILL.md
|
||||
git commit -m "feat: rewrite using-git-worktrees with detect-and-defer (PRI-974)
|
||||
|
||||
Step 0: GIT_DIR != GIT_COMMON detection (skip if already isolated)
|
||||
Step 0 consent: opt-in prompt before creating worktree (#991)
|
||||
Step 1a: native tool preference (short, first, declarative)
|
||||
Step 1b: git worktree fallback with project-local directory policy
|
||||
Submodule guard prevents false detection
|
||||
Platform-neutral instruction file references (#1049)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 3: Rewrite `finishing-a-development-branch` SKILL.md
|
||||
|
||||
Full rewrite of the finishing skill. Adds environment detection, fixes three bugs, adds provenance-based cleanup.
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/finishing-a-development-branch/SKILL.md` (full rewrite, 201 lines → ~220 lines)
|
||||
|
||||
- [ ] **Step 1: Write the complete new SKILL.md**
|
||||
|
||||
Replace the entire contents of `skills/finishing-a-development-branch/SKILL.md` with:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: finishing-a-development-branch
|
||||
description: Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
|
||||
---
|
||||
|
||||
# Finishing a Development Branch
|
||||
|
||||
## Overview
|
||||
|
||||
Guide completion of development work by presenting clear options and handling chosen workflow.
|
||||
|
||||
**Core principle:** Verify tests → Detect environment → Present options → Execute choice → Clean up.
|
||||
|
||||
**Announce at start:** "I'm using the finishing-a-development-branch skill to complete this work."
|
||||
|
||||
## The Process
|
||||
|
||||
### Step 1: Verify Tests
|
||||
|
||||
**Before presenting options, verify tests pass:**
|
||||
|
||||
```bash
|
||||
# Run project's test suite
|
||||
npm test / cargo test / pytest / go test ./...
|
||||
```
|
||||
|
||||
**If tests fail:**
|
||||
```
|
||||
Tests failing (<N> failures). Must fix before completing:
|
||||
|
||||
[Show failures]
|
||||
|
||||
Cannot proceed with merge/PR until tests pass.
|
||||
```
|
||||
|
||||
Stop. Don't proceed to Step 2.
|
||||
|
||||
**If tests pass:** Continue to Step 2.
|
||||
|
||||
### Step 2: Detect Environment
|
||||
|
||||
**Determine workspace state before presenting options:**
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
```
|
||||
|
||||
This determines which menu to show and how cleanup works:
|
||||
|
||||
| State | Menu | Cleanup |
|
||||
|-------|------|---------|
|
||||
| `GIT_DIR == GIT_COMMON` (normal repo) | Standard 4 options | No worktree to clean up |
|
||||
| `GIT_DIR != GIT_COMMON`, named branch | Standard 4 options | Provenance-based (see Step 6) |
|
||||
| `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced 3 options (no merge) | No cleanup (externally managed) |
|
||||
|
||||
### Step 3: Determine Base Branch
|
||||
|
||||
```bash
|
||||
# Try common base branches
|
||||
git merge-base HEAD main 2>/dev/null || git merge-base HEAD master 2>/dev/null
|
||||
```
|
||||
|
||||
Or ask: "This branch split from main - is that correct?"
|
||||
|
||||
### Step 4: Present Options
|
||||
|
||||
**Normal repo and named-branch worktree — present exactly these 4 options:**
|
||||
|
||||
```
|
||||
Implementation complete. What would you like to do?
|
||||
|
||||
1. Merge back to <base-branch> locally
|
||||
2. Push and create a Pull Request
|
||||
3. Keep the branch as-is (I'll handle it later)
|
||||
4. Discard this work
|
||||
|
||||
Which option?
|
||||
```
|
||||
|
||||
**Detached HEAD — present exactly these 3 options:**
|
||||
|
||||
```
|
||||
Implementation complete. You're on a detached HEAD (externally managed workspace).
|
||||
|
||||
1. Push as new branch and create a Pull Request
|
||||
2. Keep as-is (I'll handle it later)
|
||||
3. Discard this work
|
||||
|
||||
Which option?
|
||||
```
|
||||
|
||||
**Don't add explanation** - keep options concise.
|
||||
|
||||
### Step 5: Execute Choice
|
||||
|
||||
#### Option 1: Merge Locally
|
||||
|
||||
```bash
|
||||
# Get main repo root for CWD safety
|
||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||
cd "$MAIN_ROOT"
|
||||
|
||||
# Merge first — verify success before removing anything
|
||||
git checkout <base-branch>
|
||||
git pull
|
||||
git merge <feature-branch>
|
||||
|
||||
# Verify tests on merged result
|
||||
<test command>
|
||||
|
||||
# Only after merge succeeds: remove worktree, then delete branch
|
||||
# (See Step 6 for worktree cleanup)
|
||||
git branch -d <feature-branch>
|
||||
```
|
||||
|
||||
Then: Cleanup worktree (Step 6)
|
||||
|
||||
#### Option 2: Push and Create PR
|
||||
|
||||
```bash
|
||||
# Push branch
|
||||
git push -u origin <feature-branch>
|
||||
|
||||
# Create PR
|
||||
gh pr create --title "<title>" --body "$(cat <<'EOF'
|
||||
## Summary
|
||||
<2-3 bullets of what changed>
|
||||
|
||||
## Test Plan
|
||||
- [ ] <verification steps>
|
||||
EOF
|
||||
)"
|
||||
```
|
||||
|
||||
**Do NOT clean up worktree** — user needs it alive to iterate on PR feedback.
|
||||
|
||||
#### Option 3: Keep As-Is
|
||||
|
||||
Report: "Keeping branch <name>. Worktree preserved at <path>."
|
||||
|
||||
**Don't cleanup worktree.**
|
||||
|
||||
#### Option 4: Discard
|
||||
|
||||
**Confirm first:**
|
||||
```
|
||||
This will permanently delete:
|
||||
- Branch <name>
|
||||
- All commits: <commit-list>
|
||||
- Worktree at <path>
|
||||
|
||||
Type 'discard' to confirm.
|
||||
```
|
||||
|
||||
Wait for exact confirmation.
|
||||
|
||||
If confirmed:
|
||||
```bash
|
||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||
cd "$MAIN_ROOT"
|
||||
```
|
||||
|
||||
Then: Cleanup worktree (Step 6), then force-delete branch:
|
||||
```bash
|
||||
git branch -D <feature-branch>
|
||||
```
|
||||
|
||||
### Step 6: Cleanup Workspace
|
||||
|
||||
**Only runs for Options 1 and 4.** Options 2 and 3 always preserve the worktree.
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
WORKTREE_PATH=$(git rev-parse --show-toplevel)
|
||||
```
|
||||
|
||||
**If `GIT_DIR == GIT_COMMON`:** Normal repo, no worktree to clean up. Done.
|
||||
|
||||
**If worktree path is under `.worktrees/` or `worktrees/`:** Superpowers created this worktree — we own cleanup.
|
||||
|
||||
```bash
|
||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||
cd "$MAIN_ROOT"
|
||||
git worktree remove "$WORKTREE_PATH"
|
||||
git worktree prune # Self-healing: clean up any stale registrations
|
||||
```
|
||||
|
||||
**Otherwise:** The host environment (harness) owns this workspace. Do NOT remove it. If your platform provides a workspace-exit tool, use it. Otherwise, leave the workspace in place.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Option | Merge | Push | Keep Worktree | Cleanup Branch |
|
||||
|--------|-------|------|---------------|----------------|
|
||||
| 1. Merge locally | yes | - | - | yes |
|
||||
| 2. Create PR | - | yes | yes | - |
|
||||
| 3. Keep as-is | - | - | yes | - |
|
||||
| 4. Discard | - | - | - | yes (force) |
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
**Skipping test verification**
|
||||
- **Problem:** Merge broken code, create failing PR
|
||||
- **Fix:** Always verify tests before offering options
|
||||
|
||||
**Open-ended questions**
|
||||
- **Problem:** "What should I do next?" is ambiguous
|
||||
- **Fix:** Present exactly 4 structured options (or 3 for detached HEAD)
|
||||
|
||||
**Cleaning up worktree for Option 2**
|
||||
- **Problem:** Remove worktree user needs for PR iteration
|
||||
- **Fix:** Only cleanup for Options 1 and 4
|
||||
|
||||
**Deleting branch before removing worktree**
|
||||
- **Problem:** `git branch -d` fails because worktree still references the branch
|
||||
- **Fix:** Merge first, remove worktree, then delete branch
|
||||
|
||||
**Running git worktree remove from inside the worktree**
|
||||
- **Problem:** Command fails silently when CWD is inside the worktree being removed
|
||||
- **Fix:** Always `cd` to main repo root before `git worktree remove`
|
||||
|
||||
**Cleaning up harness-owned worktrees**
|
||||
- **Problem:** Removing a worktree the harness created causes phantom state
|
||||
- **Fix:** Only clean up worktrees under `.worktrees/` or `worktrees/`
|
||||
|
||||
**No confirmation for discard**
|
||||
- **Problem:** Accidentally delete work
|
||||
- **Fix:** Require typed "discard" confirmation
|
||||
|
||||
## Red Flags
|
||||
|
||||
**Never:**
|
||||
- Proceed with failing tests
|
||||
- Merge without verifying tests on result
|
||||
- Delete work without confirmation
|
||||
- Force-push without explicit request
|
||||
- Remove a worktree before confirming merge success
|
||||
- Clean up worktrees you didn't create (provenance check)
|
||||
- Run `git worktree remove` from inside the worktree
|
||||
|
||||
**Always:**
|
||||
- Verify tests before offering options
|
||||
- Detect environment before presenting menu
|
||||
- Present exactly 4 options (or 3 for detached HEAD)
|
||||
- Get typed confirmation for Option 4
|
||||
- Clean up worktree for Options 1 & 4 only
|
||||
- `cd` to main repo root before worktree removal
|
||||
- Run `git worktree prune` after removal
|
||||
|
||||
## Integration
|
||||
|
||||
**Called by:**
|
||||
- **subagent-driven-development** (Step 7) - After all tasks complete
|
||||
- **executing-plans** (Step 5) - After all batches complete
|
||||
|
||||
**Pairs with:**
|
||||
- **using-git-worktrees** - Cleans up worktree created by that skill
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the file reads correctly**
|
||||
|
||||
Run: `wc -l skills/finishing-a-development-branch/SKILL.md`
|
||||
|
||||
Expected: Approximately 210-230 lines.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add skills/finishing-a-development-branch/SKILL.md
|
||||
git commit -m "feat: rewrite finishing-a-development-branch with detect-and-defer (PRI-974)
|
||||
|
||||
Step 2: environment detection (GIT_DIR != GIT_COMMON) before presenting menu
|
||||
Detached HEAD: reduced 3-option menu (no merge from detached HEAD)
|
||||
Provenance-based cleanup: .worktrees/ = ours, anything else = hands off
|
||||
Bug #940: Option 2 no longer cleans up worktree
|
||||
Bug #999: merge -> verify -> remove worktree -> delete branch
|
||||
Bug #238: cd to main repo root before git worktree remove
|
||||
Stale worktree pruning after removal (git worktree prune)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 4: Integration Updates
|
||||
|
||||
One-line changes to three files that reference `using-git-worktrees`.
|
||||
|
||||
**Files:**
|
||||
- Modify: `skills/executing-plans/SKILL.md:68`
|
||||
- Modify: `skills/subagent-driven-development/SKILL.md:268`
|
||||
- Modify: `skills/writing-plans/SKILL.md:16`
|
||||
|
||||
- [ ] **Step 1: Update executing-plans integration line**
|
||||
|
||||
In `skills/executing-plans/SKILL.md`, change line 68 from:
|
||||
|
||||
```markdown
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```markdown
|
||||
- **superpowers:using-git-worktrees** - Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Update subagent-driven-development integration line**
|
||||
|
||||
In `skills/subagent-driven-development/SKILL.md`, change line 268 from:
|
||||
|
||||
```markdown
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```markdown
|
||||
- **superpowers:using-git-worktrees** - Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Update writing-plans context line**
|
||||
|
||||
In `skills/writing-plans/SKILL.md`, change line 16 from:
|
||||
|
||||
```markdown
|
||||
**Context:** This should be run in a dedicated worktree (created by brainstorming skill).
|
||||
```
|
||||
|
||||
to:
|
||||
|
||||
```markdown
|
||||
**Context:** If working in an isolated worktree, it should have been created via the using-git-worktrees skill at execution time.
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Commit all three**
|
||||
|
||||
```bash
|
||||
git add skills/executing-plans/SKILL.md skills/subagent-driven-development/SKILL.md skills/writing-plans/SKILL.md
|
||||
git commit -m "fix: update worktree integration references across skills (PRI-974)
|
||||
|
||||
Remove REQUIRED language from executing-plans and subagent-driven-development.
|
||||
Consent and detection now live inside using-git-worktrees itself.
|
||||
Fix stale 'created by brainstorming' claim in writing-plans."
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Task 5: End-to-End Validation
|
||||
|
||||
Verify the full rewritten skills work together. Run the existing test suite plus manual verification.
|
||||
|
||||
**Files:**
|
||||
- Read: `tests/claude-code/run-skill-tests.sh`
|
||||
- Read: `skills/using-git-worktrees/SKILL.md` (verify final state)
|
||||
- Read: `skills/finishing-a-development-branch/SKILL.md` (verify final state)
|
||||
|
||||
- [ ] **Step 1: Run existing test suite**
|
||||
|
||||
Run: `cd tests/claude-code && bash run-skill-tests.sh`
|
||||
|
||||
Expected: All existing tests pass. If any fail, investigate — the integration changes (Task 4) may have broken a content assertion.
|
||||
|
||||
- [ ] **Step 2: Re-run Step 1a GREEN test**
|
||||
|
||||
Run: `cd tests/claude-code && bash test-worktree-native-preference.sh green`
|
||||
|
||||
Expected: PASS — agent still uses EnterWorktree with the final skill text (not just the minimal Step 1a addition from Task 1).
|
||||
|
||||
- [ ] **Step 3: Manual verification — read both rewritten skills end-to-end**
|
||||
|
||||
Read `skills/using-git-worktrees/SKILL.md` and `skills/finishing-a-development-branch/SKILL.md` in their entirety. Check:
|
||||
|
||||
1. No references to old behavior (hardcoded `CLAUDE.md`, interactive directory prompt, "REQUIRED" language)
|
||||
2. Step numbering is consistent within each file
|
||||
3. Quick Reference tables match the prose
|
||||
4. Integration sections cross-reference correctly
|
||||
5. No markdown formatting issues
|
||||
|
||||
- [ ] **Step 4: Verify git status is clean**
|
||||
|
||||
Run: `git status`
|
||||
|
||||
Expected: Clean working tree. All changes committed across Tasks 1-4.
|
||||
|
||||
- [ ] **Step 5: Final commit if any fixups needed**
|
||||
|
||||
If manual verification found issues, fix them and commit:
|
||||
|
||||
```bash
|
||||
git add -A
|
||||
git commit -m "fix: address review findings in worktree skill rewrite (PRI-974)"
|
||||
```
|
||||
|
||||
If no issues found, skip this step.
|
||||
1374
docs/superpowers/plans/2026-05-06-lift-drill-into-evals.md
Normal file
1374
docs/superpowers/plans/2026-05-06-lift-drill-into-evals.md
Normal file
File diff suppressed because it is too large
Load Diff
143
docs/superpowers/plans/2026-05-07-pi-extension-and-evals.md
Normal file
143
docs/superpowers/plans/2026-05-07-pi-extension-and-evals.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# Pi Extension and Evals Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add first-class Pi package support for Superpowers and add Pi as a Drill eval backend.
|
||||
|
||||
**Architecture:** The Pi package is declared in the root `package.json` and loads existing `skills/` plus a small Pi extension. The extension injects the `using-superpowers` bootstrap into provider context as a user-role message on session startup and after compaction, with Pi-specific tool mapping. Drill gains a `pi` backend, Pi session-log normalization, and tests.
|
||||
|
||||
**Tech Stack:** Pi TypeScript extension API, Node built-in test runner, Drill Python eval harness, pytest.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Pi package manifest and extension tests
|
||||
|
||||
**Files:**
|
||||
- Modify: `package.json`
|
||||
- Create: `tests/pi/test-pi-extension.mjs`
|
||||
|
||||
- [ ] **Step 1: Write failing package/extension tests**
|
||||
|
||||
Create `tests/pi/test-pi-extension.mjs` with tests that import `extensions/superpowers.ts`, register fake Pi handlers, and assert:
|
||||
- root `package.json` has `keywords` containing `pi-package`
|
||||
- root `package.json` has `pi.skills: ["./skills"]`
|
||||
- root `package.json` has `pi.extensions: ["./extensions/superpowers.ts"]`
|
||||
- the extension registers `resources_discover`, `session_start`, `session_compact`, `context`, and `agent_end`
|
||||
- startup `context` injects exactly one user-role bootstrap message
|
||||
- `agent_end` clears startup injection
|
||||
- `session_compact` re-enables injection
|
||||
- the extension does not register `session_before_compact`
|
||||
|
||||
- [ ] **Step 2: Run tests and verify RED**
|
||||
|
||||
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
|
||||
|
||||
Expected: FAIL because `extensions/superpowers.ts` does not exist and `package.json` lacks the `pi` manifest.
|
||||
|
||||
- [ ] **Step 3: Implement manifest fields**
|
||||
|
||||
Update `package.json` with `description`, `keywords`, `pi.extensions`, and `pi.skills` while preserving existing `name`, `version`, `type`, and `main`.
|
||||
|
||||
- [ ] **Step 4: Implement `extensions/superpowers.ts`**
|
||||
|
||||
Create a zero-runtime-dependency extension that:
|
||||
- locates the package root from `import.meta.url`
|
||||
- reads `skills/using-superpowers/SKILL.md`
|
||||
- strips YAML frontmatter
|
||||
- appends Pi-specific tool mapping
|
||||
- exposes `resources_discover` with the skills path
|
||||
- marks bootstrap pending on `session_start` and `session_compact`
|
||||
- injects a user-role bootstrap message in `context`
|
||||
- inserts post-compact bootstrap after leading `compactionSummary` messages
|
||||
- clears pending bootstrap on `agent_end`
|
||||
|
||||
- [ ] **Step 5: Run tests and verify GREEN**
|
||||
|
||||
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 2: Pi tool mapping reference
|
||||
|
||||
**Files:**
|
||||
- Create: `skills/using-superpowers/references/pi-tools.md`
|
||||
- Modify: `tests/pi/test-pi-extension.mjs`
|
||||
|
||||
- [ ] **Step 1: Write failing test for Pi reference doc**
|
||||
|
||||
Add assertions that `skills/using-superpowers/references/pi-tools.md` exists and documents mappings for `Skill`, `Task`, `TodoWrite`, and built-in tool names.
|
||||
|
||||
- [ ] **Step 2: Run tests and verify RED**
|
||||
|
||||
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
|
||||
|
||||
Expected: FAIL because `pi-tools.md` does not exist.
|
||||
|
||||
- [ ] **Step 3: Add Pi reference doc**
|
||||
|
||||
Create `skills/using-superpowers/references/pi-tools.md` explaining Pi-native skills, optional `pi-subagents`, no canonical todo/tasklist plugin, and built-in lowercase tools.
|
||||
|
||||
- [ ] **Step 4: Run tests and verify GREEN**
|
||||
|
||||
Run: `node --experimental-strip-types --test tests/pi/test-pi-extension.mjs`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 3: Drill Pi backend and session log normalization
|
||||
|
||||
**Files:**
|
||||
- Create: `evals/backends/pi.yaml`
|
||||
- Modify: `evals/drill/backend.py`
|
||||
- Modify: `evals/drill/engine.py`
|
||||
- Modify: `evals/drill/normalizer.py`
|
||||
- Modify: `evals/tests/test_backend.py`
|
||||
- Modify: `evals/tests/test_normalizer.py`
|
||||
|
||||
- [ ] **Step 1: Write failing backend/normalizer tests**
|
||||
|
||||
Add pytest coverage for:
|
||||
- `load_backend("pi")` returns `family == "pi"`
|
||||
- Pi backend command starts with `pi` and includes `-e ${SUPERPOWERS_ROOT}`
|
||||
- `_resolve_log_dir()` for Pi points under `~/.pi/agent/sessions`
|
||||
- `filter_pi_logs_by_cwd()` keeps only session files whose header `cwd` matches the scenario workdir
|
||||
- `normalize_pi_logs()` extracts `toolCall` blocks from Pi assistant session entries and maps built-in lowercase tools to canonical names
|
||||
|
||||
- [ ] **Step 2: Run tests and verify RED**
|
||||
|
||||
Run: `uv run pytest evals/tests/test_backend.py evals/tests/test_normalizer.py -q`
|
||||
|
||||
Expected: FAIL because the Pi backend and normalizer do not exist.
|
||||
|
||||
- [ ] **Step 3: Add `evals/backends/pi.yaml`**
|
||||
|
||||
Configure the backend to run `pi -e ${SUPERPOWERS_ROOT}`, use permissive TUI readiness, `/quit` shutdown, and Pi session log location.
|
||||
|
||||
- [ ] **Step 4: Implement Pi family support**
|
||||
|
||||
Update `Backend.family`, `Engine._resolve_log_dir`, `Engine._collect_tool_calls`, and `normalizer.py` with Pi log filtering and normalizing.
|
||||
|
||||
- [ ] **Step 5: Run tests and verify GREEN**
|
||||
|
||||
Run: `uv run pytest evals/tests/test_backend.py evals/tests/test_normalizer.py -q`
|
||||
|
||||
Expected: PASS.
|
||||
|
||||
### Task 4: Documentation and full verification
|
||||
|
||||
**Files:**
|
||||
- Modify: `README.md`
|
||||
- Modify: `evals/README.md`
|
||||
|
||||
- [ ] **Step 1: Document Pi install and eval backend**
|
||||
|
||||
Add Pi to README quickstart/install list and add backend entry/usage to `evals/README.md`.
|
||||
|
||||
- [ ] **Step 2: Run verification**
|
||||
|
||||
Run:
|
||||
```bash
|
||||
node --experimental-strip-types --test tests/pi/test-pi-extension.mjs
|
||||
uv run pytest evals/tests/test_backend.py evals/tests/test_setup.py evals/tests/test_normalizer.py -q
|
||||
```
|
||||
|
||||
Expected: all tests pass.
|
||||
@@ -0,0 +1,162 @@
|
||||
# Visual Brainstorming Refactor: Browser Displays, Terminal Commands
|
||||
|
||||
**Date:** 2026-02-19
|
||||
**Status:** Approved
|
||||
**Scope:** `lib/brainstorm-server/`, `skills/brainstorming/visual-companion.md`, `tests/brainstorm-server/`
|
||||
|
||||
## Problem
|
||||
|
||||
During visual brainstorming, Claude runs `wait-for-feedback.sh` as a background task and blocks on `TaskOutput(block=true, timeout=600s)`. This seizes the TUI entirely — the user cannot type to Claude while visual brainstorming is running. The browser becomes the only input channel.
|
||||
|
||||
Claude Code's execution model is turn-based. There is no way for Claude to listen on two channels simultaneously within a single turn. The blocking `TaskOutput` pattern was the wrong primitive — it simulates event-driven behavior the platform doesn't support.
|
||||
|
||||
## Design
|
||||
|
||||
### Core Model
|
||||
|
||||
**Browser = interactive display.** Shows mockups, lets the user click to select options. Selections are recorded server-side.
|
||||
|
||||
**Terminal = conversation channel.** Always unblocked, always available. The user talks to Claude here.
|
||||
|
||||
### The Loop
|
||||
|
||||
1. Claude writes an HTML file to the session directory
|
||||
2. Server detects it via chokidar, pushes WebSocket reload to the browser (unchanged)
|
||||
3. Claude ends its turn — tells the user to check the browser and respond in the terminal
|
||||
4. User looks at browser, optionally clicks to select an option, then types feedback in the terminal
|
||||
5. On the next turn, Claude reads `$SCREEN_DIR/.events` for the browser interaction stream (clicks, selections), merges with the terminal text
|
||||
6. Iterate or advance
|
||||
|
||||
No background tasks. No `TaskOutput` blocking. No polling scripts.
|
||||
|
||||
### Key Deletion: `wait-for-feedback.sh`
|
||||
|
||||
Deleted entirely. Its purpose was to bridge "server logs events to stdout" and "Claude needs to receive those events." The `.events` file replaces this — the server writes user interaction events directly, and Claude reads them with whatever file-reading mechanism the platform provides.
|
||||
|
||||
### Key Addition: `.events` File (Per-Screen Event Stream)
|
||||
|
||||
The server writes all user interaction events to `$SCREEN_DIR/.events`, one JSON object per line. This gives Claude the full interaction stream for the current screen — not just the final selection, but the user's exploration path (clicked A, then B, settled on C).
|
||||
|
||||
Example contents after a user explores options:
|
||||
|
||||
```jsonl
|
||||
{"type":"click","choice":"a","text":"Option A - Preset-First Wizard","timestamp":1706000101}
|
||||
{"type":"click","choice":"c","text":"Option C - Manual Config","timestamp":1706000108}
|
||||
{"type":"click","choice":"b","text":"Option B - Hybrid Approach","timestamp":1706000115}
|
||||
```
|
||||
|
||||
- Append-only within a screen. Each user event is appended as a new line.
|
||||
- The file is cleared (deleted) when chokidar detects a new HTML file (new screen pushed), preventing stale events from carrying over.
|
||||
- If the file doesn't exist when Claude reads it, no browser interaction occurred — Claude uses only the terminal text.
|
||||
- The file contains only user events (`click`, etc.) — not server lifecycle events (`server-started`, `screen-added`). This keeps it small and focused.
|
||||
- Claude can read the full stream to understand the user's exploration pattern, or just look at the last `choice` event for the final selection.
|
||||
|
||||
## Changes by File
|
||||
|
||||
### `index.js` (server)
|
||||
|
||||
**A. Write user events to `.events` file.**
|
||||
|
||||
In the WebSocket `message` handler, after logging the event to stdout: append the event as a JSON line to `$SCREEN_DIR/.events` via `fs.appendFileSync`. Only write user interaction events (those with `source: 'user-event'`), not server lifecycle events.
|
||||
|
||||
**B. Clear `.events` on new screen.**
|
||||
|
||||
In the chokidar `add` handler (new `.html` file detected), delete `$SCREEN_DIR/.events` if it exists. This is the definitive "new screen" signal — better than clearing on GET `/` which fires on every reload.
|
||||
|
||||
**C. Replace `wrapInFrame` content injection.**
|
||||
|
||||
The current regex anchors on `<div class="feedback-footer">`, which is being removed. Replace with a comment placeholder: remove the existing default content inside `#claude-content` (the `<h2>Visual Brainstorming</h2>` and subtitle paragraph) and replace with a single `<!-- CONTENT -->` marker. Content injection becomes `frameTemplate.replace('<!-- CONTENT -->', content)`. Simpler and won't break if template formatting changes.
|
||||
|
||||
### `frame-template.html` (UI frame)
|
||||
|
||||
**Remove:**
|
||||
- The `feedback-footer` div (textarea, Send button, label, `.feedback-row`)
|
||||
- Associated CSS (`.feedback-footer`, `.feedback-footer label`, `.feedback-row`, textarea and button styles within it)
|
||||
|
||||
**Add:**
|
||||
- `<!-- CONTENT -->` placeholder inside `#claude-content`, replacing the default text
|
||||
- A selection indicator bar where the footer was, with two states:
|
||||
- Default: "Click an option above, then return to the terminal"
|
||||
- After selection: "Option B selected — return to terminal to continue"
|
||||
- CSS for the indicator bar (subtle, similar visual weight to the existing header)
|
||||
|
||||
**Keep unchanged:**
|
||||
- Header bar with "Brainstorm Companion" title and connection status
|
||||
- `.main` wrapper and `#claude-content` container
|
||||
- All component CSS (`.options`, `.cards`, `.mockup`, `.split`, `.pros-cons`, placeholders, mock elements)
|
||||
- Dark/light theme variables and media query
|
||||
|
||||
### `helper.js` (client-side script)
|
||||
|
||||
**Remove:**
|
||||
- `sendToClaude()` function and the "Sent to Claude" page takeover
|
||||
- `window.send()` function (was tied to the removed Send button)
|
||||
- Form submission handler — no purpose without the feedback textarea, adds log noise
|
||||
- Input change handler — same reason
|
||||
- `pageshow` event listener (was added to fix textarea persistence — no textarea anymore)
|
||||
|
||||
**Keep:**
|
||||
- WebSocket connection, reconnect logic, event queue
|
||||
- Reload handler (`window.location.reload()` on server push)
|
||||
- `window.toggleSelect()` for selection highlighting
|
||||
- `window.selectedChoice` tracking
|
||||
- `window.brainstorm.send()` and `window.brainstorm.choice()` — these are distinct from the removed `window.send()`. They call `sendEvent` which logs to the server via WebSocket. Useful for custom full-document pages.
|
||||
|
||||
**Narrow:**
|
||||
- Click handler: capture only `[data-choice]` clicks, not all buttons/links. The broad capture was needed when the browser was a feedback channel; now it's just for selection tracking.
|
||||
|
||||
**Add:**
|
||||
- On `data-choice` click, update the selection indicator bar text to show which option was selected.
|
||||
|
||||
**Remove from `window.brainstorm` API:**
|
||||
- `brainstorm.sendToClaude` — no longer exists
|
||||
|
||||
### `visual-companion.md` (skill instructions)
|
||||
|
||||
**Rewrite "The Loop" section** to the non-blocking flow described above. Remove all references to:
|
||||
- `wait-for-feedback.sh`
|
||||
- `TaskOutput` blocking
|
||||
- Timeout/retry logic (600s timeout, 30-minute cap)
|
||||
- "User Feedback Format" section describing `send-to-claude` JSON
|
||||
|
||||
**Replace with:**
|
||||
- The new loop (write HTML → end turn → user responds in terminal → read `.events` → iterate)
|
||||
- `.events` file format documentation
|
||||
- Guidance that the terminal message is the primary feedback; `.events` provides the full browser interaction stream for additional context
|
||||
|
||||
**Keep:**
|
||||
- Server startup/shutdown instructions
|
||||
- Content fragment vs full document guidance
|
||||
- CSS class reference and available components
|
||||
- Design tips (scale fidelity to the question, 2-4 options per screen, etc.)
|
||||
|
||||
### `wait-for-feedback.sh`
|
||||
|
||||
**Deleted entirely.**
|
||||
|
||||
### `tests/brainstorm-server/server.test.js`
|
||||
|
||||
Tests that need updating:
|
||||
- Test asserting `feedback-footer` presence in fragment responses — update to assert the selection indicator bar or `<!-- CONTENT -->` replacement
|
||||
- Test asserting `helper.js` contains `send` — update to reflect narrowed API
|
||||
- Test asserting `sendToClaude` CSS variable usage — remove (function no longer exists)
|
||||
|
||||
## Platform Compatibility
|
||||
|
||||
The server code (`index.js`, `helper.js`, `frame-template.html`) is fully platform-agnostic — pure Node.js and browser JavaScript. No Claude Code-specific references. Already proven to work on Codex via background terminal interaction.
|
||||
|
||||
The skill instructions (`visual-companion.md`) are the platform-adaptive layer. Each platform's Claude uses its own tools to start the server, read `.events`, etc. The non-blocking model works naturally across platforms since it doesn't depend on any platform-specific blocking primitive.
|
||||
|
||||
## What This Enables
|
||||
|
||||
- **TUI always responsive** during visual brainstorming
|
||||
- **Mixed input** — click in browser + type in terminal, naturally merged
|
||||
- **Graceful degradation** — browser down or user doesn't open it? Terminal still works
|
||||
- **Simpler architecture** — no background tasks, no polling scripts, no timeout management
|
||||
- **Cross-platform** — same server code works on Claude Code, Codex, and any future platform
|
||||
|
||||
## What This Drops
|
||||
|
||||
- **Pure-browser feedback workflow** — user must return to the terminal to continue. The selection indicator bar guides them, but it's one extra step compared to the old click-Send-and-wait flow.
|
||||
- **Inline text feedback from browser** — the textarea is gone. All text feedback goes through the terminal. This is intentional — the terminal is a better text input channel than a small textarea in a frame.
|
||||
- **Immediate response on browser Send** — the old system had Claude respond the moment the user clicked Send. Now there's a gap while the user switches to the terminal. In practice this is seconds, and the user gets to add context in their terminal message.
|
||||
@@ -0,0 +1,118 @@
|
||||
# Zero-Dependency Brainstorm Server
|
||||
|
||||
Replace the brainstorm companion server's vendored node_modules (express, ws, chokidar — 714 tracked files) with a single zero-dependency `server.js` using only Node.js built-ins.
|
||||
|
||||
## Motivation
|
||||
|
||||
Vendoring node_modules into the git repo creates a supply chain risk: frozen dependencies don't get security patches, 714 files of third-party code are committed without audit, and modifications to vendored code look like normal commits. While the actual risk is low (localhost-only dev server), eliminating it is straightforward.
|
||||
|
||||
## Architecture
|
||||
|
||||
A single `server.js` file (~250-300 lines) using `http`, `crypto`, `fs`, and `path`. The file serves two roles:
|
||||
|
||||
- **When run directly** (`node server.js`): starts the HTTP/WebSocket server
|
||||
- **When required** (`require('./server.js')`): exports WebSocket protocol functions for unit testing
|
||||
|
||||
### WebSocket Protocol
|
||||
|
||||
Implements RFC 6455 for text frames only:
|
||||
|
||||
**Handshake:** Compute `Sec-WebSocket-Accept` from client's `Sec-WebSocket-Key` using SHA-1 + the RFC 6455 magic GUID. Return 101 Switching Protocols.
|
||||
|
||||
**Frame decoding (client to server):** Handle three masked length encodings:
|
||||
- Small: payload < 126 bytes
|
||||
- Medium: 126-65535 bytes (16-bit extended)
|
||||
- Large: > 65535 bytes (64-bit extended)
|
||||
|
||||
XOR-unmask payload using 4-byte mask key. Return `{ opcode, payload, bytesConsumed }` or `null` for incomplete buffers. Reject unmasked frames.
|
||||
|
||||
**Frame encoding (server to client):** Unmasked frames with the same three length encodings.
|
||||
|
||||
**Opcodes handled:** TEXT (0x01), CLOSE (0x08), PING (0x09), PONG (0x0A). Unrecognized opcodes get a close frame with status 1003 (Unsupported Data).
|
||||
|
||||
**Deliberately skipped:** Binary frames, fragmented messages, extensions (permessage-deflate), subprotocols. These are unnecessary for small JSON text messages between localhost clients. Extensions and subprotocols are negotiated in the handshake — by not advertising them, they are never active.
|
||||
|
||||
**Buffer accumulation:** Each connection maintains a buffer. On `data`, append and loop `decodeFrame` until it returns null or buffer is empty.
|
||||
|
||||
### HTTP Server
|
||||
|
||||
Three routes:
|
||||
|
||||
1. **`GET /`** — Serve newest `.html` from screen directory by mtime. Detect full documents vs fragments, wrap fragments in frame template, inject helper.js. Return `text/html`. When no `.html` files exist, serve a hardcoded waiting page ("Waiting for Claude to push a screen...") with helper.js injected.
|
||||
2. **`GET /files/*`** — Serve static files from screen directory with MIME type lookup from a hardcoded extension map (html, css, js, png, jpg, gif, svg, json). Return 404 if not found.
|
||||
3. **Everything else** — 404.
|
||||
|
||||
WebSocket upgrade handled via the `'upgrade'` event on the HTTP server, separate from the request handler.
|
||||
|
||||
### Configuration
|
||||
|
||||
Environment variables (all optional):
|
||||
|
||||
- `BRAINSTORM_PORT` — port to bind (default: random high port 49152-65535)
|
||||
- `BRAINSTORM_HOST` — interface to bind (default: `127.0.0.1`)
|
||||
- `BRAINSTORM_URL_HOST` — hostname for the URL in startup JSON (default: `localhost` when host is `127.0.0.1`, otherwise same as host)
|
||||
- `BRAINSTORM_DIR` — screen directory path (default: `/tmp/brainstorm`)
|
||||
|
||||
### Startup Sequence
|
||||
|
||||
1. Create `SCREEN_DIR` if it doesn't exist (`mkdirSync` recursive)
|
||||
2. Load frame template and helper.js from `__dirname`
|
||||
3. Start HTTP server on configured host/port
|
||||
4. Start `fs.watch` on `SCREEN_DIR`
|
||||
5. On successful listen, log `server-started` JSON to stdout: `{ type, port, host, url_host, url, screen_dir }`
|
||||
6. Write the same JSON to `SCREEN_DIR/.server-info` so agents can find connection details when stdout is hidden (background execution)
|
||||
|
||||
### Application-Level WebSocket Messages
|
||||
|
||||
When a TEXT frame arrives from a client:
|
||||
|
||||
1. Parse as JSON. If parsing fails, log to stderr and continue.
|
||||
2. Log to stdout as `{ source: 'user-event', ...event }`.
|
||||
3. If the event contains a `choice` property, append the JSON to `SCREEN_DIR/.events` (one line per event).
|
||||
|
||||
### File Watching
|
||||
|
||||
`fs.watch(SCREEN_DIR)` replaces chokidar. On HTML file events:
|
||||
|
||||
- On new file (`rename` event for a file that exists): delete `.events` file if present (`unlinkSync`), log `screen-added` to stdout as JSON
|
||||
- On file change (`change` event): log `screen-updated` to stdout as JSON (do NOT clear `.events`)
|
||||
- Both events: send `{ type: 'reload' }` to all connected WebSocket clients
|
||||
|
||||
Debounce per-filename with ~100ms timeout to prevent duplicate events (common on macOS and Linux).
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Malformed JSON from WebSocket clients: log to stderr, continue
|
||||
- Unhandled opcodes: close with status 1003
|
||||
- Client disconnects: remove from broadcast set
|
||||
- `fs.watch` errors: log to stderr, continue
|
||||
- No graceful shutdown logic — shell scripts handle process lifecycle via SIGTERM
|
||||
|
||||
## What Changes
|
||||
|
||||
| Before | After |
|
||||
|---|---|
|
||||
| `index.js` + `package.json` + `package-lock.json` + 714 `node_modules` files | `server.js` (single file) |
|
||||
| express, ws, chokidar dependencies | none |
|
||||
| No static file serving | `/files/*` serves from screen directory |
|
||||
|
||||
## What Stays the Same
|
||||
|
||||
- `helper.js` — no changes
|
||||
- `frame-template.html` — no changes
|
||||
- `start-server.sh` — one-line update: `index.js` to `server.js`
|
||||
- `stop-server.sh` — no changes
|
||||
- `visual-companion.md` — no changes
|
||||
- All existing server behavior and external contract
|
||||
|
||||
## Platform Compatibility
|
||||
|
||||
- `server.js` uses only cross-platform Node built-ins
|
||||
- `fs.watch` is reliable for single flat directories on macOS, Linux, and Windows
|
||||
- Shell scripts require bash (Git Bash on Windows, which is required for Claude Code)
|
||||
|
||||
## Testing
|
||||
|
||||
**Unit tests** (`ws-protocol.test.js`): Test WebSocket frame encoding/decoding, handshake computation, and protocol edge cases directly by requiring `server.js` exports.
|
||||
|
||||
**Integration tests** (`server.test.js`): Test full server behavior — HTTP serving, WebSocket communication, file watching, brainstorming workflow. Uses `ws` npm package as a test-only client dependency (not shipped to end users).
|
||||
@@ -0,0 +1,244 @@
|
||||
# Codex App Compatibility: Worktree and Finishing Skill Adaptation
|
||||
|
||||
Make superpowers skills work in the Codex App's sandboxed worktree environment without breaking existing Claude Code or Codex CLI behavior.
|
||||
|
||||
**Ticket:** PRI-823
|
||||
|
||||
## Motivation
|
||||
|
||||
The Codex App runs agents inside git worktrees it manages — detached HEAD, located under `$CODEX_HOME/worktrees/`, with a Seatbelt sandbox that blocks `git checkout -b`, `git push`, and network access. Three superpowers skills assume unrestricted git access: `using-git-worktrees` creates manual worktrees with named branches, `finishing-a-development-branch` merges/pushes/PRs by branch name, and `subagent-driven-development` requires both.
|
||||
|
||||
The Codex CLI (open source terminal tool) does NOT have this conflict — it has no built-in worktree management. Our manual worktree approach fills an isolation gap there. The problem is specifically with the Codex App.
|
||||
|
||||
## Empirical Findings
|
||||
|
||||
Tested in the Codex App on 2026-03-23:
|
||||
|
||||
| Operation | workspace-write sandbox | Full access sandbox |
|
||||
|---|---|---|
|
||||
| `git add` | Works | Works |
|
||||
| `git commit` | Works | Works |
|
||||
| `git checkout -b` | **Blocked** (can't write `.git/refs/heads/`) | Works |
|
||||
| `git push` | **Blocked** (network + `.git/refs/remotes/`) | Works |
|
||||
| `gh pr create` | **Blocked** (network) | Works |
|
||||
| `git status/diff/log` | Works | Works |
|
||||
|
||||
Additional findings:
|
||||
- `spawn_agent` subagents **share** the parent thread's filesystem (confirmed via marker file test)
|
||||
- "Create branch" button appears in the App header regardless of which branch the worktree was started from
|
||||
- The App's native finishing flow: Create branch → Commit modal → Commit and push / Commit and create PR
|
||||
- `network_access = true` config is silently broken on macOS (issue #10390)
|
||||
|
||||
## Design: Read-Only Environment Detection
|
||||
|
||||
Three read-only git commands detect the environment without side effects:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
Two signals derived:
|
||||
|
||||
- **IN_LINKED_WORKTREE:** `GIT_DIR != GIT_COMMON` — the agent is in a worktree created by something else (Codex App, Claude Code Agent tool, previous skill run, or the user)
|
||||
- **ON_DETACHED_HEAD:** `BRANCH` is empty — no named branch exists
|
||||
|
||||
Why `git-dir != git-common-dir` instead of checking `show-toplevel`:
|
||||
- In a normal repo, both resolve to the same `.git` directory
|
||||
- In a linked worktree, `git-dir` is `.git/worktrees/<name>` while `git-common-dir` is `.git`
|
||||
- In a submodule, both are equal — avoiding a false positive that `show-toplevel` would produce
|
||||
- Resolving via `cd && pwd -P` handles the relative-path problem (`git-common-dir` returns `.git` relative in normal repos but absolute in worktrees) and symlinks (macOS `/tmp` → `/private/tmp`)
|
||||
|
||||
### Decision Matrix
|
||||
|
||||
| Linked Worktree? | Detached HEAD? | Environment | Action |
|
||||
|---|---|---|---|
|
||||
| No | No | Claude Code / Codex CLI / normal git | Full skill behavior (unchanged) |
|
||||
| Yes | Yes | Codex App worktree (workspace-write) | Skip worktree creation; handoff payload at finish |
|
||||
| Yes | No | Codex App (Full access) or manual worktree | Skip worktree creation; full finishing flow |
|
||||
| No | Yes | Unusual (manual detached HEAD) | Create worktree normally; warn at finish |
|
||||
|
||||
## Changes
|
||||
|
||||
### 1. `using-git-worktrees/SKILL.md` — Add Step 0 (~12 lines)
|
||||
|
||||
New section between "Overview" and "Directory Selection Process":
|
||||
|
||||
**Step 0: Check if Already in an Isolated Workspace**
|
||||
|
||||
Run the detection commands. If `GIT_DIR != GIT_COMMON`, skip worktree creation entirely. Instead:
|
||||
1. Skip to "Run Project Setup" subsection under Creation Steps — `npm install` etc. is idempotent, worth running for safety
|
||||
2. Then "Verify Clean Baseline" — run tests
|
||||
3. Report with branch state:
|
||||
- On a branch: "Already in an isolated workspace at `<path>` on branch `<name>`. Tests passing. Ready to implement."
|
||||
- Detached HEAD: "Already in an isolated workspace at `<path>` (detached HEAD, externally managed). Tests passing. Note: branch creation needed at finish time. Ready to implement."
|
||||
|
||||
If `GIT_DIR == GIT_COMMON`, proceed with the full worktree creation flow (unchanged).
|
||||
|
||||
Safety verification (.gitignore check) is skipped when Step 0 fires — irrelevant for externally-created worktrees.
|
||||
|
||||
Update the Integration section's "Called by" entries. Change the description on each from context-specific text to: "Ensures isolated workspace (creates one or verifies existing)". For example, the `subagent-driven-development` entry changes from "REQUIRED: Set up isolated workspace before starting" to "REQUIRED: Ensures isolated workspace (creates one or verifies existing)".
|
||||
|
||||
**Sandbox fallback:** If `GIT_DIR == GIT_COMMON` and the skill proceeds to Creation Steps, but `git worktree add -b` fails with a permission error (e.g., Seatbelt sandbox denial), treat this as a late-detected restricted environment. Fall back to the Step 0 "already in workspace" behavior — skip creation, run setup and baseline tests in the current directory, report accordingly.
|
||||
|
||||
After reporting in Step 0, STOP. Do not continue to Directory Selection or Creation Steps.
|
||||
|
||||
**Everything else unchanged:** Directory Selection, Safety Verification, Creation Steps, Project Setup, Baseline Tests, Quick Reference, Common Mistakes, Red Flags.
|
||||
|
||||
### 2. `finishing-a-development-branch/SKILL.md` — Add Step 1.5 + cleanup guard (~20 lines)
|
||||
|
||||
**Step 1.5: Detect Environment** (after Step 1 "Verify Tests", before Step 2 "Determine Base Branch")
|
||||
|
||||
Run the detection commands. Three paths:
|
||||
|
||||
- **Path A** skips Steps 2 and 3 entirely (no base branch or options needed).
|
||||
- **Paths B and C** proceed through Step 2 (Determine Base Branch) and Step 3 (Present Options) as normal.
|
||||
|
||||
**Path A — Externally managed worktree + detached HEAD** (`GIT_DIR != GIT_COMMON` AND `BRANCH` empty):
|
||||
|
||||
First, ensure all work is staged and committed (`git add` + `git commit`). The Codex App's finishing controls operate on committed work.
|
||||
|
||||
Then present this to the user (do NOT present the 4-option menu):
|
||||
|
||||
```
|
||||
Implementation complete. All tests passing.
|
||||
Current HEAD: <full-commit-sha>
|
||||
|
||||
This workspace is externally managed (detached HEAD).
|
||||
I cannot create branches, push, or open PRs from here.
|
||||
|
||||
⚠ These commits are on a detached HEAD. If you do not create a branch,
|
||||
they may be lost when this workspace is cleaned up.
|
||||
|
||||
If your host application provides these controls:
|
||||
- "Create branch" — to name a branch, then commit/push/PR
|
||||
- "Hand off to local" — to move changes to your local checkout
|
||||
|
||||
Suggested branch name: <ticket-id/short-description>
|
||||
Suggested commit message: <summary-of-work>
|
||||
```
|
||||
|
||||
Branch name derivation: use the ticket ID if available (e.g., `pri-823/codex-compat`), otherwise slugify the first 5 words of the plan title, otherwise omit the suggestion. Avoid including sensitive content (vulnerability descriptions, customer names) in branch names.
|
||||
|
||||
Skip to Step 5 (cleanup is a no-op for externally managed worktrees).
|
||||
|
||||
**Path B — Externally managed worktree + named branch** (`GIT_DIR != GIT_COMMON` AND `BRANCH` exists):
|
||||
|
||||
Present the 4-option menu as normal. (The Step 5 cleanup guard will re-detect the externally managed state independently.)
|
||||
|
||||
**Path C — Normal environment** (`GIT_DIR == GIT_COMMON`):
|
||||
|
||||
Present the 4-option menu as today (unchanged).
|
||||
|
||||
**Step 5 cleanup guard:**
|
||||
|
||||
Re-run the `GIT_DIR` vs `GIT_COMMON` detection at cleanup time (do not rely on earlier skill output — the finishing skill may run in a different session). If `GIT_DIR != GIT_COMMON`, skip `git worktree remove` — the host environment owns this workspace.
|
||||
|
||||
Otherwise, check and remove as today. Note: the existing Step 5 text says "For Options 1, 2, 4" but the Quick Reference table and Common Mistakes section say "Options 1 & 4 only." The new guard is added before this existing logic and does not change which options trigger cleanup.
|
||||
|
||||
**Everything else unchanged:** Options 1-4 logic, Quick Reference, Common Mistakes, Red Flags.
|
||||
|
||||
### 3. `subagent-driven-development/SKILL.md` and `executing-plans/SKILL.md` — 1 line edit each
|
||||
|
||||
Both skills have an identical Integration section line. Change from:
|
||||
```
|
||||
- superpowers:using-git-worktrees - REQUIRED: Set up isolated workspace before starting
|
||||
```
|
||||
To:
|
||||
```
|
||||
- superpowers:using-git-worktrees - REQUIRED: Ensures isolated workspace (creates one or verifies existing)
|
||||
```
|
||||
|
||||
**Everything else unchanged:** Dispatch/review loop, prompt templates, model selection, status handling, red flags.
|
||||
|
||||
### 4. `codex-tools.md` — Add environment detection docs (~15 lines)
|
||||
|
||||
Two new sections at the end:
|
||||
|
||||
**Environment Detection:**
|
||||
|
||||
```markdown
|
||||
## Environment Detection
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
\```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)
|
||||
\```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1.5 for how each skill uses these signals.
|
||||
```
|
||||
|
||||
**Codex App Finishing:**
|
||||
|
||||
```markdown
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
```
|
||||
|
||||
## What Does NOT Change
|
||||
|
||||
- `implementer-prompt.md`, `spec-reviewer-prompt.md`, `code-quality-reviewer-prompt.md` — subagent prompts untouched
|
||||
- `executing-plans/SKILL.md` — only the 1-line Integration description changes (same as `subagent-driven-development`); all runtime behavior is unchanged
|
||||
- `dispatching-parallel-agents/SKILL.md` — no worktree or finishing operations
|
||||
- `.codex/INSTALL.md` — installation process unchanged
|
||||
- The 4-option finishing menu — preserved exactly for Claude Code and Codex CLI
|
||||
- The full worktree creation flow — preserved exactly for non-worktree environments
|
||||
- Subagent dispatch/review/iterate loop — unchanged (filesystem sharing confirmed)
|
||||
|
||||
## Scope Summary
|
||||
|
||||
| File | Change |
|
||||
|---|---|
|
||||
| `skills/using-git-worktrees/SKILL.md` | +12 lines (Step 0) |
|
||||
| `skills/finishing-a-development-branch/SKILL.md` | +20 lines (Step 1.5 + cleanup guard) |
|
||||
| `skills/subagent-driven-development/SKILL.md` | 1 line edit |
|
||||
| `skills/executing-plans/SKILL.md` | 1 line edit |
|
||||
| `skills/using-superpowers/references/codex-tools.md` | +15 lines |
|
||||
|
||||
~50 lines added/changed across 5 files. Zero new files. Zero breaking changes.
|
||||
|
||||
## Future Considerations
|
||||
|
||||
If a third skill needs the same detection pattern, extract it into a shared `references/environment-detection.md` file (Approach B). Not needed now — only 2 skills use it.
|
||||
|
||||
## Test Plan
|
||||
|
||||
### Automated (run in Claude Code after implementation)
|
||||
|
||||
1. Normal repo detection — assert IN_LINKED_WORKTREE=false
|
||||
2. Linked worktree detection — `git worktree add` test worktree, assert IN_LINKED_WORKTREE=true
|
||||
3. Detached HEAD detection — `git checkout --detach`, assert ON_DETACHED_HEAD=true
|
||||
4. Finishing skill handoff output — verify handoff message (not 4-option menu) in restricted environment
|
||||
5. **Step 5 cleanup guard** — create a linked worktree (`git worktree add /tmp/test-cleanup -b test-cleanup`), `cd` into it, run the Step 5 cleanup detection (`GIT_DIR` vs `GIT_COMMON`), assert it would NOT call `git worktree remove`. Then `cd` back to main repo, run the same detection, assert it WOULD call `git worktree remove`. Clean up test worktree afterward.
|
||||
|
||||
### Manual Codex App Tests (5 tests)
|
||||
|
||||
1. Detection in Worktree thread (workspace-write) — verify GIT_DIR != GIT_COMMON, empty branch
|
||||
2. Detection in Worktree thread (Full access) — same detection, different sandbox behavior
|
||||
3. Finishing skill handoff format — verify agent emits handoff payload, not 4-option menu
|
||||
4. Full lifecycle — detection → commit → finishing detection → correct behavior → cleanup
|
||||
5. **Sandbox fallback in Local thread** — Start a Codex App **Local thread** (workspace-write sandbox). Prompt: "Use the superpowers skill `using-git-worktrees` to set up an isolated workspace for implementing a small change." Pre-check: `git checkout -b test-sandbox-check` should fail with `Operation not permitted`. Expected: the skill detects `GIT_DIR == GIT_COMMON` (normal repo), attempts `git worktree add -b`, hits Seatbelt denial, falls back to Step 0 "already in workspace" behavior — runs setup, baseline tests, reports ready from current directory. Pass: agent recovers gracefully without cryptic error messages. Fail: agent prints raw Seatbelt error, retries, or gives up with confusing output.
|
||||
|
||||
### Regression
|
||||
|
||||
- Existing Claude Code skill-triggering tests still pass
|
||||
- Existing subagent-driven-development integration tests still pass
|
||||
- Normal Claude Code session: full worktree creation + 4-option finishing still works
|
||||
341
docs/superpowers/specs/2026-04-06-worktree-rototill-design.md
Normal file
341
docs/superpowers/specs/2026-04-06-worktree-rototill-design.md
Normal file
@@ -0,0 +1,341 @@
|
||||
# Worktree Rototill: Detect-and-Defer
|
||||
|
||||
**Date:** 2026-04-06
|
||||
**Status:** Draft
|
||||
**Ticket:** PRI-974
|
||||
**Subsumes:** PRI-823 (Codex App compatibility)
|
||||
|
||||
## Problem
|
||||
|
||||
Superpowers is opinionated about worktree management — specific paths (`.worktrees/<branch>`), specific commands (`git worktree add`), specific cleanup (`git worktree remove`). Meanwhile, Claude Code, Codex App, Gemini CLI, and Cursor all provide native worktree support with their own paths, lifecycle management, and cleanup.
|
||||
|
||||
This creates three failure modes:
|
||||
|
||||
1. **Duplication** — on Claude Code, the skill does what `EnterWorktree`/`ExitWorktree` already does
|
||||
2. **Conflict** — on Codex App, the skill tries to create worktrees inside an already-managed worktree
|
||||
3. **Phantom state** — skill-created worktrees at `.worktrees/` are invisible to the harness; harness-created worktrees at `.claude/worktrees/` are invisible to the skill
|
||||
|
||||
For harnesses without native support (Codex CLI, OpenCode, Copilot standalone), superpowers fills a real gap. The skill shouldn't go away — it should get out of the way when native support exists.
|
||||
|
||||
## Goals
|
||||
|
||||
1. Defer to native harness worktree systems when they exist
|
||||
2. Continue providing worktree support for harnesses that lack it
|
||||
3. Fix three known bugs in finishing-a-development-branch (#940, #999, #238)
|
||||
4. Make worktree creation opt-in rather than mandatory (#991)
|
||||
5. Replace hardcoded `CLAUDE.md` references with platform-neutral language (#1049)
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Per-worktree environment conventions (`.worktree-env.sh`, port offsetting) — Phase 4
|
||||
- PreToolUse hooks for path enforcement — Phase 4
|
||||
- Multi-repo worktree documentation — Phase 4
|
||||
- Brainstorming checklist changes for worktrees — Phase 4
|
||||
- `.superpowers-session.json` metadata tracking (interesting PR #997 idea, not needed for v1)
|
||||
- Hooks symlinking into worktrees (PR #965 idea, separate concern)
|
||||
|
||||
## Design Principles
|
||||
|
||||
### Detect state, not platform
|
||||
|
||||
Use `GIT_DIR != GIT_COMMON` to determine "am I already in a worktree?" rather than sniffing environment variables to identify the harness. This is a stable git primitive (since git 2.5, 2015), works universally across all harnesses, and requires zero maintenance as new harnesses appear.
|
||||
|
||||
### Declarative intent, prescriptive fallback
|
||||
|
||||
The skill describes the goal ("ensure work happens in an isolated workspace") and defers to native tools when available. It prescribes specific git commands only as a fallback for harnesses without native worktree support. Step 1a comes first and names native tools explicitly (`EnterWorktree`, `WorktreeCreate`, `/worktree`, `--worktree`); Step 1b comes second with the git fallback. The original spec kept Step 1a abstract ("you know your own toolkit"), but TDD proved that agents anchor on Step 1b's concrete commands when Step 1a is too vague. Explicit tool naming and a consent-authorization bridge were required to make the preference reliable.
|
||||
|
||||
### Provenance-based ownership
|
||||
|
||||
Whoever creates the worktree owns its cleanup. If the harness created it, superpowers doesn't touch it. If superpowers created it (via git fallback), superpowers cleans it up. The heuristic: if the worktree lives under `.worktrees/` or `worktrees/`, superpowers owns it. Anything else (`.claude/worktrees/`, `~/.codex/worktrees/`, `.gemini/worktrees/`, or old user-global Superpowers paths) belongs to the harness or user and is left alone.
|
||||
|
||||
## Design
|
||||
|
||||
### 1. `using-git-worktrees` SKILL.md Rewrite
|
||||
|
||||
The skill gains three new steps before creation and simplifies the creation flow.
|
||||
|
||||
#### Step 0: Detect Existing Isolation
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
BRANCH=$(git branch --show-current)
|
||||
```
|
||||
|
||||
Three outcomes:
|
||||
|
||||
| Condition | Meaning | Action |
|
||||
|-----------|---------|--------|
|
||||
| `GIT_DIR == GIT_COMMON` | Normal repo checkout | Proceed to Step 0.5 |
|
||||
| `GIT_DIR != GIT_COMMON`, named branch | Already in a linked worktree | Skip to Step 3 (project setup). Report: "Already in isolated workspace at `<path>` on branch `<name>`." |
|
||||
| `GIT_DIR != GIT_COMMON`, detached HEAD | Externally managed worktree (e.g., Codex App sandbox) | Skip to Step 3. Report: "Already in isolated workspace at `<path>` (detached HEAD, externally managed)." |
|
||||
|
||||
Step 0 does not care who created the worktree or which harness is running. A worktree is a worktree regardless of origin.
|
||||
|
||||
**Submodule guard:** `GIT_DIR != GIT_COMMON` is also true inside git submodules. Before concluding "already in a worktree," check that we're not in a submodule:
|
||||
|
||||
```bash
|
||||
# If this returns a path, we're in a submodule, not a worktree
|
||||
git rev-parse --show-superproject-working-tree 2>/dev/null
|
||||
```
|
||||
|
||||
If in a submodule, treat as `GIT_DIR == GIT_COMMON` (proceed to Step 0.5).
|
||||
|
||||
#### Step 0.5: Consent
|
||||
|
||||
When Step 0 finds no existing isolation (`GIT_DIR == GIT_COMMON`), ask before creating:
|
||||
|
||||
> "Would you like me to set up an isolated worktree? This protects your current branch from changes. (y/n)"
|
||||
|
||||
If yes, proceed to Step 1. If no, work in place — skip to Step 3 with no worktree.
|
||||
|
||||
This step is skipped entirely when Step 0 detects existing isolation (no point asking about what already exists).
|
||||
|
||||
#### Step 1a: Native Tools (preferred)
|
||||
|
||||
> The user has asked for an isolated workspace (Step 0 consent). Check your available tools — do you have `EnterWorktree`, `WorktreeCreate`, a `/worktree` command, or a `--worktree` flag? If YES: the user's consent to create a worktree is your authorization to use it. Use it now and skip to Step 3.
|
||||
|
||||
After using a native tool, skip to Step 3 (project setup).
|
||||
|
||||
**Design note — TDD revision:** The original spec used a deliberately short, abstract Step 1a ("You know your own toolkit — the skill does not need to name specific tools"). TDD validation disproved this: agents anchored on Step 1b's concrete git commands and ignored the abstract guidance (2/6 pass rate). Three changes fixed it (50/50 pass rate across GREEN and PRESSURE tests):
|
||||
|
||||
1. **Explicit tool naming** — listing `EnterWorktree`, `WorktreeCreate`, `/worktree`, `--worktree` by name transforms the decision from interpretation ("do I have a native tool?") into factual lookup ("is `EnterWorktree` in my tool list?"). Agents on platforms without these tools simply check, find nothing, and fall through to Step 1b. No false positives observed.
|
||||
2. **Consent bridge** — "the user's consent to create a worktree is your authorization to use it" directly addresses `EnterWorktree`'s tool-level guardrail ("ONLY when user explicitly asks"). Tool descriptions override skill instructions (Claude Code #29950), so the skill must frame user consent as the authorization the tool requires.
|
||||
3. **Red Flag entry** — naming the specific anti-pattern ("Use `git worktree add` when you have a native worktree tool — this is the #1 mistake") in the Red Flags section.
|
||||
|
||||
File splitting (Step 1b in a separate skill) was tested and proven unnecessary. The anchoring problem is solved by the quality of Step 1a's text, not by physical separation of git commands. Control tests with the full 240-line skill (all git commands visible) passed 20/20.
|
||||
|
||||
#### Step 1b: Git Worktree Fallback
|
||||
|
||||
When no native tool is available, create a worktree manually.
|
||||
|
||||
**Directory selection** (priority order):
|
||||
1. Check the project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent) for a worktree directory preference.
|
||||
2. Check for existing `.worktrees/` or `worktrees/` directory — if found, use it. If both exist, `.worktrees/` wins.
|
||||
3. Default to `.worktrees/`.
|
||||
|
||||
No interactive directory selection prompt. Old user-global Superpowers worktree paths are not detected or offered; new manual worktrees are project-local unless the user explicitly specifies another location.
|
||||
|
||||
**Safety verification** (project-local directories only):
|
||||
|
||||
```bash
|
||||
git check-ignore -q .worktrees 2>/dev/null
|
||||
```
|
||||
|
||||
If not ignored, add to `.gitignore` and commit before proceeding.
|
||||
|
||||
**Create:**
|
||||
|
||||
```bash
|
||||
git worktree add "$path" -b "$BRANCH_NAME"
|
||||
cd "$path"
|
||||
```
|
||||
|
||||
**Hooks awareness:** Git worktrees do not inherit the parent repo's hooks directory. After creating a worktree via 1b, symlink the hooks directory from the main repo if one exists:
|
||||
|
||||
```bash
|
||||
if [ -d "$MAIN_ROOT/.git/hooks" ]; then
|
||||
ln -sf "$MAIN_ROOT/.git/hooks" "$path/.git/hooks"
|
||||
fi
|
||||
```
|
||||
|
||||
This prevents pre-commit checks, linters, and other hooks from silently stopping when work moves to a worktree. (Idea from PR #965.)
|
||||
|
||||
**Sandbox fallback:** If `git worktree add` fails with a permission error, treat as a restricted environment. Skip creation, work in current directory, proceed to Step 3.
|
||||
|
||||
**Step numbering note:** The current skill has Steps 1-4 as a flat list. This redesign uses 0, 0.5, 1a, 1b, 3, 4. There is no Step 2 — it was the old monolithic "Create Isolated Workspace" which is now split into the 1a/1b structure. The implementation should renumber cleanly (e.g., 0 → "Step 0: Detect", 0.5 → within Step 0's flow, 1a/1b → "Step 1", 3 → "Step 2", 4 → "Step 3") or keep the current numbering with a note. Implementer's choice.
|
||||
|
||||
#### Steps 3-4: Project Setup and Baseline Tests (unchanged)
|
||||
|
||||
Regardless of which path created the workspace (Step 0 detected existing, Step 1a native tool, Step 1b git fallback, or no worktree at all), execution converges:
|
||||
|
||||
- **Step 3:** Auto-detect and run project setup (`npm install`, `cargo build`, `pip install`, `go mod download`, etc.)
|
||||
- **Step 4:** Run the test suite. If tests fail, report failures and ask whether to proceed.
|
||||
|
||||
### 2. `finishing-a-development-branch` SKILL.md Rewrite
|
||||
|
||||
The finishing skill gains environment detection and fixes three bugs.
|
||||
|
||||
#### Step 1: Verify Tests (unchanged)
|
||||
|
||||
Run the project's test suite. If tests fail, stop. Don't offer completion options.
|
||||
|
||||
#### Step 1.5: Detect Environment (new)
|
||||
|
||||
Re-run the same detection as Step 0 in creation:
|
||||
|
||||
```bash
|
||||
GIT_DIR=$(cd "$(git rev-parse --git-dir)" 2>/dev/null && pwd -P)
|
||||
GIT_COMMON=$(cd "$(git rev-parse --git-common-dir)" 2>/dev/null && pwd -P)
|
||||
```
|
||||
|
||||
Three paths:
|
||||
|
||||
| State | Menu | Cleanup |
|
||||
|-------|------|---------|
|
||||
| `GIT_DIR == GIT_COMMON` (normal repo) | Standard 4 options | No worktree to clean up |
|
||||
| `GIT_DIR != GIT_COMMON`, named branch | Standard 4 options | Provenance-based (see Step 5) |
|
||||
| `GIT_DIR != GIT_COMMON`, detached HEAD | Reduced menu: push as new branch + PR, keep as-is, discard | No merge options (can't merge from detached HEAD) |
|
||||
|
||||
#### Step 2: Determine Base Branch (unchanged)
|
||||
|
||||
#### Step 3: Present Options
|
||||
|
||||
**Normal repo and named-branch worktree:**
|
||||
|
||||
1. Merge back to `<base-branch>` locally
|
||||
2. Push and create a Pull Request
|
||||
3. Keep the branch as-is (I'll handle it later)
|
||||
4. Discard this work
|
||||
|
||||
**Detached HEAD:**
|
||||
|
||||
1. Push as new branch and create a Pull Request
|
||||
2. Keep as-is (I'll handle it later)
|
||||
3. Discard this work
|
||||
|
||||
#### Step 4: Execute Choice
|
||||
|
||||
**Option 1 (Merge locally):**
|
||||
|
||||
```bash
|
||||
# Get main repo root for CWD safety (Bug #238 fix)
|
||||
MAIN_ROOT=$(git -C "$(git rev-parse --git-common-dir)/.." rev-parse --show-toplevel)
|
||||
cd "$MAIN_ROOT"
|
||||
|
||||
# Merge first, verify success before removing anything
|
||||
git checkout <base-branch>
|
||||
git pull
|
||||
git merge <feature-branch>
|
||||
<run tests>
|
||||
|
||||
# Only after merge succeeds: remove worktree, then delete branch (Bug #999 fix)
|
||||
git worktree remove "$WORKTREE_PATH" # only if superpowers owns it
|
||||
git branch -d <feature-branch>
|
||||
```
|
||||
|
||||
The order is critical: merge → verify → remove worktree → delete branch. The old skill deleted the branch before removing the worktree (which fails because the worktree still references the branch). The naive fix of removing the worktree first is also wrong — if the merge then fails, the working directory is gone and changes are lost.
|
||||
|
||||
**Option 2 (Create PR):**
|
||||
|
||||
Push branch, create PR. Do NOT clean up worktree — user needs it for PR iteration. (Bug #940 fix: remove contradictory "Then: Cleanup worktree" prose.)
|
||||
|
||||
**Option 3 (Keep as-is):** No action.
|
||||
|
||||
**Option 4 (Discard):** Require typed "discard" confirmation. Then remove worktree (if superpowers owns it), force-delete branch.
|
||||
|
||||
#### Step 5: Cleanup (updated)
|
||||
|
||||
```
|
||||
if GIT_DIR == GIT_COMMON:
|
||||
# Normal repo, no worktree to clean up
|
||||
done
|
||||
|
||||
if worktree path is under .worktrees/ or worktrees/:
|
||||
# Superpowers created it — we own cleanup
|
||||
cd to main repo root # Bug #238 fix
|
||||
git worktree remove <path>
|
||||
|
||||
else:
|
||||
# Harness created it — hands off
|
||||
# If platform provides a workspace-exit tool, use it
|
||||
# Otherwise, leave the worktree in place
|
||||
```
|
||||
|
||||
Cleanup only runs for Options 1 and 4. Options 2 and 3 always preserve the worktree. (Bug #940 fix.)
|
||||
|
||||
**Stale worktree pruning:** After any `git worktree remove`, run `git worktree prune` as a self-healing step. Worktree directories can get deleted out-of-band (e.g., by harness cleanup, manual `rm`, or `.claude/` cleanup), leaving stale registrations that cause confusing errors. One line, prevents silent rot. (Idea from PR #1072.)
|
||||
|
||||
### 3. Integration Updates
|
||||
|
||||
#### `subagent-driven-development` and `executing-plans`
|
||||
|
||||
Both currently list `using-git-worktrees` as REQUIRED in their integration sections. Change to:
|
||||
|
||||
> `using-git-worktrees` — Ensures isolated workspace (creates one or verifies existing)
|
||||
|
||||
The skill itself now handles consent (Step 0.5) and detection (Step 0), so calling skills don't need to gate or prompt.
|
||||
|
||||
#### `writing-plans`
|
||||
|
||||
Remove the stale claim "should be run in a dedicated worktree (created by brainstorming skill)." Brainstorming is a design skill and does not create worktrees. The worktree prompt happens at execution time via `using-git-worktrees`.
|
||||
|
||||
### 4. Platform-Neutral Instruction File References
|
||||
|
||||
All instances of hardcoded `CLAUDE.md` in worktree-related skills are replaced with:
|
||||
|
||||
> "your project's agent instruction file (CLAUDE.md, GEMINI.md, AGENTS.md, .cursorrules, or equivalent)"
|
||||
|
||||
This applies to directory preference checks in Step 1b.
|
||||
|
||||
## Bug Fixes (bundled)
|
||||
|
||||
| Bug | Problem | Fix | Location |
|
||||
|-----|---------|-----|----------|
|
||||
| #940 | Option 2 prose says "Then: Cleanup worktree (Step 5)" but quick reference says keep it. Step 5 says "For Options 1, 2, 4" but Common Mistakes says "Options 1 and 4 only." | Remove cleanup from Option 2. Step 5 applies to Options 1 and 4 only. | finishing SKILL.md |
|
||||
| #999 | Option 1 deletes branch before removing worktree. `git branch -d` can fail because worktree still references the branch. | Reorder to: merge → verify tests → remove worktree → delete branch. Merge must succeed before anything is removed. | finishing SKILL.md |
|
||||
| #238 | `git worktree remove` fails silently if CWD is inside the worktree being removed. | Add CWD guard: `cd` to main repo root before `git worktree remove`. | finishing SKILL.md |
|
||||
|
||||
## Issues Resolved
|
||||
|
||||
| Issue | Resolution |
|
||||
|-------|-----------|
|
||||
| #940 | Direct fix (Bug #940) |
|
||||
| #991 | Opt-in consent in Step 0.5 |
|
||||
| #918 | Step 0 detection + Step 1.5 finishing detection |
|
||||
| #1009 | Resolved by Step 1a — agents use native tools (e.g., `EnterWorktree`) which create at harness-native paths. Depends on Step 1a working; see Risks. |
|
||||
| #999 | Direct fix (Bug #999) |
|
||||
| #238 | Direct fix (Bug #238) |
|
||||
| #1049 | Platform-neutral instruction file references |
|
||||
| #279 | Solved by detect-and-defer — native paths respected because we don't override them |
|
||||
| #574 | **Deferred.** Nothing in this spec touches the brainstorming skill where the bug lives. Full fix (adding a worktree step to brainstorming's checklist) is Phase 4. |
|
||||
|
||||
## Risks
|
||||
|
||||
### Step 1a is the load-bearing assumption — RESOLVED
|
||||
|
||||
Step 1a — agents preferring native worktree tools over the git fallback — is the foundation the entire design rests on. If agents ignore Step 1a and fall through to Step 1b on harnesses with native support, detect-and-defer fails entirely.
|
||||
|
||||
**Status:** This risk materialized during implementation. The original abstract Step 1a ("You know your own toolkit") failed at 2/6 on Claude Code. The TDD gate worked as designed — it caught the failure before any skill files were modified, preventing a broken release. Three REFACTOR iterations identified the root causes (agent anchoring on concrete commands, tool-description guardrail overriding skill instructions) and produced a fix validated at 50/50 across GREEN and PRESSURE tests. See Step 1a design note above for details.
|
||||
|
||||
**Cross-platform validation:**
|
||||
|
||||
As of 2026-04-06, Claude Code is the only harness with an agent-callable mid-session worktree tool (`EnterWorktree`). All others either create worktrees before the agent starts (Codex App, Gemini CLI, Cursor) or have no native worktree support (Codex CLI, OpenCode). Step 1a is forward-compatible: when other harnesses add agent-callable worktree tools, agents will match them against the named examples and use them without skill changes.
|
||||
|
||||
| Harness | Current worktree model | Skill mechanism | Tested |
|
||||
|---------|----------------------|-----------------|--------|
|
||||
| Claude Code | Agent-callable `EnterWorktree` | Step 1a | 50/50 (GREEN + PRESSURE) |
|
||||
| Codex CLI | No native tool (shell only) | Step 1b git fallback | 6/6 (`codex exec`) |
|
||||
| Gemini CLI | Launch-time `--worktree` flag, no agent tool | Step 0 if launched with flag, Step 1b if not | Step 0: 1/1, Step 1b: 1/1 (`gemini -p`) |
|
||||
| Cursor Agent | User-facing `/worktree`, no agent tool | Step 0 if user activated, Step 1b if not | Step 0: 1/1, Step 1b: 1/1 (`cursor-agent -p`) |
|
||||
| Codex App | Platform-managed, detached HEAD, no agent tool | Step 0 detects existing | 1/1 simulated |
|
||||
| OpenCode | Detection only (`ctx.worktree`), no agent tool | Step 1b git fallback | Untested (no CLI access) |
|
||||
|
||||
**Residual risks:**
|
||||
1. If Anthropic changes `EnterWorktree`'s tool description to be more restrictive (e.g., "Do not use based on skill instructions"), the consent bridge breaks. Worth filing an issue requesting that the tool description accommodate skill-driven invocation.
|
||||
2. When other harnesses add agent-callable worktree tools, they may use names not in Step 1a's list. The list should be updated as new tools appear. The generic phrasing ("a worktree or workspace-isolation tool") provides some forward coverage.
|
||||
|
||||
### Provenance heuristic
|
||||
|
||||
The `.worktrees/` or `worktrees/` = ours, anything else = hands off` heuristic works for every current harness. If a future harness adopts one of those project-local directories as its convention, we'd have a false positive (superpowers tries to clean up a harness-owned worktree). Similarly, if a user manually runs `git worktree add .worktrees/experiment` without superpowers, we'd incorrectly claim ownership. Both are low risk — every harness uses branded paths, and manual `.worktrees/` creation is unlikely — but worth noting.
|
||||
|
||||
### Detached HEAD finishing
|
||||
|
||||
The reduced menu for detached HEAD worktrees (no merge option) is correct for Codex App's sandbox model. If a user is in detached HEAD for another reason, the reduced menu still makes sense — you genuinely can't merge from detached HEAD without creating a branch first.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
Both skill files contain sections beyond the core steps that need updating during implementation:
|
||||
|
||||
- **Frontmatter** (`name`, `description`): Update to reflect detect-and-defer behavior
|
||||
- **Quick Reference tables**: Rewrite to match new step structure and bug fixes
|
||||
- **Common Mistakes sections**: Update or remove items that reference old behavior (e.g., "Skip CLAUDE.md check" is now wrong)
|
||||
- **Red Flags sections**: Update to reflect new priorities (e.g., "Never create a worktree when Step 0 detects existing isolation")
|
||||
- **Integration sections**: Update cross-references between skills
|
||||
|
||||
The spec describes *what changes*; the implementation plan will specify exact edits to these secondary sections.
|
||||
|
||||
## Future Work (not in this spec)
|
||||
|
||||
- **Phase 3 remainder:** `$TMPDIR` directory option (#666), setup docs for caching and env inheritance (#299)
|
||||
- **Phase 4:** PreToolUse hooks for path enforcement (#1040), per-worktree env conventions (#597), brainstorming checklist worktree step (#574), multi-repo documentation (#710)
|
||||
@@ -0,0 +1,77 @@
|
||||
# Platform-neutral config-file references — Phase B design
|
||||
|
||||
## Background
|
||||
|
||||
Phase A (see `2026-05-05-platform-neutral-prose-design.md`) replaced generic third-person "Claude" prose with agent-neutral forms. This phase tackles the next category: references to the per-platform instruction file (CLAUDE.md, AGENTS.md, GEMINI.md) inside skills.
|
||||
|
||||
The plugin runs on multiple harnesses, and each one reads its own instruction file. Where a skill names CLAUDE.md as if it were the only file, that's a Claude-Code-centric assumption that doesn't hold on Codex / Gemini CLI / OpenCode.
|
||||
|
||||
## In scope
|
||||
|
||||
Two specific lines in active skills:
|
||||
|
||||
1. **`skills/writing-skills/SKILL.md:58`** — `Project-specific conventions (put in CLAUDE.md)`
|
||||
2. **`skills/receiving-code-review/SKILL.md:30`** — `"You're absolutely right!" (explicit CLAUDE.md violation)`
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **`skills/using-superpowers/SKILL.md:22, 26`** — instruction-priority list. The list already names all three (CLAUDE.md, GEMINI.md, AGENTS.md) inclusively, which is correct: the section is making a real claim about *what counts as user instruction* on a multi-platform plugin. No change needed.
|
||||
- **Historical / example artifacts**:
|
||||
- `skills/systematic-debugging/CREATION-LOG.md` — attribution path (`~/.claude/CLAUDE.md`) is a historical fact.
|
||||
- `skills/writing-skills/examples/CLAUDE_MD_TESTING.md` — the entire file is a worked example testing CLAUDE.md content variants. The filename, body, and the reference from `testing-skills-with-subagents.md` all stay; normalizing them defeats the example.
|
||||
- **Platform-tooling references** — Phase D candidates:
|
||||
- `skills/using-superpowers/SKILL.md:40` (Gemini CLI tool mapping note about GEMINI.md)
|
||||
- `skills/using-superpowers/references/gemini-tools.md` (`save_memory` persists to GEMINI.md)
|
||||
|
||||
## Substitution rules
|
||||
|
||||
Two distinct calls, one per in-scope line.
|
||||
|
||||
### Rule 1: "where to put project-specific conventions"
|
||||
|
||||
`writing-skills/SKILL.md:58`:
|
||||
|
||||
- **Before:** `Project-specific conventions (put in CLAUDE.md)`
|
||||
- **After:** `Project-specific conventions (put in your instructions file)`
|
||||
|
||||
Use a generic phrase rather than picking one filename. Different harnesses read different files (CLAUDE.md, AGENTS.md, GEMINI.md, etc.) and the skill should not assume one. The platform-tools reference docs (`references/{codex,copilot,gemini}-tools.md`) are the right place to name each platform's preferred file.
|
||||
|
||||
### Rule 2: the "(explicit CLAUDE.md violation)" parenthetical
|
||||
|
||||
`receiving-code-review/SKILL.md:30`:
|
||||
|
||||
- **Before:** `"You're absolutely right!" (explicit CLAUDE.md violation)`
|
||||
- **After:** `"You're absolutely right!" (explicit instruction-file violation)`
|
||||
|
||||
The parenthetical is doing real work — it signals this phrase isn't just stylistically bad, it actively violates rules many users put in their instruction files. "Instruction file" is the natural cross-platform term covering AGENTS.md / CLAUDE.md / GEMINI.md collectively, and keeps the original signal without picking one filename or softening to "common".
|
||||
|
||||
## Commit plan
|
||||
|
||||
Atomic commits, in order:
|
||||
|
||||
1. **`writing-skills/SKILL.md`** — CLAUDE.md → "your instructions file" in the "where to put project conventions" line
|
||||
2. **`receiving-code-review/SKILL.md`** — CLAUDE.md → instruction-file in the violation parenthetical
|
||||
3. **Platform-tools reference docs** — add the preferred per-platform instructions filename (CLAUDE.md, AGENTS.md, GEMINI.md, etc.) to each `references/{codex,copilot,gemini}-tools.md` so readers can resolve "your instructions file" to a real filename.
|
||||
|
||||
Each commit message names "Phase B" and the slice.
|
||||
|
||||
## Verification
|
||||
|
||||
After each commit:
|
||||
|
||||
- Read the surrounding paragraph to confirm grammar and meaning still parse.
|
||||
- `grep -n "CLAUDE\.md" <touched-file>` — no remaining hits in active prose (carve-outs already documented).
|
||||
|
||||
After both commits:
|
||||
|
||||
- `grep -rn "CLAUDE\.md" skills/` should return only the documented carve-outs (CREATION-LOG, CLAUDE_MD_TESTING and its inbound reference, the priority list in using-superpowers).
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Do not touch the priority list ordering in `using-superpowers/SKILL.md`. Reordering CLAUDE.md / GEMINI.md / AGENTS.md is an aesthetic change, not a substitution, and out of scope here.
|
||||
- Do not rename `examples/CLAUDE_MD_TESTING.md` or change its content.
|
||||
- Do not modify Gemini-CLI-specific tooling references (Phase D candidates).
|
||||
|
||||
## Implementation note
|
||||
|
||||
Phase B as written here covered three commits and the three non-Claude-Code platform-tools refs. Implementation went one step further: a fourth ref, `references/claude-code-tools.md`, was added in commit `8505703` for symmetry, so Claude Code's instructions-file conventions and tool-name list live alongside the others rather than implicitly in the surrounding skill prose. That addition wasn't anticipated in this spec but is consistent with its intent.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Platform-neutral prose — Phase A design
|
||||
|
||||
## Background
|
||||
|
||||
Superpowers ships to multiple agent runtimes (Claude Code, Codex, Cursor, OpenCode, Copilot CLI, Gemini CLI). Skill content and supporting docs were written first for Claude Code and use "Claude" in places where any runtime's agent applies. OpenAI's vendored fork (openai/plugins#217) attempted a wholesale rewrite that was actively wrong in places — rewriting historical attribution paths, model names, and platform-specific install instructions — and we want to avoid that mistake while still removing platform-centric prose where it is genuinely incidental.
|
||||
|
||||
The full effort is broken into phases by reference category. **This spec covers Phase A only:** generic third-person prose mentioning "Claude" in non-platform-specific contexts. Later phases (config-file references, marketing copy, tool-name references) are out of scope here and will get their own specs.
|
||||
|
||||
## In scope
|
||||
|
||||
Generic prose mentions of "Claude" in:
|
||||
|
||||
- `skills/*/SKILL.md` and supporting `.md` files in active skill directories
|
||||
- `skills/writing-skills/anthropic-best-practices.md`
|
||||
- `README.md` (only where the mention is generic prose, not platform marketing)
|
||||
|
||||
Plus one coined-term rename: **Claude Search Optimization (CSO) → Skill Discovery Optimization (SDO)** in `skills/writing-skills/SKILL.md`.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- **Platform/runtime statements** — "In Claude Code:", install instructions, tool-mapping references. (Phase D candidate.)
|
||||
- **Config-file references** — CLAUDE.md, AGENTS.md, GEMINI.md priority lists and "where to put project conventions" callouts. (Phase B.)
|
||||
- **Tool-name references** — `Skill`, `Bash`, `Read`, `Task`, `TodoWrite`. Skills are written in Claude Code's tool vocabulary; the existing `references/{codex,copilot,gemini}-tools.md` files map them. (At the time this spec was written, the plan was to defer or skip these. Phase E ended up doing them — replacing tool names with action language across active skills and unifying the platform-tools refs around the same vocabulary.)
|
||||
- **Marketing copy** in README — "Superpowers for Claude Code", platform-named install sections. (Phase C.)
|
||||
- **Historical artifacts** — `docs/plans/*.md`, `docs/superpowers/specs/*.md`, `CREATION-LOG.md`. These are dated, point-in-time documents; rewriting them rewrites history.
|
||||
- **Model identifiers** — Claude Haiku / Sonnet / Opus. These are real product names.
|
||||
- **Filename / URL references** — `CLAUDE.md`, `claude.com`, `claude-plugin/`, paths under `~/.claude/`.
|
||||
- **`anthropic-best-practices.md` filename** — the file remains named after its source even though we rewrite the prose inside it.
|
||||
|
||||
## Replacement style
|
||||
|
||||
Use a mix that reads naturally in English:
|
||||
|
||||
- **Second person — "your agent"** when addressing the skill author about *their* runtime
|
||||
- "your agent reads the description"
|
||||
- **Third person — "the agent" / "agents" / "an agent"** when describing system behavior generically
|
||||
- "Future agents find your skills"
|
||||
- "Use words an agent would search for"
|
||||
- "Agents read SKILL.md only when the skill becomes relevant"
|
||||
|
||||
Pick whichever fits the surrounding sentence; do not force consistency at the cost of awkward phrasing. Pluralize when natural ("future agents", "agents read") rather than always saying "the agent".
|
||||
|
||||
### Carve-outs that stay as "Claude"
|
||||
|
||||
- Model names: Claude Haiku, Claude Sonnet, Claude Opus
|
||||
- Filenames and URLs: `CLAUDE.md`, `claude.com`, `~/.claude/`
|
||||
- Branded platform name "Claude Code" wherever it refers to the runtime as such (handled in later phases)
|
||||
|
||||
### Coined-term rename
|
||||
|
||||
- **Claude Search Optimization (CSO) → Skill Discovery Optimization (SDO)**
|
||||
- Appears in `skills/writing-skills/SKILL.md` as a section heading and in nearby prose. Rename the heading, the acronym, and any in-file cross-references.
|
||||
|
||||
## Files affected
|
||||
|
||||
Approximate counts based on a `grep` filtered to exclude carve-outs:
|
||||
|
||||
| File | Generic-prose mentions |
|
||||
|------|------------------------|
|
||||
| `skills/writing-skills/SKILL.md` | ~12 (includes CSO heading + body) |
|
||||
| `skills/writing-skills/anthropic-best-practices.md` | ~30 |
|
||||
| `skills/writing-skills/examples/CLAUDE_MD_TESTING.md` | ~1 — filename stays (it's a CLAUDE.md test artifact); the "Variant C: Claude.AI Emphatic Style" heading also stays (it's a label naming a specific style) |
|
||||
| `README.md` | ~1 |
|
||||
|
||||
Final list confirmed during implementation by re-running the filtered grep.
|
||||
|
||||
## Commit plan
|
||||
|
||||
Four atomic commits, in order:
|
||||
|
||||
1. **Rename CSO → SDO** in `skills/writing-skills/SKILL.md`. Mechanical, isolated, easy to revert if we change our minds about the term.
|
||||
2. **Active skills prose** — generic "Claude" → "agent" forms across `skills/*/SKILL.md` and supporting `.md`, excluding `anthropic-best-practices.md`.
|
||||
3. **`anthropic-best-practices.md` prose** — same substitution rules. Separate commit because this file is a vendored adaptation of an external doc; isolating the change makes future reconciliation with upstream easier to read.
|
||||
4. **README.md prose** *(only if any generic-prose mentions remain after filtering)*. Skipped if empty.
|
||||
|
||||
Each commit message names the phase ("Phase A") and the slice ("rename CSO to SDO", "agent prose in active skills", etc.) so the series is self-documenting.
|
||||
|
||||
## Verification
|
||||
|
||||
After each commit:
|
||||
|
||||
- `grep -rn "Claude" <touched-paths>` — every remaining hit must fall into a documented carve-out (model name, filename, URL, "Claude Code" platform name, historical artifact).
|
||||
- Read the touched file end-to-end — substitutions should not have broken sentence flow, pronoun agreement, or list parallelism.
|
||||
- No tests to run; this is prose-only.
|
||||
|
||||
After the final commit:
|
||||
|
||||
- Skim each modified skill in a live session to confirm nothing reads awkwardly.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Do not change behavior, structure, headings (other than CSO→SDO), examples, code blocks, or YAML frontmatter.
|
||||
- Do not introduce new sections, callouts, or compatibility notes.
|
||||
- Do not "improve" prose beyond the substitution while editing.
|
||||
@@ -0,0 +1,47 @@
|
||||
# Platform-neutral README ordering — Phase C design
|
||||
|
||||
## Background
|
||||
|
||||
Phases A and B (see `2026-05-05-platform-neutral-prose-design.md` and `2026-05-05-platform-neutral-config-refs-design.md`) already neutralized generic Claude prose and config-file references in the README. The remaining platform-leaning signal is layout: the README's two platform listings put Claude Code first and aren't strictly alphabetical elsewhere.
|
||||
|
||||
This phase fixes the ordering. No prose changes.
|
||||
|
||||
## In scope
|
||||
|
||||
1. **Quickstart platform list** (`README.md:7`) — the inline link list of supported harnesses
|
||||
2. **Installation section ordering** (`README.md:35–152`) — the per-harness install sub-sections
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Prose, marketplace names, plugin IDs, URLs — all factually correct as-is.
|
||||
- Visual weight of the Claude Code section (which has two sub-sections — official Anthropic marketplace and Superpowers marketplace). Both are real install paths; collapsing them would hide accurate info.
|
||||
- Section headings and content within each install block — only the ordering of the blocks changes.
|
||||
|
||||
## Substitution
|
||||
|
||||
Both listings reorder to strict alphabetical:
|
||||
|
||||
| Old order | New order |
|
||||
|-----------|-----------|
|
||||
| Claude Code | Claude Code |
|
||||
| Codex CLI | Codex App |
|
||||
| Codex App | Codex CLI |
|
||||
| Factory Droid | Cursor |
|
||||
| Gemini CLI | Factory Droid |
|
||||
| OpenCode | Gemini CLI |
|
||||
| Cursor | GitHub Copilot CLI |
|
||||
| GitHub Copilot CLI | OpenCode |
|
||||
|
||||
Three moves: Codex App swaps with Codex CLI; Cursor moves up two slots; GitHub Copilot CLI moves up one.
|
||||
|
||||
Claude Code remains first by alphabetical chance (`Cl…` precedes `Co…`).
|
||||
|
||||
## Commit plan
|
||||
|
||||
One atomic commit covering both listings, since changing one without the other would create inconsistency between the quickstart and the installation section.
|
||||
|
||||
## Verification
|
||||
|
||||
- Quickstart anchors (`#claude-code`, `#codex-app`, etc.) still resolve to existing `### …` headings — no headings renamed.
|
||||
- Each install sub-section's body is byte-identical pre/post; only positions changed.
|
||||
- `git diff README.md` shows section moves only, no content edits.
|
||||
@@ -0,0 +1,247 @@
|
||||
# Lift drill into superpowers as `evals/` — design
|
||||
|
||||
## Background
|
||||
|
||||
Drill is a Python skill-compliance benchmark that lives in its own repo at `obra/drill`. It drives real tmux sessions, runs an LLM actor as a simulated user, runs an LLM verifier on the resulting transcript, and reports pass/fail per scenario. It supports Claude Code, Codex, Gemini CLI, and (per recent commits) OpenCode and Copilot CLI.
|
||||
|
||||
Drill is already the *de facto* eval harness for superpowers. The PRI-1397 commit series in the drill repo lifted ~22 superpowers bash tests into drill scenarios, and the most recent superpowers commit (`a2292c5`) explicitly removed a redundant bash test with the message *"replaced by drill behavioral coverage"*. Migration momentum exists; this spec completes it.
|
||||
|
||||
This work moves drill into superpowers under `evals/`, deletes the redundant bash tests after per-file verification of drill scenario coverage, and updates docs so contributors land on the new structure.
|
||||
|
||||
## Goals
|
||||
|
||||
1. `evals/` is the canonical eval harness in superpowers — full drill source, scenarios, fixtures, prompts, backend configs, and tests.
|
||||
2. Bash tests in `superpowers/tests/` that have been individually verified as 100% covered by drill scenarios are deleted; the rest are preserved.
|
||||
3. The split between `tests/` (plugin infrastructure: bash + node + python integration tests) and `evals/` (LLM behavior with actor + verifier) is meaningful and documented.
|
||||
4. Top-level docs (`README.md`, `CLAUDE.md`, `docs/testing.md`) point contributors at the right place.
|
||||
5. The standalone `obra/drill` repo continues to exist (this PR does not touch it) and gets archived as a separate manual step after this PR merges.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- **CI integration.** Manual-only here. The natural follow-up is "tiered": fast subset on every PR, full sweep nightly + on-demand. That requires API budget decisions, GitHub Actions secrets, and a runner image with `tmux` + `node` + `python` + `claude` / `codex` / `gemini` CLIs installed. Out of scope.
|
||||
- **Scenario co-location with skills.** Scenarios stay centralized at `evals/scenarios/`. If we later decide each skill should own its scenarios, that's a path-find-and-rename operation; the YAML format does not change.
|
||||
- **Renaming the internal Python package** (`drill` → `evals`). The directory is `evals/` (user-facing); the Python package keeps its `drill` name to keep the diff small. A short note in `evals/README.md` explains.
|
||||
- **Drill repo archival.** This PR does not touch `obra/drill`. After merge, the drill repo is archived manually (read-only on GitHub, README pointer to `obra/superpowers/evals/`).
|
||||
- **Lifting `tests/claude-code/analyze-token-usage.py` into `evals/bin/`.** Useful utility, not test code. Can move later; not required by this PR.
|
||||
|
||||
## Branching
|
||||
|
||||
Branch off `dev` as `f/evals-lift`. This work is independent of the open `f/cross-platform` PR — no shared file changes besides possibly `README.md`, which is small enough to resolve at merge time if it conflicts.
|
||||
|
||||
## Architecture after the move
|
||||
|
||||
```
|
||||
superpowers/
|
||||
evals/ ← NEW (full drill copy)
|
||||
pyproject.toml (Python 3.11, uv-managed)
|
||||
uv.lock
|
||||
.gitignore (drill's own; results/, .venv/, .env)
|
||||
README.md (was drill's README; install instructions updated)
|
||||
CLAUDE.md (was drill's CLAUDE.md; paths updated)
|
||||
docs/
|
||||
design.md (drill's design — preserved verbatim, cross-linked from this spec)
|
||||
manual-testing.md
|
||||
pressure-and-red-testing.md
|
||||
drill/ (Python package; name kept; cli, engine, actor, verifier, etc.)
|
||||
backends/ (claude-*.yaml, codex.yaml, gemini.yaml)
|
||||
scenarios/ (32+ YAML scenarios)
|
||||
setup_helpers/ (15 Python helpers; create_base_repo, sdd_*, spec_*, worktree, etc.)
|
||||
fixtures/ (template-repo, sdd-go-fractals, sdd-svelte-todo)
|
||||
prompts/ (actor.md, verifier.md)
|
||||
bin/ (assertion helper scripts: tool-called, tool-count, etc.)
|
||||
tests/ (drill's own pytest suite)
|
||||
|
||||
tests/ ← bash tests preserved by default
|
||||
brainstorm-server/ ← KEEP (node tests for brainstorm-server JS code)
|
||||
opencode/ ← KEEP (plugin loading tests)
|
||||
codex-plugin-sync/ ← KEEP (sync verification)
|
||||
claude-code/ ← MOSTLY KEEP — see deletion gate
|
||||
explicit-skill-requests/ ← KEEP unless verified replaced
|
||||
skill-triggering/ ← KEEP unless verified replaced
|
||||
subagent-driven-dev/ ← KEEP unless verified replaced
|
||||
|
||||
docs/
|
||||
testing.md ← UPDATED (split into "Plugin tests" + "Skill behavior evals")
|
||||
superpowers/
|
||||
specs/
|
||||
2026-05-06-lift-drill-into-evals-design.md ← THIS SPEC
|
||||
|
||||
README.md ← small Contributing-section pointer to evals/
|
||||
CLAUDE.md ← one-line "Eval harness lives at evals/" pointer
|
||||
```
|
||||
|
||||
The `tests/` and `evals/` directories serve clearly distinct roles after this PR:
|
||||
|
||||
- **`tests/`** — does the plugin's non-LLM code work? Unit and integration tests for the brainstorm-server JS code, OpenCode plugin loading, codex-plugin-sync sync verification. Bash + node + python.
|
||||
- **`evals/`** — do agents behave correctly on real LLM sessions? Drill scenarios with actor + verifier. Python-only, runs real tmux sessions.
|
||||
|
||||
## Deletion gate (per bash test)
|
||||
|
||||
A bash test is deleted *only if* a drill scenario verifiably covers every assertion it makes. The implementation plan documents this verification per file: read the bash test, list its checks, find the drill scenario, confirm each check has a matching `verify.assertions` or `verify.criteria` entry. If even one check is missing, the option is to either extend the drill scenario or keep the bash test. Default keeps it.
|
||||
|
||||
**Tentative coverage map** (commit-message-based; needs per-file verification before any deletion):
|
||||
|
||||
| Bash test | Claimed drill replacement | Coverage status |
|
||||
|-----------|---------------------------|-----------------|
|
||||
| `tests/skill-triggering/prompts/*` (6 prompt files) | `triggering-*.yaml` (6 scenarios) | candidate — verify per-prompt before deleting |
|
||||
| `tests/skill-triggering/run-test.sh`, `run-all.sh` | n/a (runners, not tests) | **keep** — runner scripts |
|
||||
| `tests/explicit-skill-requests/prompts/please-use-brainstorming.txt` | needs verification — drill has no obvious counterpart yet | likely **keep** unless drill scenario added |
|
||||
| `tests/explicit-skill-requests/prompts/use-systematic-debugging.txt` | needs verification — drill has no obvious counterpart | likely **keep** unless drill scenario added |
|
||||
| `tests/explicit-skill-requests/run-claude-describes-sdd.sh` | partially → `mid-conversation-skill-invocation.yaml` | candidate — verify per-script |
|
||||
| `tests/explicit-skill-requests/run-haiku-test.sh` | no drill scenario covers Haiku-specific behavior | **keep** |
|
||||
| `tests/explicit-skill-requests/run-multiturn-test.sh`, `run-extended-multiturn-test.sh` | no drill scenario covers multi-turn build-up | **keep** unless drill scenarios added |
|
||||
| `tests/explicit-skill-requests/run-test.sh`, `run-all.sh` | n/a (runners) | **keep** |
|
||||
| `tests/subagent-driven-dev/go-fractals/`, `tests/subagent-driven-dev/svelte-todo/` | `sdd-go-fractals.yaml`, `sdd-svelte-todo.yaml` | candidate — verify before deleting (these include real assertions about test suites passing) |
|
||||
| `tests/claude-code/test-document-review-system.sh` | `spec-reviewer-catches-planted-flaws.yaml` | candidate — verify before deleting |
|
||||
| `tests/claude-code/test-requesting-code-review.sh` | `code-review-catches-planted-bugs.yaml` | candidate — verify before deleting |
|
||||
| `tests/claude-code/test-subagent-driven-development-integration.sh` | `sdd-rejects-extra-features.yaml` (YAGNI subset) | **partial** — bash test also asserts ≥3 commits / `npm test` passes / runs `analyze-token-usage.py`. Drill scenario asserts forbidden-exports + reviewer-as-gate. Mostly disjoint — almost certainly **keep + extend drill scenario**. |
|
||||
| `tests/claude-code/test-subagent-driven-development.sh` | meta/documentation test (asks agent to *describe* SDD); no drill scenario covers description tests | **keep** unless drill scenario added |
|
||||
| `tests/claude-code/test-worktree-native-preference.sh` | `worktree-creation-under-pressure.yaml` | candidate — verify before deleting |
|
||||
| `tests/claude-code/test-helpers.sh`, `run-skill-tests.sh`, `analyze-token-usage.py` | n/a (utilities, not tests) | **keep** — libraries/tools |
|
||||
|
||||
## Verification protocol (subagent-gated)
|
||||
|
||||
Every change in the implementation plan gets cross-checked by an independent subagent before commit.
|
||||
|
||||
| Change category | Subagent verification |
|
||||
|----------------|----------------------|
|
||||
| Each bash-test deletion | Dispatch a subagent with: (a) the bash test file content, (b) the candidate drill scenario YAML, (c) the prompt: *"List every assertion the bash test makes. List every verify entry in the drill scenario. For each bash assertion, find a matching drill check or report it as unmatched. Output a per-assertion table."* The subagent's output is the gate — only delete if every bash assertion has a match. |
|
||||
| Initial `evals/` copy | Subagent verifies: (a) drill SHA being copied is recorded in the lift commit message so provenance is auditable; (b) **per-file SHA-256 checksum** matches drill repo for every file (not just file count); (c) excluded paths (`.git/`, `.venv/`, `results/`, `.env`, `__pycache__/`, `*.egg-info/`, any `.private-journal/`) are absent from `evals/`; (d) all backend YAMLs reference paths that exist post-move; (e) `pyproject.toml`, `uv.lock`, `.gitignore` are intact. |
|
||||
| Drill's own pytest suite | Subagent runs `cd evals && uv run pytest` after the path-default change. Drill ships its own pytest suite at `evals/tests/` including `test_backend.py` which exercises `SUPERPOWERS_ROOT` env-var behavior — these tests must update to match the helper and continue to pass. |
|
||||
| Reference scrubbing after deletion | Subagent greps the entire superpowers tree (excluding `node_modules/`, `.venv/`, and `evals/`) for references to deleted bash test paths. Search targets: `docs/`, `docs/superpowers/plans/`, `RELEASE-NOTES.md`, `CLAUDE.md`, `GEMINI.md`, `AGENTS.md`, `README.md`, `.github/`, `scripts/`, `.opencode/INSTALL.md`, `.codex-plugin/INSTALL.md`, `lefthook.yml`. Any hit is either updated or surfaces a missed dependency. |
|
||||
| Path defaults change (`SUPERPOWERS_ROOT` default) | Subagent runs at least one cheap drill scenario after the path changes (e.g., `triggering-test-driven-development`) and confirms it still passes. Real validation, not just code review. |
|
||||
| Final pre-PR adversarial review | Two subagents in parallel, "5 points to whoever finds the most legitimate issues" framing — same protocol used on the cross-platform PR. Verify both source code and behavior. |
|
||||
|
||||
Each subagent task gets its own bullet in the implementation plan with explicit inputs and pass criteria. The subagent's output is summarized in the relevant commit message ("Subagent verification: …") so the trail is auditable.
|
||||
|
||||
## Concrete path/config edits
|
||||
|
||||
**Verified prior to writing this spec.** `drill/cli.py` defines `PROJECT_ROOT = Path(__file__).parent.parent`. After the move, `cli.py` lives at `evals/drill/cli.py`, so `PROJECT_ROOT` resolves to `evals/` and `PROJECT_ROOT.parent` resolves to the superpowers repo root. That's the value `SUPERPOWERS_ROOT` should take by default.
|
||||
|
||||
**YAML substitution audit.** Only the four `claude*.yaml` backend configs interpolate `${SUPERPOWERS_ROOT}` into `args` (for the `--plugin-dir` flag); `codex.yaml` and `gemini.yaml` only list `SUPERPOWERS_ROOT` in `required_env` (consumed by `engine.py:233` / `setup.py:25`'s `os.environ["SUPERPOWERS_ROOT"]` lookups in pre/post-run hooks). The helper's `os.environ` mutation covers both code paths.
|
||||
|
||||
| File | Current | After |
|
||||
|------|---------|-------|
|
||||
| `drill/cli.py` | `load_dotenv(PROJECT_ROOT / ".env")` at module import; nothing about `SUPERPOWERS_ROOT` | After `load_dotenv`, call new helper `_set_superpowers_root_default()` that sets `os.environ["SUPERPOWERS_ROOT"]` to `str(PROJECT_ROOT.parent)` if and only if not already set. Order: `load_dotenv` → set default → click group definitions. |
|
||||
| `drill/engine.py:233`, `drill/setup.py:25` | Direct `os.environ["SUPERPOWERS_ROOT"]` access (KeyError if unset) | Unchanged. The CLI startup hook guarantees the env var is set by the time the engine/setup execute. |
|
||||
| `backends/claude*.yaml` (5 files) | `${SUPERPOWERS_ROOT}` substituted in `args` for `--plugin-dir` | Unchanged. YAML substitution reads `os.environ` at backend-load time, which is after CLI startup. |
|
||||
| `backends/codex.yaml`, `backends/gemini.yaml` | `SUPERPOWERS_ROOT` in `required_env` only | Drop from `required_env` (the helper supplies it). `claude*.yaml` keep `required_env` for backward compat (env var works as override). |
|
||||
| `evals/tests/test_backend.py` | Tests assert `SUPERPOWERS_ROOT` is in `required_env` lists, plus path-resolution tests | Update tests to match the new contract: helper-supplied default, env override still works, `required_env` no longer required for codex/gemini. |
|
||||
| `evals/README.md` | "export SUPERPOWERS_ROOT=/path/to/superpowers" | Drop the export line; note that the env var auto-defaults to the parent of `evals/`; mention the only required setup is `ANTHROPIC_API_KEY` (or `OPENAI_API_KEY` / Gemini auth). |
|
||||
| `evals/CLAUDE.md` | Same | Same |
|
||||
| `evals/.gitignore` | drill's existing patterns (`results/`, `.venv/`, `__pycache__/`, `.env`, `*.pyc`, `*.egg-info/`, `dist/`, `build/`, `.claude/`) | Copied verbatim. Patterns are relative to file location, so they apply correctly under `evals/`. |
|
||||
| `evals/lefthook.yml` | drill ships `lefthook.yml` defining `pre-commit: uv run ruff check && uv run ty check` | Move to `evals/lefthook.yml`. Either (a) install lefthook at the superpowers root and have it federate to `evals/lefthook.yml`, or (b) document that contributors run `cd evals && lefthook run pre-commit` manually. **Decision in implementation: option (b) for simplicity** — superpowers' top-level workflow doesn't change. |
|
||||
|
||||
`.env` placement: keep `evals/.env` (gitignored). Contributors source it from there or set `ANTHROPIC_API_KEY` in their shell environment.
|
||||
|
||||
**Top-level superpowers files needing small additions:**
|
||||
|
||||
- `superpowers/.gitignore`: add `evals/results/`, `evals/.venv/`, `evals/.env` (belt-and-suspenders; evals/.gitignore already covers these locally).
|
||||
- `superpowers/CLAUDE.md`: add a one-line pointer "Eval harness lives at `evals/` — see `evals/README.md`" so agents discover it.
|
||||
- `superpowers/docs/testing.md`: split into "## Plugin tests" (existing tests/ content, with the deleted-test references trimmed) and "## Skill behavior evals" (one-paragraph summary + pointer to `evals/`).
|
||||
- `superpowers/README.md`: add a single line in the Contributing section pointing at `evals/` for skill-behavior testing.
|
||||
|
||||
## Migration ordering
|
||||
|
||||
Each step is a separate commit (or small group of commits). Step 2 is the biggest single commit (the verbatim drill copy); subsequent steps are small and atomic.
|
||||
|
||||
```
|
||||
1. Branch off `dev` (f/evals-lift)
|
||||
|
||||
2. Copy drill repo into evals/ (single commit, easy to revert)
|
||||
├─ Record drill SHA at copy time → commit message
|
||||
├─ Use `rsync -a --exclude=.git --exclude=.venv --exclude=results
|
||||
│ --exclude=.env --exclude=__pycache__ --exclude='*.egg-info'
|
||||
│ --exclude=.private-journal /path/to/drill/ evals/`
|
||||
│ (rsync chosen over `cp -r` for explicit excludes; verify with
|
||||
│ `find evals -name '.git' -type d` returns nothing)
|
||||
├─ Subagent gate: per-file SHA-256 checksum matches drill repo for every
|
||||
│ non-excluded file; excluded paths absent from evals/
|
||||
└─ Smoke check: `cd evals && uv sync` succeeds (proves install only;
|
||||
not a behavioral test)
|
||||
|
||||
3. Update path defaults
|
||||
├─ Add _set_superpowers_root_default() helper to drill/cli.py
|
||||
├─ Wire it after load_dotenv, before click group definition
|
||||
├─ Update evals/README.md and evals/CLAUDE.md (drop SUPERPOWERS_ROOT install step)
|
||||
├─ Drop SUPERPOWERS_ROOT from required_env in codex.yaml/gemini.yaml
|
||||
│ (keep in claude*.yaml as override)
|
||||
└─ Update evals/tests/test_backend.py to match new contract
|
||||
|
||||
4. Validate from new location (TWO checks)
|
||||
├─ Run drill's own pytest: `cd evals && uv run pytest` — must pass
|
||||
└─ Run cheap drill scenario: `cd evals && uv run drill run
|
||||
triggering-test-driven-development -b claude` — must pass.
|
||||
Real behavioral validation, not just code review.
|
||||
|
||||
5. Bash test deletion phase — per-file with subagent gate
|
||||
For each file in the candidate-deletion list:
|
||||
a. Subagent compares bash test assertions vs drill scenario verify block
|
||||
b. Pass criterion: every bash assertion has a matching drill check
|
||||
c. If pass → delete the bash test file (one commit per file or per
|
||||
coherent group)
|
||||
d. If fail → either extend drill scenario (separate commit + verify) or
|
||||
keep the bash test (no commit)
|
||||
|
||||
6. Stale-reference scrub
|
||||
├─ Subagent greps the superpowers tree (excluding node_modules/, .venv/,
|
||||
│ evals/) for deleted file paths
|
||||
├─ Search targets: docs/, docs/superpowers/plans/, RELEASE-NOTES.md,
|
||||
│ CLAUDE.md, GEMINI.md, AGENTS.md, README.md, .github/, scripts/,
|
||||
│ .opencode/INSTALL.md, .codex-plugin/INSTALL.md, lefthook.yml
|
||||
├─ Update active references (e.g., docs/testing.md, README.md install)
|
||||
└─ Historical references in docs/superpowers/plans/*.md and
|
||||
RELEASE-NOTES.md are PRESERVED with a brief annotation
|
||||
("(test removed; behavior covered by drill scenario X)") rather
|
||||
than rewritten — these are dated artifacts, not living docs.
|
||||
|
||||
7. Top-level docs
|
||||
├─ docs/testing.md split
|
||||
├─ CLAUDE.md pointer
|
||||
└─ README.md Contributing section
|
||||
|
||||
8. Re-run smoke checks (regression gate)
|
||||
├─ `cd evals && uv run pytest`
|
||||
└─ `cd evals && uv run drill run triggering-test-driven-development -b claude`
|
||||
|
||||
9. Final adversarial review
|
||||
└─ Two parallel subagents, full diff, "5 points to whoever finds the
|
||||
most legitimate issues" framing. Address findings before push.
|
||||
|
||||
10. Push branch + open PR against dev
|
||||
└─ PR description includes: drill SHA pinned at copy, archival action
|
||||
item ("after merge: archive obra/drill, add README pointer to
|
||||
obra/superpowers/evals/"), per-deleted-file coverage receipts.
|
||||
```
|
||||
|
||||
## Verification (post-implementation)
|
||||
|
||||
The implementation plan must show:
|
||||
|
||||
- All non-excluded drill source files present at `evals/` after step 2 (subagent **per-file SHA-256 checksum diff** vs `obra/drill@<recorded-sha>`).
|
||||
- Excluded paths (`.git/`, `.venv/`, `results/`, `.env`, `__pycache__/`, `*.egg-info/`, `.private-journal/`) absent from `evals/`.
|
||||
- The step-2 commit message records the drill source SHA.
|
||||
- `cd evals && uv sync` succeeds without `SUPERPOWERS_ROOT` set.
|
||||
- `cd evals && uv run pytest` passes (drill's own pytest suite).
|
||||
- `cd evals && uv run drill list` returns the same scenario count as the standalone drill repo at the recorded SHA.
|
||||
- `cd evals && uv run drill run triggering-test-driven-development -b claude` passes (proves path defaults work end-to-end).
|
||||
- For each deleted bash test: subagent verification table in the commit message showing every assertion mapped to a drill check.
|
||||
- Grep for deleted file paths returns zero hits across living superpowers docs (post step 6); historical refs in `docs/superpowers/plans/*.md` and `RELEASE-NOTES.md` are annotated, not rewritten.
|
||||
- `docs/testing.md` has both "Plugin tests" and "Skill behavior evals" sections.
|
||||
- The drill repo's history is untouched; `obra/drill` is unaffected by this PR.
|
||||
- PR description names the action item to archive `obra/drill` after merge.
|
||||
|
||||
## Open questions
|
||||
|
||||
None. All clarifying decisions have been made:
|
||||
|
||||
| Question | Decision |
|
||||
|----------|----------|
|
||||
| Where does drill live in superpowers? | `evals/` (rename from drill); standalone repo archived as separate step |
|
||||
| Fate of redundant bash tests? | Delete per-file with subagent verification of coverage; default keep |
|
||||
| Scenarios layout? | Centralized at `evals/scenarios/` |
|
||||
| Python toolchain placement? | Self-contained at `evals/` |
|
||||
| CI integration? | Manual-only this PR; documented future path |
|
||||
| Migration mechanics? | Plain copy; drill repo's history preserved in archived repo, not in-tree |
|
||||
| Internal Python package name? | Keep as `drill` (directory is `evals/`) |
|
||||
| Branching strategy? | Independent off `dev` (not stacked on `f/cross-platform`) |
|
||||
313
docs/testing.md
313
docs/testing.md
@@ -1,303 +1,34 @@
|
||||
# Testing Superpowers Skills
|
||||
# Testing Superpowers
|
||||
|
||||
This document describes how to test Superpowers skills, particularly the integration tests for complex skills like `subagent-driven-development`.
|
||||
Superpowers has two distinct kinds of tests, each in its own directory:
|
||||
|
||||
## Overview
|
||||
- **`tests/`** — does the plugin's non-LLM code work? Bash + node + python integration tests for brainstorm-server JS, OpenCode plugin loading, codex-plugin sync, and analysis utilities.
|
||||
- **`evals/`** — do agents behave correctly on real LLM sessions? Python harness driving real tmux sessions of Claude Code / Codex / Gemini CLI, with an LLM actor and verifier judging skill compliance.
|
||||
|
||||
Testing skills that involve subagents, workflows, and complex interactions requires running actual Claude Code sessions in headless mode and verifying their behavior through session transcripts.
|
||||
## Plugin tests
|
||||
|
||||
## Test Structure
|
||||
Live in `tests/`. Currently:
|
||||
|
||||
```
|
||||
tests/
|
||||
├── claude-code/
|
||||
│ ├── test-helpers.sh # Shared test utilities
|
||||
│ ├── test-subagent-driven-development-integration.sh
|
||||
│ ├── analyze-token-usage.py # Token analysis tool
|
||||
│ └── run-skill-tests.sh # Test runner (if exists)
|
||||
```
|
||||
- `tests/brainstorm-server/` — node test suite for the brainstorm server JS code.
|
||||
- `tests/opencode/` — bash tests for OpenCode plugin loading, bootstrap caching, and tool registration.
|
||||
- `tests/codex-plugin-sync/` — bash sync verification.
|
||||
- `tests/claude-code/test-helpers.sh`, `analyze-token-usage.py` — utilities used by remaining bash tests.
|
||||
- `tests/claude-code/test-subagent-driven-development.sh` — agent-can-describe-SDD test (no drill counterpart; tests description-recall, not behavior).
|
||||
- `tests/claude-code/test-subagent-driven-development-integration.sh` — extended SDD integration with token analysis (drill covers the YAGNI subset; bash adds commit-count, Claude Code task-tracking, and token telemetry assertions).
|
||||
- `tests/claude-code/test-worktree-native-preference.sh` — RED-GREEN-REFACTOR validation for worktree skill (drill covers the PRESSURE phase; bash also covers RED/GREEN baselines).
|
||||
- `tests/explicit-skill-requests/` — Haiku-specific, multi-turn, and skill-name-prompted tests not covered by drill.
|
||||
|
||||
## Running Tests
|
||||
Run plugin tests via the relevant directory's `run-*.sh` or `npm test`.
|
||||
|
||||
### Integration Tests
|
||||
## Skill behavior evals
|
||||
|
||||
Integration tests execute real Claude Code sessions with actual skills:
|
||||
Live in `evals/`. Drill is the harness; scenarios live at `evals/scenarios/*.yaml`. See `evals/README.md` for setup. Quick start:
|
||||
|
||||
```bash
|
||||
# Run the subagent-driven-development integration test
|
||||
cd tests/claude-code
|
||||
./test-subagent-driven-development-integration.sh
|
||||
cd evals
|
||||
uv sync --extra dev
|
||||
export ANTHROPIC_API_KEY=sk-...
|
||||
uv run drill run triggering-test-driven-development -b claude
|
||||
```
|
||||
|
||||
**Note:** Integration tests can take 10-30 minutes as they execute real implementation plans with multiple subagents.
|
||||
|
||||
### Requirements
|
||||
|
||||
- Must run from the **superpowers plugin directory** (not from temp directories)
|
||||
- Claude Code must be installed and available as `claude` command
|
||||
- Local dev marketplace must be enabled: `"superpowers@superpowers-dev": true` in `~/.claude/settings.json`
|
||||
|
||||
## Integration Test: subagent-driven-development
|
||||
|
||||
### What It Tests
|
||||
|
||||
The integration test verifies the `subagent-driven-development` skill correctly:
|
||||
|
||||
1. **Plan Loading**: Reads the plan once at the beginning
|
||||
2. **Full Task Text**: Provides complete task descriptions to subagents (doesn't make them read files)
|
||||
3. **Self-Review**: Ensures subagents perform self-review before reporting
|
||||
4. **Review Order**: Runs spec compliance review before code quality review
|
||||
5. **Review Loops**: Uses review loops when issues are found
|
||||
6. **Independent Verification**: Spec reviewer reads code independently, doesn't trust implementer reports
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Setup**: Creates a temporary Node.js project with a minimal implementation plan
|
||||
2. **Execution**: Runs Claude Code in headless mode with the skill
|
||||
3. **Verification**: Parses the session transcript (`.jsonl` file) to verify:
|
||||
- Skill tool was invoked
|
||||
- Subagents were dispatched (Task tool)
|
||||
- TodoWrite was used for tracking
|
||||
- Implementation files were created
|
||||
- Tests pass
|
||||
- Git commits show proper workflow
|
||||
4. **Token Analysis**: Shows token usage breakdown by subagent
|
||||
|
||||
### Test Output
|
||||
|
||||
```
|
||||
========================================
|
||||
Integration Test: subagent-driven-development
|
||||
========================================
|
||||
|
||||
Test project: /tmp/tmp.xyz123
|
||||
|
||||
=== Verification Tests ===
|
||||
|
||||
Test 1: Skill tool invoked...
|
||||
[PASS] subagent-driven-development skill was invoked
|
||||
|
||||
Test 2: Subagents dispatched...
|
||||
[PASS] 7 subagents dispatched
|
||||
|
||||
Test 3: Task tracking...
|
||||
[PASS] TodoWrite used 5 time(s)
|
||||
|
||||
Test 6: Implementation verification...
|
||||
[PASS] src/math.js created
|
||||
[PASS] add function exists
|
||||
[PASS] multiply function exists
|
||||
[PASS] test/math.test.js created
|
||||
[PASS] Tests pass
|
||||
|
||||
Test 7: Git commit history...
|
||||
[PASS] Multiple commits created (3 total)
|
||||
|
||||
Test 8: No extra features added...
|
||||
[PASS] No extra features added
|
||||
|
||||
=========================================
|
||||
Token Usage Analysis
|
||||
=========================================
|
||||
|
||||
Usage Breakdown:
|
||||
----------------------------------------------------------------------------------------------------
|
||||
Agent Description Msgs Input Output Cache Cost
|
||||
----------------------------------------------------------------------------------------------------
|
||||
main Main session (coordinator) 34 27 3,996 1,213,703 $ 4.09
|
||||
3380c209 implementing Task 1: Create Add Function 1 2 787 24,989 $ 0.09
|
||||
34b00fde implementing Task 2: Create Multiply Function 1 4 644 25,114 $ 0.09
|
||||
3801a732 reviewing whether an implementation matches... 1 5 703 25,742 $ 0.09
|
||||
4c142934 doing a final code review... 1 6 854 25,319 $ 0.09
|
||||
5f017a42 a code reviewer. Review Task 2... 1 6 504 22,949 $ 0.08
|
||||
a6b7fbe4 a code reviewer. Review Task 1... 1 6 515 22,534 $ 0.08
|
||||
f15837c0 reviewing whether an implementation matches... 1 6 416 22,485 $ 0.07
|
||||
----------------------------------------------------------------------------------------------------
|
||||
|
||||
TOTALS:
|
||||
Total messages: 41
|
||||
Input tokens: 62
|
||||
Output tokens: 8,419
|
||||
Cache creation tokens: 132,742
|
||||
Cache read tokens: 1,382,835
|
||||
|
||||
Total input (incl cache): 1,515,639
|
||||
Total tokens: 1,524,058
|
||||
|
||||
Estimated cost: $4.67
|
||||
(at $3/$15 per M tokens for input/output)
|
||||
|
||||
========================================
|
||||
Test Summary
|
||||
========================================
|
||||
|
||||
STATUS: PASSED
|
||||
```
|
||||
|
||||
## Token Analysis Tool
|
||||
|
||||
### Usage
|
||||
|
||||
Analyze token usage from any Claude Code session:
|
||||
|
||||
```bash
|
||||
python3 tests/claude-code/analyze-token-usage.py ~/.claude/projects/<project-dir>/<session-id>.jsonl
|
||||
```
|
||||
|
||||
### Finding Session Files
|
||||
|
||||
Session transcripts are stored in `~/.claude/projects/` with the working directory path encoded:
|
||||
|
||||
```bash
|
||||
# Example for /Users/jesse/Documents/GitHub/superpowers/superpowers
|
||||
SESSION_DIR="$HOME/.claude/projects/-Users-jesse-Documents-GitHub-superpowers-superpowers"
|
||||
|
||||
# Find recent sessions
|
||||
ls -lt "$SESSION_DIR"/*.jsonl | head -5
|
||||
```
|
||||
|
||||
### What It Shows
|
||||
|
||||
- **Main session usage**: Token usage by the coordinator (you or main Claude instance)
|
||||
- **Per-subagent breakdown**: Each Task invocation with:
|
||||
- Agent ID
|
||||
- Description (extracted from prompt)
|
||||
- Message count
|
||||
- Input/output tokens
|
||||
- Cache usage
|
||||
- Estimated cost
|
||||
- **Totals**: Overall token usage and cost estimate
|
||||
|
||||
### Understanding the Output
|
||||
|
||||
- **High cache reads**: Good - means prompt caching is working
|
||||
- **High input tokens on main**: Expected - coordinator has full context
|
||||
- **Similar costs per subagent**: Expected - each gets similar task complexity
|
||||
- **Cost per task**: Typical range is $0.05-$0.15 per subagent depending on task
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skills Not Loading
|
||||
|
||||
**Problem**: Skill not found when running headless tests
|
||||
|
||||
**Solutions**:
|
||||
1. Ensure you're running FROM the superpowers directory: `cd /path/to/superpowers && tests/...`
|
||||
2. Check `~/.claude/settings.json` has `"superpowers@superpowers-dev": true` in `enabledPlugins`
|
||||
3. Verify skill exists in `skills/` directory
|
||||
|
||||
### Permission Errors
|
||||
|
||||
**Problem**: Claude blocked from writing files or accessing directories
|
||||
|
||||
**Solutions**:
|
||||
1. Use `--permission-mode bypassPermissions` flag
|
||||
2. Use `--add-dir /path/to/temp/dir` to grant access to test directories
|
||||
3. Check file permissions on test directories
|
||||
|
||||
### Test Timeouts
|
||||
|
||||
**Problem**: Test takes too long and times out
|
||||
|
||||
**Solutions**:
|
||||
1. Increase timeout: `timeout 1800 claude ...` (30 minutes)
|
||||
2. Check for infinite loops in skill logic
|
||||
3. Review subagent task complexity
|
||||
|
||||
### Session File Not Found
|
||||
|
||||
**Problem**: Can't find session transcript after test run
|
||||
|
||||
**Solutions**:
|
||||
1. Check the correct project directory in `~/.claude/projects/`
|
||||
2. Use `find ~/.claude/projects -name "*.jsonl" -mmin -60` to find recent sessions
|
||||
3. Verify test actually ran (check for errors in test output)
|
||||
|
||||
## Writing New Integration Tests
|
||||
|
||||
### Template
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/test-helpers.sh"
|
||||
|
||||
# Create test project
|
||||
TEST_PROJECT=$(create_test_project)
|
||||
trap "cleanup_test_project $TEST_PROJECT" EXIT
|
||||
|
||||
# Set up test files...
|
||||
cd "$TEST_PROJECT"
|
||||
|
||||
# Run Claude with skill
|
||||
PROMPT="Your test prompt here"
|
||||
cd "$SCRIPT_DIR/../.." && timeout 1800 claude -p "$PROMPT" \
|
||||
--allowed-tools=all \
|
||||
--add-dir "$TEST_PROJECT" \
|
||||
--permission-mode bypassPermissions \
|
||||
2>&1 | tee output.txt
|
||||
|
||||
# Find and analyze session
|
||||
WORKING_DIR_ESCAPED=$(echo "$SCRIPT_DIR/../.." | sed 's/\\//-/g' | sed 's/^-//')
|
||||
SESSION_DIR="$HOME/.claude/projects/$WORKING_DIR_ESCAPED"
|
||||
SESSION_FILE=$(find "$SESSION_DIR" -name "*.jsonl" -type f -mmin -60 | sort -r | head -1)
|
||||
|
||||
# Verify behavior by parsing session transcript
|
||||
if grep -q '"name":"Skill".*"skill":"your-skill-name"' "$SESSION_FILE"; then
|
||||
echo "[PASS] Skill was invoked"
|
||||
fi
|
||||
|
||||
# Show token analysis
|
||||
python3 "$SCRIPT_DIR/analyze-token-usage.py" "$SESSION_FILE"
|
||||
```
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Always cleanup**: Use trap to cleanup temp directories
|
||||
2. **Parse transcripts**: Don't grep user-facing output - parse the `.jsonl` session file
|
||||
3. **Grant permissions**: Use `--permission-mode bypassPermissions` and `--add-dir`
|
||||
4. **Run from plugin dir**: Skills only load when running from the superpowers directory
|
||||
5. **Show token usage**: Always include token analysis for cost visibility
|
||||
6. **Test real behavior**: Verify actual files created, tests passing, commits made
|
||||
|
||||
## Session Transcript Format
|
||||
|
||||
Session transcripts are JSONL (JSON Lines) files where each line is a JSON object representing a message or tool result.
|
||||
|
||||
### Key Fields
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "assistant",
|
||||
"message": {
|
||||
"content": [...],
|
||||
"usage": {
|
||||
"input_tokens": 27,
|
||||
"output_tokens": 3996,
|
||||
"cache_read_input_tokens": 1213703
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Tool Results
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "user",
|
||||
"toolUseResult": {
|
||||
"agentId": "3380c209",
|
||||
"usage": {
|
||||
"input_tokens": 2,
|
||||
"output_tokens": 787,
|
||||
"cache_read_input_tokens": 24989
|
||||
},
|
||||
"prompt": "You are implementing Task 1...",
|
||||
"content": [{"type": "text", "text": "..."}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `agentId` field links to subagent sessions, and the `usage` field contains token usage for that specific subagent invocation.
|
||||
Drill scenarios are slow (3-30+ minutes each) and run real LLM sessions. They are not part of CI today; the natural follow-up is a tiered model (fast subset on PR, full sweep nightly + on-demand).
|
||||
|
||||
@@ -148,7 +148,7 @@ exit /b
|
||||
CMDBLOCK
|
||||
|
||||
# Unix shell runs from here
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT_NAME="$1"
|
||||
shift
|
||||
"${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
||||
|
||||
1
evals
Submodule
1
evals
Submodule
Submodule evals added at e2b37138c8
6
gemini-extension.json
Normal file
6
gemini-extension.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "5.1.0",
|
||||
"contextFileName": "GEMINI.md"
|
||||
}
|
||||
16
hooks/hooks-codex.json
Normal file
16
hooks/hooks-codex.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "startup|resume|clear",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "\"${PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start-codex",
|
||||
"async": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
10
hooks/hooks-cursor.json
Normal file
10
hooks/hooks-cursor.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 1,
|
||||
"hooks": {
|
||||
"sessionStart": [
|
||||
{
|
||||
"command": "./hooks/run-hook.cmd session-start"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "startup|resume|clear|compact",
|
||||
"matcher": "startup|clear|compact",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd session-start",
|
||||
"async": true
|
||||
"command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd\" session-start",
|
||||
"async": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ exit /b 0
|
||||
CMDBLOCK
|
||||
|
||||
# Unix: run the named script directly
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT_NAME="$1"
|
||||
shift
|
||||
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
||||
|
||||
@@ -4,16 +4,9 @@
|
||||
set -euo pipefail
|
||||
|
||||
# Determine plugin root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
# Check if legacy skills directory exists and build warning
|
||||
warning_message=""
|
||||
legacy_skills_dir="${HOME}/.config/superpowers/skills"
|
||||
if [ -d "$legacy_skills_dir" ]; then
|
||||
warning_message="\n\n<important-reminder>IN YOUR FIRST REPLY AFTER SEEING THIS MESSAGE YOU MUST TELL THE USER:⚠️ **WARNING:** Superpowers now uses Claude Code's skills system. Custom skills in ~/.config/superpowers/skills will not be read. Move custom skills to ~/.claude/skills instead. To make this message go away, remove ~/.config/superpowers/skills</important-reminder>"
|
||||
fi
|
||||
|
||||
# Read using-superpowers content
|
||||
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
|
||||
|
||||
@@ -31,16 +24,26 @@ escape_for_json() {
|
||||
}
|
||||
|
||||
using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
|
||||
warning_escaped=$(escape_for_json "$warning_message")
|
||||
session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${using_superpowers_escaped}\n</EXTREMELY_IMPORTANT>"
|
||||
|
||||
# Output context injection as JSON
|
||||
cat <<EOF
|
||||
{
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
# Output context injection as JSON.
|
||||
# Cursor hooks expect additional_context (snake_case).
|
||||
# Claude Code hooks expect hookSpecificOutput.additionalContext (nested).
|
||||
# Copilot CLI (v1.0.11+) and others expect additionalContext (top-level, SDK standard).
|
||||
# Claude Code reads BOTH additional_context and hookSpecificOutput without
|
||||
# deduplication, so we must emit only the field the current platform consumes.
|
||||
#
|
||||
# Uses printf instead of heredoc to work around bash 5.3+ heredoc hang.
|
||||
# See: https://github.com/obra/superpowers/issues/571
|
||||
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
|
||||
# Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT)
|
||||
printf '{\n "additional_context": "%s"\n}\n' "$session_context"
|
||||
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
|
||||
# Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI
|
||||
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
|
||||
else
|
||||
# Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format
|
||||
printf '{\n "additionalContext": "%s"\n}\n' "$session_context"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
26
hooks/session-start-codex
Executable file
26
hooks/session-start-codex
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
# Codex SessionStart hook for superpowers plugin
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
|
||||
|
||||
escape_for_json() {
|
||||
local s="$1"
|
||||
s="${s//\\/\\\\}"
|
||||
s="${s//\"/\\\"}"
|
||||
s="${s//$'\n'/\\n}"
|
||||
s="${s//$'\r'/\\r}"
|
||||
s="${s//$'\t'/\\t}"
|
||||
printf '%s' "$s"
|
||||
}
|
||||
|
||||
using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
|
||||
session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, follow the Codex skill-loading instructions in that skill:**\n\n${using_superpowers_escaped}\n</EXTREMELY_IMPORTANT>"
|
||||
|
||||
printf '{\n "hookSpecificOutput": {\n "hookEventName": "SessionStart",\n "additionalContext": "%s"\n }\n}\n' "$session_context"
|
||||
|
||||
exit 0
|
||||
@@ -1,139 +0,0 @@
|
||||
(function() {
|
||||
const WS_URL = 'ws://' + window.location.host;
|
||||
let ws = null;
|
||||
let eventQueue = [];
|
||||
|
||||
function connect() {
|
||||
ws = new WebSocket(WS_URL);
|
||||
|
||||
ws.onopen = () => {
|
||||
eventQueue.forEach(e => ws.send(JSON.stringify(e)));
|
||||
eventQueue = [];
|
||||
};
|
||||
|
||||
ws.onmessage = (msg) => {
|
||||
const data = JSON.parse(msg.data);
|
||||
if (data.type === 'reload') {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
}
|
||||
|
||||
function sendEvent(event) {
|
||||
event.timestamp = Date.now();
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify(event));
|
||||
} else {
|
||||
eventQueue.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-capture clicks on interactive elements
|
||||
document.addEventListener('click', (e) => {
|
||||
const target = e.target.closest('button, a, [data-choice], [role="button"], input[type="submit"]');
|
||||
if (!target) return;
|
||||
|
||||
// Don't capture regular link navigation
|
||||
if (target.tagName === 'A' && !target.dataset.choice) return;
|
||||
|
||||
// Don't capture the Send feedback button (handled by send())
|
||||
if (target.id === 'send-feedback') return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
sendEvent({
|
||||
type: 'click',
|
||||
text: target.textContent.trim(),
|
||||
choice: target.dataset.choice || null,
|
||||
id: target.id || null,
|
||||
className: target.className || null
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-capture form submissions
|
||||
document.addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const form = e.target;
|
||||
const formData = new FormData(form);
|
||||
const data = {};
|
||||
formData.forEach((value, key) => { data[key] = value; });
|
||||
|
||||
sendEvent({
|
||||
type: 'submit',
|
||||
formId: form.id || null,
|
||||
formName: form.name || null,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-capture input changes (debounced)
|
||||
let inputTimeout = null;
|
||||
document.addEventListener('input', (e) => {
|
||||
const target = e.target;
|
||||
if (!target.matches('input, textarea, select')) return;
|
||||
|
||||
clearTimeout(inputTimeout);
|
||||
inputTimeout = setTimeout(() => {
|
||||
sendEvent({
|
||||
type: 'input',
|
||||
name: target.name || null,
|
||||
id: target.id || null,
|
||||
value: target.value,
|
||||
inputType: target.type || target.tagName.toLowerCase()
|
||||
});
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Send to Claude - triggers feedback delivery
|
||||
function sendToClaude(feedback) {
|
||||
sendEvent({
|
||||
type: 'send-to-claude',
|
||||
feedback: feedback || null
|
||||
});
|
||||
// Show themed confirmation page
|
||||
document.body.innerHTML = `
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif; background: var(--bg-primary, #f5f5f7);">
|
||||
<div style="text-align: center; color: var(--text-secondary, #86868b);">
|
||||
<h2 style="color: var(--text-primary, #1d1d1f); margin-bottom: 0.5rem;">Sent to Claude</h2>
|
||||
<p>Return to the terminal to see Claude's response.</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Frame UI: selection tracking and feedback send
|
||||
window.selectedChoice = null;
|
||||
|
||||
window.toggleSelect = function(el) {
|
||||
const container = el.closest('.options') || el.closest('.cards');
|
||||
if (container) {
|
||||
container.querySelectorAll('.option, .card').forEach(o => o.classList.remove('selected'));
|
||||
}
|
||||
el.classList.add('selected');
|
||||
window.selectedChoice = el.dataset.choice;
|
||||
};
|
||||
|
||||
window.send = function() {
|
||||
const feedbackEl = document.getElementById('feedback');
|
||||
const feedback = feedbackEl ? feedbackEl.value.trim() : '';
|
||||
const payload = {};
|
||||
if (window.selectedChoice) payload.choice = window.selectedChoice;
|
||||
if (feedback) payload.feedback = feedback;
|
||||
if (Object.keys(payload).length === 0) return;
|
||||
sendToClaude(payload);
|
||||
if (feedbackEl) feedbackEl.value = '';
|
||||
};
|
||||
|
||||
// Expose API for explicit use
|
||||
window.brainstorm = {
|
||||
send: sendEvent,
|
||||
choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata }),
|
||||
sendToClaude: sendToClaude
|
||||
};
|
||||
|
||||
connect();
|
||||
})();
|
||||
@@ -1,132 +0,0 @@
|
||||
const express = require('express');
|
||||
const http = require('http');
|
||||
const WebSocket = require('ws');
|
||||
const chokidar = require('chokidar');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const PORT = process.env.BRAINSTORM_PORT || (49152 + Math.floor(Math.random() * 16383));
|
||||
const SCREEN_DIR = process.env.BRAINSTORM_DIR || '/tmp/brainstorm';
|
||||
|
||||
if (!fs.existsSync(SCREEN_DIR)) {
|
||||
fs.mkdirSync(SCREEN_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
// Load frame template and helper script once at startup
|
||||
const frameTemplate = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf-8');
|
||||
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
|
||||
const helperInjection = `<script>\n${helperScript}\n</script>`;
|
||||
|
||||
// Detect whether content is a full HTML document or a bare fragment
|
||||
function isFullDocument(html) {
|
||||
const trimmed = html.trimStart().toLowerCase();
|
||||
return trimmed.startsWith('<!doctype') || trimmed.startsWith('<html');
|
||||
}
|
||||
|
||||
// Wrap a content fragment in the frame template
|
||||
function wrapInFrame(content) {
|
||||
return frameTemplate.replace(
|
||||
/(<div id="claude-content">)[\s\S]*?(<\/div>\s*<\/div>\s*<div class="feedback-footer">)/,
|
||||
`$1\n ${content}\n $2`
|
||||
);
|
||||
}
|
||||
|
||||
// Find the newest .html file in the directory by mtime
|
||||
function getNewestScreen() {
|
||||
const files = fs.readdirSync(SCREEN_DIR)
|
||||
.filter(f => f.endsWith('.html'))
|
||||
.map(f => ({
|
||||
name: f,
|
||||
path: path.join(SCREEN_DIR, f),
|
||||
mtime: fs.statSync(path.join(SCREEN_DIR, f)).mtime.getTime()
|
||||
}))
|
||||
.sort((a, b) => b.mtime - a.mtime);
|
||||
|
||||
return files.length > 0 ? files[0].path : null;
|
||||
}
|
||||
|
||||
const WAITING_PAGE = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Brainstorm Companion</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
|
||||
h1 { color: #333; }
|
||||
p { color: #666; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Brainstorm Companion</h1>
|
||||
<p>Waiting for Claude to push a screen...</p>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const wss = new WebSocket.Server({ server });
|
||||
|
||||
const clients = new Set();
|
||||
|
||||
wss.on('connection', (ws) => {
|
||||
clients.add(ws);
|
||||
ws.on('close', () => clients.delete(ws));
|
||||
|
||||
ws.on('message', (data) => {
|
||||
const event = JSON.parse(data.toString());
|
||||
console.log(JSON.stringify({ source: 'user-event', ...event }));
|
||||
});
|
||||
});
|
||||
|
||||
// Serve newest screen with helper.js injected
|
||||
app.get('/', (req, res) => {
|
||||
const screenFile = getNewestScreen();
|
||||
let html;
|
||||
|
||||
if (!screenFile) {
|
||||
html = WAITING_PAGE;
|
||||
} else {
|
||||
const raw = fs.readFileSync(screenFile, 'utf-8');
|
||||
html = isFullDocument(raw) ? raw : wrapInFrame(raw);
|
||||
}
|
||||
|
||||
// Inject helper script
|
||||
if (html.includes('</body>')) {
|
||||
html = html.replace('</body>', `${helperInjection}\n</body>`);
|
||||
} else {
|
||||
html += helperInjection;
|
||||
}
|
||||
|
||||
res.type('html').send(html);
|
||||
});
|
||||
|
||||
// Watch for new or changed .html files
|
||||
chokidar.watch(SCREEN_DIR, { ignoreInitial: true })
|
||||
.on('add', (filePath) => {
|
||||
if (filePath.endsWith('.html')) {
|
||||
console.log(JSON.stringify({ type: 'screen-added', file: filePath }));
|
||||
clients.forEach(ws => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify({ type: 'reload' }));
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.on('change', (filePath) => {
|
||||
if (filePath.endsWith('.html')) {
|
||||
console.log(JSON.stringify({ type: 'screen-updated', file: filePath }));
|
||||
clients.forEach(ws => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify({ type: 'reload' }));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(PORT, '127.0.0.1', () => {
|
||||
console.log(JSON.stringify({
|
||||
type: 'server-started',
|
||||
port: PORT,
|
||||
url: `http://localhost:${PORT}`,
|
||||
screen_dir: SCREEN_DIR
|
||||
}));
|
||||
});
|
||||
1036
lib/brainstorm-server/package-lock.json
generated
1036
lib/brainstorm-server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"name": "brainstorm-server",
|
||||
"version": "1.0.0",
|
||||
"description": "Visual brainstorming companion server for Claude Code",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.3",
|
||||
"express": "^4.18.2",
|
||||
"ws": "^8.14.2"
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Start the brainstorm server and output connection info
|
||||
# Usage: start-server.sh [--project-dir <path>]
|
||||
#
|
||||
# Starts server on a random high port, outputs JSON with URL.
|
||||
# Each session gets its own directory to avoid conflicts.
|
||||
#
|
||||
# Options:
|
||||
# --project-dir <path> Store session files under <path>/.superpowers/brainstorm/
|
||||
# instead of /tmp. Files persist after server stops.
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# Parse arguments
|
||||
PROJECT_DIR=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--project-dir)
|
||||
PROJECT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
*)
|
||||
echo "{\"error\": \"Unknown argument: $1\"}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Generate unique session directory
|
||||
SESSION_ID="$$-$(date +%s)"
|
||||
|
||||
if [[ -n "$PROJECT_DIR" ]]; then
|
||||
SCREEN_DIR="${PROJECT_DIR}/.superpowers/brainstorm/${SESSION_ID}"
|
||||
else
|
||||
SCREEN_DIR="/tmp/brainstorm-${SESSION_ID}"
|
||||
fi
|
||||
|
||||
PID_FILE="${SCREEN_DIR}/.server.pid"
|
||||
LOG_FILE="${SCREEN_DIR}/.server.log"
|
||||
|
||||
# Create fresh session directory
|
||||
mkdir -p "$SCREEN_DIR"
|
||||
|
||||
# Kill any existing server
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
old_pid=$(cat "$PID_FILE")
|
||||
kill "$old_pid" 2>/dev/null
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
|
||||
# Start server, capturing output to log file
|
||||
cd "$SCRIPT_DIR"
|
||||
BRAINSTORM_DIR="$SCREEN_DIR" node index.js > "$LOG_FILE" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
echo "$SERVER_PID" > "$PID_FILE"
|
||||
|
||||
# Wait for server-started message (check log file)
|
||||
for i in {1..50}; do
|
||||
if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then
|
||||
grep "server-started" "$LOG_FILE" | head -1
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
# Timeout - server didn't start
|
||||
echo '{"error": "Server failed to start within 5 seconds"}'
|
||||
exit 1
|
||||
@@ -1,31 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Stop the brainstorm server and clean up
|
||||
# Usage: stop-server.sh <screen_dir>
|
||||
#
|
||||
# Kills the server process. Only deletes session directory if it's
|
||||
# under /tmp (ephemeral). Persistent directories (.superpowers/) are
|
||||
# kept so mockups can be reviewed later.
|
||||
|
||||
SCREEN_DIR="$1"
|
||||
|
||||
if [[ -z "$SCREEN_DIR" ]]; then
|
||||
echo '{"error": "Usage: stop-server.sh <screen_dir>"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PID_FILE="${SCREEN_DIR}/.server.pid"
|
||||
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
pid=$(cat "$PID_FILE")
|
||||
kill "$pid" 2>/dev/null
|
||||
rm -f "$PID_FILE" "${SCREEN_DIR}/.server.log"
|
||||
|
||||
# Only delete ephemeral /tmp directories
|
||||
if [[ "$SCREEN_DIR" == /tmp/* ]]; then
|
||||
rm -rf "$SCREEN_DIR"
|
||||
fi
|
||||
|
||||
echo '{"status": "stopped"}'
|
||||
else
|
||||
echo '{"status": "not_running"}'
|
||||
fi
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Wait for user feedback from the brainstorm browser
|
||||
# Usage: wait-for-feedback.sh <screen_dir>
|
||||
#
|
||||
# Blocks until user sends feedback, then outputs the JSON.
|
||||
# Write HTML to screen_file BEFORE calling this.
|
||||
|
||||
SCREEN_DIR="${1:?Usage: wait-for-feedback.sh <screen_dir>}"
|
||||
LOG_FILE="${SCREEN_DIR}/.server.log"
|
||||
|
||||
if [[ ! -d "$SCREEN_DIR" ]]; then
|
||||
echo '{"error": "Screen directory not found"}' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Record current position in log file
|
||||
LOG_POS=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
|
||||
# Poll for new lines containing the event
|
||||
while true; do
|
||||
RESULT=$(tail -n +$((LOG_POS + 1)) "$LOG_FILE" 2>/dev/null | grep -m 1 "send-to-claude")
|
||||
if [[ -n "$RESULT" ]]; then
|
||||
echo "$RESULT"
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
@@ -1,208 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
/**
|
||||
* Extract YAML frontmatter from a skill file.
|
||||
* Current format:
|
||||
* ---
|
||||
* name: skill-name
|
||||
* description: Use when [condition] - [what it does]
|
||||
* ---
|
||||
*
|
||||
* @param {string} filePath - Path to SKILL.md file
|
||||
* @returns {{name: string, description: string}}
|
||||
*/
|
||||
function extractFrontmatter(filePath) {
|
||||
try {
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const lines = content.split('\n');
|
||||
|
||||
let inFrontmatter = false;
|
||||
let name = '';
|
||||
let description = '';
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.trim() === '---') {
|
||||
if (inFrontmatter) break;
|
||||
inFrontmatter = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inFrontmatter) {
|
||||
const match = line.match(/^(\w+):\s*(.*)$/);
|
||||
if (match) {
|
||||
const [, key, value] = match;
|
||||
switch (key) {
|
||||
case 'name':
|
||||
name = value.trim();
|
||||
break;
|
||||
case 'description':
|
||||
description = value.trim();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { name, description };
|
||||
} catch (error) {
|
||||
return { name: '', description: '' };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all SKILL.md files in a directory recursively.
|
||||
*
|
||||
* @param {string} dir - Directory to search
|
||||
* @param {string} sourceType - 'personal' or 'superpowers' for namespacing
|
||||
* @param {number} maxDepth - Maximum recursion depth (default: 3)
|
||||
* @returns {Array<{path: string, name: string, description: string, sourceType: string}>}
|
||||
*/
|
||||
function findSkillsInDir(dir, sourceType, maxDepth = 3) {
|
||||
const skills = [];
|
||||
|
||||
if (!fs.existsSync(dir)) return skills;
|
||||
|
||||
function recurse(currentDir, depth) {
|
||||
if (depth > maxDepth) return;
|
||||
|
||||
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(currentDir, entry.name);
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
// Check for SKILL.md in this directory
|
||||
const skillFile = path.join(fullPath, 'SKILL.md');
|
||||
if (fs.existsSync(skillFile)) {
|
||||
const { name, description } = extractFrontmatter(skillFile);
|
||||
skills.push({
|
||||
path: fullPath,
|
||||
skillFile: skillFile,
|
||||
name: name || entry.name,
|
||||
description: description || '',
|
||||
sourceType: sourceType
|
||||
});
|
||||
}
|
||||
|
||||
// Recurse into subdirectories
|
||||
recurse(fullPath, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
recurse(dir, 0);
|
||||
return skills;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a skill name to its file path, handling shadowing
|
||||
* (personal skills override superpowers skills).
|
||||
*
|
||||
* @param {string} skillName - Name like "superpowers:brainstorming" or "my-skill"
|
||||
* @param {string} superpowersDir - Path to superpowers skills directory
|
||||
* @param {string} personalDir - Path to personal skills directory
|
||||
* @returns {{skillFile: string, sourceType: string, skillPath: string} | null}
|
||||
*/
|
||||
function resolveSkillPath(skillName, superpowersDir, personalDir) {
|
||||
// Strip superpowers: prefix if present
|
||||
const forceSuperpowers = skillName.startsWith('superpowers:');
|
||||
const actualSkillName = forceSuperpowers ? skillName.replace(/^superpowers:/, '') : skillName;
|
||||
|
||||
// Try personal skills first (unless explicitly superpowers:)
|
||||
if (!forceSuperpowers && personalDir) {
|
||||
const personalPath = path.join(personalDir, actualSkillName);
|
||||
const personalSkillFile = path.join(personalPath, 'SKILL.md');
|
||||
if (fs.existsSync(personalSkillFile)) {
|
||||
return {
|
||||
skillFile: personalSkillFile,
|
||||
sourceType: 'personal',
|
||||
skillPath: actualSkillName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Try superpowers skills
|
||||
if (superpowersDir) {
|
||||
const superpowersPath = path.join(superpowersDir, actualSkillName);
|
||||
const superpowersSkillFile = path.join(superpowersPath, 'SKILL.md');
|
||||
if (fs.existsSync(superpowersSkillFile)) {
|
||||
return {
|
||||
skillFile: superpowersSkillFile,
|
||||
sourceType: 'superpowers',
|
||||
skillPath: actualSkillName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a git repository has updates available.
|
||||
*
|
||||
* @param {string} repoDir - Path to git repository
|
||||
* @returns {boolean} - True if updates are available
|
||||
*/
|
||||
function checkForUpdates(repoDir) {
|
||||
try {
|
||||
// Quick check with 3 second timeout to avoid delays if network is down
|
||||
const output = execSync('git fetch origin && git status --porcelain=v1 --branch', {
|
||||
cwd: repoDir,
|
||||
timeout: 3000,
|
||||
encoding: 'utf8',
|
||||
stdio: 'pipe'
|
||||
});
|
||||
|
||||
// Parse git status output to see if we're behind
|
||||
const statusLines = output.split('\n');
|
||||
for (const line of statusLines) {
|
||||
if (line.startsWith('## ') && line.includes('[behind ')) {
|
||||
return true; // We're behind remote
|
||||
}
|
||||
}
|
||||
return false; // Up to date
|
||||
} catch (error) {
|
||||
// Network down, git error, timeout, etc. - don't block bootstrap
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip YAML frontmatter from skill content, returning just the content.
|
||||
*
|
||||
* @param {string} content - Full content including frontmatter
|
||||
* @returns {string} - Content without frontmatter
|
||||
*/
|
||||
function stripFrontmatter(content) {
|
||||
const lines = content.split('\n');
|
||||
let inFrontmatter = false;
|
||||
let frontmatterEnded = false;
|
||||
const contentLines = [];
|
||||
|
||||
for (const line of lines) {
|
||||
if (line.trim() === '---') {
|
||||
if (inFrontmatter) {
|
||||
frontmatterEnded = true;
|
||||
continue;
|
||||
}
|
||||
inFrontmatter = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frontmatterEnded || !inFrontmatter) {
|
||||
contentLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
return contentLines.join('\n').trim();
|
||||
}
|
||||
|
||||
export {
|
||||
extractFrontmatter,
|
||||
findSkillsInDir,
|
||||
resolveSkillPath,
|
||||
checkForUpdates,
|
||||
stripFrontmatter
|
||||
};
|
||||
23
package.json
Normal file
23
package.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"version": "5.1.0",
|
||||
"description": "Superpowers skills and runtime bootstrap for coding agents",
|
||||
"type": "module",
|
||||
"main": ".opencode/plugins/superpowers.js",
|
||||
"keywords": [
|
||||
"pi-package",
|
||||
"skills",
|
||||
"tdd",
|
||||
"debugging",
|
||||
"collaboration",
|
||||
"workflow"
|
||||
],
|
||||
"pi": {
|
||||
"extensions": [
|
||||
"./.pi/extensions/superpowers.ts"
|
||||
],
|
||||
"skills": [
|
||||
"./skills"
|
||||
]
|
||||
}
|
||||
}
|
||||
220
scripts/bump-version.sh
Executable file
220
scripts/bump-version.sh
Executable file
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# bump-version.sh — bump version numbers across all declared files,
|
||||
# with drift detection and repo-wide audit for missed files.
|
||||
#
|
||||
# Usage:
|
||||
# bump-version.sh <new-version> Bump all declared files to new version
|
||||
# bump-version.sh --check Report current versions (detect drift)
|
||||
# bump-version.sh --audit Check + grep repo for old version strings
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
CONFIG="$REPO_ROOT/.version-bump.json"
|
||||
|
||||
if [[ ! -f "$CONFIG" ]]; then
|
||||
echo "error: .version-bump.json not found at $CONFIG" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- helpers ---
|
||||
|
||||
# Read a dotted field path from a JSON file.
|
||||
# Handles both simple ("version") and nested ("plugins.0.version") paths.
|
||||
read_json_field() {
|
||||
local file="$1" field="$2"
|
||||
# Convert dot-path to jq path: "plugins.0.version" -> .plugins[0].version
|
||||
local jq_path
|
||||
jq_path=$(echo "$field" | sed -E 's/\.([0-9]+)/[\1]/g' | sed 's/^/./' | sed 's/\.\././g')
|
||||
jq -r "$jq_path" "$file"
|
||||
}
|
||||
|
||||
# Write a dotted field path in a JSON file, preserving formatting.
|
||||
write_json_field() {
|
||||
local file="$1" field="$2" value="$3"
|
||||
local jq_path
|
||||
jq_path=$(echo "$field" | sed -E 's/\.([0-9]+)/[\1]/g' | sed 's/^/./' | sed 's/\.\././g')
|
||||
local tmp="${file}.tmp"
|
||||
jq "$jq_path = \"$value\"" "$file" > "$tmp" && mv "$tmp" "$file"
|
||||
}
|
||||
|
||||
# Read the list of declared files from config.
|
||||
# Outputs lines of "path<TAB>field"
|
||||
declared_files() {
|
||||
jq -r '.files[] | "\(.path)\t\(.field)"' "$CONFIG"
|
||||
}
|
||||
|
||||
# Read the audit exclude patterns from config.
|
||||
audit_excludes() {
|
||||
jq -r '.audit.exclude[]' "$CONFIG" 2>/dev/null
|
||||
}
|
||||
|
||||
# --- commands ---
|
||||
|
||||
cmd_check() {
|
||||
local has_drift=0
|
||||
local versions=()
|
||||
|
||||
echo "Version check:"
|
||||
echo ""
|
||||
|
||||
while IFS=$'\t' read -r path field; do
|
||||
local fullpath="$REPO_ROOT/$path"
|
||||
if [[ ! -f "$fullpath" ]]; then
|
||||
printf " %-45s MISSING\n" "$path ($field)"
|
||||
has_drift=1
|
||||
continue
|
||||
fi
|
||||
local ver
|
||||
ver=$(read_json_field "$fullpath" "$field")
|
||||
printf " %-45s %s\n" "$path ($field)" "$ver"
|
||||
versions+=("$ver")
|
||||
done < <(declared_files)
|
||||
|
||||
echo ""
|
||||
|
||||
# Check if all versions match
|
||||
local unique
|
||||
unique=$(printf '%s\n' "${versions[@]}" | sort -u | wc -l | tr -d ' ')
|
||||
if [[ "$unique" -gt 1 ]]; then
|
||||
echo "DRIFT DETECTED — versions are not in sync:"
|
||||
printf '%s\n' "${versions[@]}" | sort | uniq -c | sort -rn | while read -r count ver; do
|
||||
echo " $ver ($count files)"
|
||||
done
|
||||
has_drift=1
|
||||
else
|
||||
echo "All declared files are in sync at ${versions[0]}"
|
||||
fi
|
||||
|
||||
return $has_drift
|
||||
}
|
||||
|
||||
cmd_audit() {
|
||||
# First run check
|
||||
cmd_check || true
|
||||
echo ""
|
||||
|
||||
# Determine the current version (most common across declared files)
|
||||
local current_version
|
||||
current_version=$(
|
||||
while IFS=$'\t' read -r path field; do
|
||||
local fullpath="$REPO_ROOT/$path"
|
||||
[[ -f "$fullpath" ]] && read_json_field "$fullpath" "$field"
|
||||
done < <(declared_files) | sort | uniq -c | sort -rn | head -1 | awk '{print $2}'
|
||||
)
|
||||
|
||||
if [[ -z "$current_version" ]]; then
|
||||
echo "error: could not determine current version" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Audit: scanning repo for version string '$current_version'..."
|
||||
echo ""
|
||||
|
||||
# Build grep exclude args
|
||||
local -a exclude_args=()
|
||||
while IFS= read -r pattern; do
|
||||
exclude_args+=("--exclude=$pattern" "--exclude-dir=$pattern")
|
||||
done < <(audit_excludes)
|
||||
|
||||
# Also always exclude binary files and .git
|
||||
exclude_args+=("--exclude-dir=.git" "--exclude-dir=node_modules" "--binary-files=without-match")
|
||||
|
||||
# Get list of declared paths for comparison
|
||||
local -a declared_paths=()
|
||||
while IFS=$'\t' read -r path _field; do
|
||||
declared_paths+=("$path")
|
||||
done < <(declared_files)
|
||||
|
||||
# Grep for the version string
|
||||
local found_undeclared=0
|
||||
while IFS= read -r match; do
|
||||
local match_file
|
||||
match_file=$(echo "$match" | cut -d: -f1)
|
||||
# Make path relative to repo root
|
||||
local rel_path="${match_file#$REPO_ROOT/}"
|
||||
|
||||
# Check if this file is in the declared list
|
||||
local is_declared=0
|
||||
for dp in "${declared_paths[@]}"; do
|
||||
if [[ "$rel_path" == "$dp" ]]; then
|
||||
is_declared=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$is_declared" -eq 0 ]]; then
|
||||
if [[ "$found_undeclared" -eq 0 ]]; then
|
||||
echo "UNDECLARED files containing '$current_version':"
|
||||
found_undeclared=1
|
||||
fi
|
||||
echo " $match"
|
||||
fi
|
||||
done < <(grep -rn "${exclude_args[@]}" -F "$current_version" "$REPO_ROOT" 2>/dev/null || true)
|
||||
|
||||
if [[ "$found_undeclared" -eq 0 ]]; then
|
||||
echo "No undeclared files contain the version string. All clear."
|
||||
else
|
||||
echo ""
|
||||
echo "Review the above files — if they should be bumped, add them to .version-bump.json"
|
||||
echo "If they should be skipped, add them to the audit.exclude list."
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_bump() {
|
||||
local new_version="$1"
|
||||
|
||||
# Validate semver-ish format
|
||||
if ! echo "$new_version" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
|
||||
echo "error: '$new_version' doesn't look like a version (expected X.Y.Z)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Bumping all declared files to $new_version..."
|
||||
echo ""
|
||||
|
||||
while IFS=$'\t' read -r path field; do
|
||||
local fullpath="$REPO_ROOT/$path"
|
||||
if [[ ! -f "$fullpath" ]]; then
|
||||
echo " SKIP (missing): $path"
|
||||
continue
|
||||
fi
|
||||
local old_ver
|
||||
old_ver=$(read_json_field "$fullpath" "$field")
|
||||
write_json_field "$fullpath" "$field" "$new_version"
|
||||
printf " %-45s %s -> %s\n" "$path ($field)" "$old_ver" "$new_version"
|
||||
done < <(declared_files)
|
||||
|
||||
echo ""
|
||||
echo "Done. Running audit to check for missed files..."
|
||||
echo ""
|
||||
cmd_audit
|
||||
}
|
||||
|
||||
# --- main ---
|
||||
|
||||
case "${1:-}" in
|
||||
--check)
|
||||
cmd_check
|
||||
;;
|
||||
--audit)
|
||||
cmd_audit
|
||||
;;
|
||||
--help|-h|"")
|
||||
echo "Usage: bump-version.sh <new-version> | --check | --audit"
|
||||
echo ""
|
||||
echo " <new-version> Bump all declared files to the given version"
|
||||
echo " --check Show current versions, detect drift"
|
||||
echo " --audit Check + scan repo for undeclared version references"
|
||||
exit 0
|
||||
;;
|
||||
--*)
|
||||
echo "error: unknown flag '$1'" >&2
|
||||
exit 1
|
||||
;;
|
||||
*)
|
||||
cmd_bump "$1"
|
||||
;;
|
||||
esac
|
||||
462
scripts/sync-to-codex-plugin.sh
Executable file
462
scripts/sync-to-codex-plugin.sh
Executable file
@@ -0,0 +1,462 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# sync-to-codex-plugin.sh
|
||||
#
|
||||
# Sync this superpowers checkout → prime-radiant-inc/openai-codex-plugins.
|
||||
# Clones the fork fresh into a temp dir, rsyncs tracked upstream plugin content
|
||||
# (including committed Codex files under .codex-plugin/ and assets/), preserves
|
||||
# OpenAI-owned marketplace metadata already in the destination plugin, commits,
|
||||
# pushes a sync branch, and opens a PR.
|
||||
# Path/user agnostic — auto-detects upstream from script location.
|
||||
#
|
||||
# Deterministic: running twice against the same upstream SHA produces PRs with
|
||||
# identical diffs, so two back-to-back runs can verify the tool itself.
|
||||
#
|
||||
# Usage:
|
||||
# ./scripts/sync-to-codex-plugin.sh # full run
|
||||
# ./scripts/sync-to-codex-plugin.sh -n # dry run
|
||||
# ./scripts/sync-to-codex-plugin.sh -y # skip confirm
|
||||
# ./scripts/sync-to-codex-plugin.sh --local PATH # existing checkout
|
||||
# ./scripts/sync-to-codex-plugin.sh --base BRANCH # default: main
|
||||
# ./scripts/sync-to-codex-plugin.sh --bootstrap # create plugin dir if missing
|
||||
#
|
||||
# Bootstrap mode: skips the "plugin must exist on base" requirement and creates
|
||||
# plugins/superpowers/ when absent, then copies the tracked plugin files from
|
||||
# upstream just like a normal sync.
|
||||
#
|
||||
# Requires: bash, rsync, git, gh (authenticated), python3.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# =============================================================================
|
||||
# Config — edit as upstream or canonical plugin shape evolves
|
||||
# =============================================================================
|
||||
|
||||
FORK="prime-radiant-inc/openai-codex-plugins"
|
||||
DEFAULT_BASE="main"
|
||||
DEST_REL="plugins/superpowers"
|
||||
|
||||
# Paths in upstream that should NOT land in the embedded plugin.
|
||||
# All patterns use a leading "/" to anchor them to the source root.
|
||||
# Unanchored patterns like "scripts/" would match any directory named
|
||||
# "scripts" at any depth — including legitimate nested dirs like
|
||||
# skills/brainstorming/scripts/. Anchoring prevents that.
|
||||
# (.DS_Store is intentionally unanchored — Finder creates them everywhere.)
|
||||
EXCLUDES=(
|
||||
# Dotfiles and infra — top-level only
|
||||
"/.claude/"
|
||||
"/.claude-plugin/"
|
||||
"/.codex/"
|
||||
"/.cursor-plugin/"
|
||||
"/.git/"
|
||||
"/.gitattributes"
|
||||
"/.github/"
|
||||
"/.gitignore"
|
||||
"/.opencode/"
|
||||
"/.version-bump.json"
|
||||
"/.worktrees/"
|
||||
".DS_Store"
|
||||
|
||||
# Root ceremony files
|
||||
"/AGENTS.md"
|
||||
"/CHANGELOG.md"
|
||||
"/CLAUDE.md"
|
||||
"/GEMINI.md"
|
||||
"/RELEASE-NOTES.md"
|
||||
"/gemini-extension.json"
|
||||
"/package.json"
|
||||
|
||||
# Directories not shipped by canonical Codex plugins
|
||||
"/commands/"
|
||||
"/docs/"
|
||||
"/evals/"
|
||||
"/lib/"
|
||||
"/scripts/"
|
||||
"/tests/"
|
||||
"/tmp/"
|
||||
)
|
||||
|
||||
# =============================================================================
|
||||
# Ignored-path helpers
|
||||
# =============================================================================
|
||||
|
||||
IGNORED_DIR_EXCLUDES=()
|
||||
|
||||
path_has_directory_exclude() {
|
||||
local path="$1"
|
||||
local dir
|
||||
|
||||
if [[ ${#IGNORED_DIR_EXCLUDES[@]} -eq 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
for dir in "${IGNORED_DIR_EXCLUDES[@]}"; do
|
||||
[[ "$path" == "$dir"* ]] && return 0
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
ignored_directory_has_tracked_descendants() {
|
||||
local path="$1"
|
||||
|
||||
[[ -n "$(git -C "$UPSTREAM" ls-files --cached -- "$path/")" ]]
|
||||
}
|
||||
|
||||
append_git_ignored_directory_excludes() {
|
||||
local path
|
||||
local lookup_path
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
[[ "$path" == */ ]] || continue
|
||||
|
||||
lookup_path="${path%/}"
|
||||
if ! ignored_directory_has_tracked_descendants "$lookup_path"; then
|
||||
IGNORED_DIR_EXCLUDES+=("$path")
|
||||
RSYNC_ARGS+=(--exclude="/$path")
|
||||
fi
|
||||
done < <(git -C "$UPSTREAM" ls-files --others --ignored --exclude-standard --directory -z)
|
||||
}
|
||||
|
||||
append_git_ignored_file_excludes() {
|
||||
local path
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
path_has_directory_exclude "$path" && continue
|
||||
RSYNC_ARGS+=(--exclude="/$path")
|
||||
done < <(git -C "$UPSTREAM" ls-files --others --ignored --exclude-standard -z)
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# Args
|
||||
# =============================================================================
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
UPSTREAM="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
BASE="$DEFAULT_BASE"
|
||||
DRY_RUN=0
|
||||
YES=0
|
||||
LOCAL_CHECKOUT=""
|
||||
BOOTSTRAP=0
|
||||
|
||||
usage() {
|
||||
sed -n '/^# Usage:/,/^# Requires:/s/^# \{0,1\}//p' "$0"
|
||||
exit "${1:-0}"
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-n|--dry-run) DRY_RUN=1; shift ;;
|
||||
-y|--yes) YES=1; shift ;;
|
||||
--local) LOCAL_CHECKOUT="$2"; shift 2 ;;
|
||||
--base) BASE="$2"; shift 2 ;;
|
||||
--bootstrap) BOOTSTRAP=1; shift ;;
|
||||
-h|--help) usage 0 ;;
|
||||
*) echo "Unknown arg: $1" >&2; usage 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# =============================================================================
|
||||
# Preflight
|
||||
# =============================================================================
|
||||
|
||||
die() { echo "ERROR: $*" >&2; exit 1; }
|
||||
|
||||
command -v rsync >/dev/null || die "rsync not found in PATH"
|
||||
command -v git >/dev/null || die "git not found in PATH"
|
||||
command -v gh >/dev/null || die "gh not found — install GitHub CLI"
|
||||
command -v python3 >/dev/null || die "python3 not found in PATH"
|
||||
|
||||
gh auth status >/dev/null 2>&1 || die "gh not authenticated — run 'gh auth login'"
|
||||
|
||||
[[ -d "$UPSTREAM/.git" ]] || die "upstream '$UPSTREAM' is not a git checkout"
|
||||
[[ -f "$UPSTREAM/.codex-plugin/plugin.json" ]] || die "committed Codex manifest missing at $UPSTREAM/.codex-plugin/plugin.json"
|
||||
|
||||
# Read the upstream version from the committed Codex manifest.
|
||||
UPSTREAM_VERSION="$(python3 -c 'import json,sys; print(json.load(open(sys.argv[1]))["version"])' "$UPSTREAM/.codex-plugin/plugin.json")"
|
||||
[[ -n "$UPSTREAM_VERSION" ]] || die "could not read 'version' from committed Codex manifest"
|
||||
|
||||
UPSTREAM_BRANCH="$(cd "$UPSTREAM" && git branch --show-current)"
|
||||
UPSTREAM_SHA="$(cd "$UPSTREAM" && git rev-parse HEAD)"
|
||||
UPSTREAM_SHORT="$(cd "$UPSTREAM" && git rev-parse --short HEAD)"
|
||||
|
||||
confirm() {
|
||||
[[ $YES -eq 1 ]] && return 0
|
||||
read -rp "$1 [y/N] " ans
|
||||
[[ "$ans" == "y" || "$ans" == "Y" ]]
|
||||
}
|
||||
|
||||
if [[ "$UPSTREAM_BRANCH" != "main" ]]; then
|
||||
echo "WARNING: upstream is on '$UPSTREAM_BRANCH', not 'main'"
|
||||
confirm "Sync from '$UPSTREAM_BRANCH' anyway?" || exit 1
|
||||
fi
|
||||
|
||||
UPSTREAM_STATUS="$(cd "$UPSTREAM" && git status --porcelain)"
|
||||
if [[ -n "$UPSTREAM_STATUS" ]]; then
|
||||
echo "WARNING: upstream has uncommitted changes:"
|
||||
echo "$UPSTREAM_STATUS" | sed 's/^/ /'
|
||||
echo "Sync will use working-tree state, not HEAD ($UPSTREAM_SHORT)."
|
||||
confirm "Continue anyway?" || exit 1
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Prepare destination (clone fork fresh, or use --local)
|
||||
# =============================================================================
|
||||
|
||||
CLEANUP_DIR=""
|
||||
cleanup() {
|
||||
if [[ -n "$CLEANUP_DIR" ]]; then
|
||||
rm -rf "$CLEANUP_DIR"
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
DEST_REPO="$(cd "$LOCAL_CHECKOUT" && pwd)"
|
||||
[[ -d "$DEST_REPO/.git" ]] || die "--local path '$DEST_REPO' is not a git checkout"
|
||||
else
|
||||
echo "Cloning $FORK..."
|
||||
CLEANUP_DIR="$(mktemp -d)"
|
||||
DEST_REPO="$CLEANUP_DIR/openai-codex-plugins"
|
||||
gh repo clone "$FORK" "$DEST_REPO" >/dev/null
|
||||
fi
|
||||
|
||||
DEST="$DEST_REPO/$DEST_REL"
|
||||
PREVIEW_REPO="$DEST_REPO"
|
||||
PREVIEW_DEST="$DEST"
|
||||
SYNC_SOURCE=""
|
||||
|
||||
overlay_destination_paths() {
|
||||
local repo="$1"
|
||||
local path
|
||||
local source_path
|
||||
local preview_path
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
source_path="$repo/$path"
|
||||
preview_path="$PREVIEW_REPO/$path"
|
||||
|
||||
if [[ -e "$source_path" ]]; then
|
||||
mkdir -p "$(dirname "$preview_path")"
|
||||
cp -R "$source_path" "$preview_path"
|
||||
else
|
||||
rm -rf "$preview_path"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
copy_local_destination_overlay() {
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" diff --name-only -z -- "$DEST_REL"
|
||||
)
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" diff --cached --name-only -z -- "$DEST_REL"
|
||||
)
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" ls-files --others --exclude-standard -z -- "$DEST_REL"
|
||||
)
|
||||
overlay_destination_paths "$DEST_REPO" < <(
|
||||
git -C "$DEST_REPO" ls-files --others --ignored --exclude-standard -z -- "$DEST_REL"
|
||||
)
|
||||
}
|
||||
|
||||
local_checkout_has_uncommitted_destination_changes() {
|
||||
[[ -n "$(git -C "$DEST_REPO" status --porcelain=1 --untracked-files=all --ignored=matching -- "$DEST_REL")" ]]
|
||||
}
|
||||
|
||||
prepare_preview_checkout() {
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
[[ -n "$CLEANUP_DIR" ]] || CLEANUP_DIR="$(mktemp -d)"
|
||||
PREVIEW_REPO="$CLEANUP_DIR/preview"
|
||||
git clone -q --no-local "$DEST_REPO" "$PREVIEW_REPO"
|
||||
PREVIEW_DEST="$PREVIEW_REPO/$DEST_REL"
|
||||
fi
|
||||
|
||||
git -C "$PREVIEW_REPO" checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
copy_local_destination_overlay
|
||||
fi
|
||||
if [[ $BOOTSTRAP -ne 1 ]]; then
|
||||
[[ -d "$PREVIEW_DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap, or pass --base <branch>"
|
||||
fi
|
||||
}
|
||||
|
||||
prepare_apply_checkout() {
|
||||
git -C "$DEST_REPO" checkout -q "$BASE" 2>/dev/null || die "base branch '$BASE' doesn't exist in $FORK"
|
||||
if [[ $BOOTSTRAP -ne 1 ]]; then
|
||||
[[ -d "$DEST" ]] || die "base branch '$BASE' has no '$DEST_REL/' — use --bootstrap, or pass --base <branch>"
|
||||
fi
|
||||
}
|
||||
|
||||
apply_to_preview_checkout() {
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
mkdir -p "$PREVIEW_DEST"
|
||||
fi
|
||||
|
||||
rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$PREVIEW_DEST/"
|
||||
}
|
||||
|
||||
preview_checkout_has_changes() {
|
||||
[[ -n "$(git -C "$PREVIEW_REPO" status --porcelain "$DEST_REL")" ]]
|
||||
}
|
||||
|
||||
prepare_preview_checkout
|
||||
|
||||
TIMESTAMP="$(date -u +%Y%m%d-%H%M%S)"
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
SYNC_BRANCH="bootstrap/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
|
||||
else
|
||||
SYNC_BRANCH="sync/superpowers-${UPSTREAM_SHORT}-${TIMESTAMP}"
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Build rsync args
|
||||
# =============================================================================
|
||||
|
||||
RSYNC_ARGS=(-av --delete --delete-excluded)
|
||||
for pat in "${EXCLUDES[@]}"; do RSYNC_ARGS+=(--exclude="$pat"); done
|
||||
append_git_ignored_directory_excludes
|
||||
append_git_ignored_file_excludes
|
||||
|
||||
copy_preserved_destination_metadata() {
|
||||
local destination="$1"
|
||||
local source="$2"
|
||||
local path
|
||||
local rel
|
||||
|
||||
[[ -d "$destination/skills" ]] || return 0
|
||||
|
||||
while IFS= read -r -d '' path; do
|
||||
rel="${path#"$destination"/}"
|
||||
mkdir -p "$source/$(dirname "$rel")"
|
||||
cp -p "$path" "$source/$rel"
|
||||
done < <(find "$destination/skills" -path '*/agents/openai.yaml' -type f -print0)
|
||||
}
|
||||
|
||||
prepare_sync_source() {
|
||||
local destination="$1"
|
||||
|
||||
[[ -n "$CLEANUP_DIR" ]] || CLEANUP_DIR="$(mktemp -d)"
|
||||
|
||||
SYNC_SOURCE="$CLEANUP_DIR/source-overlay"
|
||||
rm -rf "$SYNC_SOURCE"
|
||||
mkdir -p "$SYNC_SOURCE"
|
||||
|
||||
rsync "${RSYNC_ARGS[@]}" "$UPSTREAM/" "$SYNC_SOURCE/" >/dev/null
|
||||
copy_preserved_destination_metadata "$destination" "$SYNC_SOURCE"
|
||||
}
|
||||
|
||||
prepare_sync_source "$PREVIEW_DEST"
|
||||
|
||||
# =============================================================================
|
||||
# Dry run preview (always shown)
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
echo "Upstream: $UPSTREAM ($UPSTREAM_BRANCH @ $UPSTREAM_SHORT)"
|
||||
echo "Version: $UPSTREAM_VERSION"
|
||||
echo "Fork: $FORK"
|
||||
echo "Base: $BASE"
|
||||
echo "Branch: $SYNC_BRANCH"
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
echo "Mode: BOOTSTRAP (creating plugins/superpowers/ when absent)"
|
||||
fi
|
||||
echo ""
|
||||
echo "=== Preview (rsync --dry-run) ==="
|
||||
rsync "${RSYNC_ARGS[@]}" --dry-run --itemize-changes "$SYNC_SOURCE/" "$PREVIEW_DEST/"
|
||||
echo "=== End preview ==="
|
||||
echo ""
|
||||
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo ""
|
||||
echo "Dry run only. Nothing was changed or pushed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Apply
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
confirm "Apply changes, push branch, and open PR?" || { echo "Aborted."; exit 1; }
|
||||
|
||||
echo ""
|
||||
if [[ -n "$LOCAL_CHECKOUT" ]]; then
|
||||
if local_checkout_has_uncommitted_destination_changes; then
|
||||
die "local checkout has uncommitted changes under '$DEST_REL' — commit, stash, or discard them before syncing"
|
||||
fi
|
||||
|
||||
apply_to_preview_checkout
|
||||
if ! preview_checkout_has_changes; then
|
||||
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
prepare_apply_checkout
|
||||
cd "$DEST_REPO"
|
||||
git checkout -q -b "$SYNC_BRANCH"
|
||||
echo "Syncing upstream content..."
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
mkdir -p "$DEST"
|
||||
fi
|
||||
rsync "${RSYNC_ARGS[@]}" "$SYNC_SOURCE/" "$DEST/"
|
||||
|
||||
# Bail early if nothing actually changed
|
||||
cd "$DEST_REPO"
|
||||
if [[ -z "$(git status --porcelain "$DEST_REL")" ]]; then
|
||||
echo "No changes — embedded plugin was already in sync with upstream $UPSTREAM_SHORT (v$UPSTREAM_VERSION)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# Commit, push, open PR
|
||||
# =============================================================================
|
||||
|
||||
git add "$DEST_REL"
|
||||
|
||||
if [[ $BOOTSTRAP -eq 1 ]]; then
|
||||
COMMIT_TITLE="bootstrap superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
|
||||
PR_BODY="Initial bootstrap of the superpowers plugin from upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
|
||||
|
||||
Creates \`plugins/superpowers/\` by copying the tracked plugin files from upstream, including \`.codex-plugin/plugin.json\`, \`assets/\`, and \`hooks/\`.
|
||||
|
||||
Run via: \`scripts/sync-to-codex-plugin.sh --bootstrap\`
|
||||
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
|
||||
|
||||
This is a one-time bootstrap. Subsequent syncs will be normal (non-bootstrap) runs using the same tracked upstream plugin files."
|
||||
else
|
||||
COMMIT_TITLE="sync superpowers v$UPSTREAM_VERSION from upstream main @ $UPSTREAM_SHORT"
|
||||
PR_BODY="Automated sync from superpowers upstream \`main\` @ \`$UPSTREAM_SHORT\` (v$UPSTREAM_VERSION).
|
||||
|
||||
Copies the tracked plugin files from upstream, including the committed Codex manifest, assets, and hooks.
|
||||
|
||||
Run via: \`scripts/sync-to-codex-plugin.sh\`
|
||||
Upstream commit: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
|
||||
|
||||
Running the sync tool again against the same upstream SHA should produce a PR with an identical diff — use that to verify the tool is behaving."
|
||||
fi
|
||||
|
||||
git commit --quiet -m "$COMMIT_TITLE
|
||||
|
||||
Automated sync via scripts/sync-to-codex-plugin.sh
|
||||
Upstream: https://github.com/obra/superpowers/commit/$UPSTREAM_SHA
|
||||
Branch: $SYNC_BRANCH"
|
||||
|
||||
echo "Pushing $SYNC_BRANCH to $FORK..."
|
||||
git push -u origin "$SYNC_BRANCH" --quiet
|
||||
|
||||
echo "Opening PR..."
|
||||
PR_URL="$(gh pr create \
|
||||
--repo "$FORK" \
|
||||
--base "$BASE" \
|
||||
--head "$SYNC_BRANCH" \
|
||||
--title "$COMMIT_TITLE" \
|
||||
--body "$PR_BODY")"
|
||||
|
||||
PR_NUM="${PR_URL##*/}"
|
||||
DIFF_URL="https://github.com/$FORK/pull/$PR_NUM/files"
|
||||
|
||||
echo ""
|
||||
echo "PR opened: $PR_URL"
|
||||
echo "Diff view: $DIFF_URL"
|
||||
@@ -7,11 +7,68 @@ description: "You MUST use this before any creative work - creating features, bu
|
||||
|
||||
Help turn ideas into fully formed designs and specs through natural collaborative dialogue.
|
||||
|
||||
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design in small sections (200-300 words), checking after each section whether it looks right so far.
|
||||
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design and get user approval.
|
||||
|
||||
<HARD-GATE>
|
||||
Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity.
|
||||
</HARD-GATE>
|
||||
|
||||
## Anti-Pattern: "This Is Too Simple To Need A Design"
|
||||
|
||||
Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval.
|
||||
|
||||
## Checklist
|
||||
|
||||
You MUST create a task for each of these items and complete them in order:
|
||||
|
||||
1. **Explore project context** — check files, docs, recent commits
|
||||
2. **Offer visual companion** (if topic will involve visual questions) — this is its own message, not combined with a clarifying question. See the Visual Companion section below.
|
||||
3. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria
|
||||
4. **Propose 2-3 approaches** — with trade-offs and your recommendation
|
||||
5. **Present design** — in sections scaled to their complexity, get user approval after each section
|
||||
6. **Write design doc** — save to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md` and commit
|
||||
7. **Spec self-review** — quick inline check for placeholders, contradictions, ambiguity, scope (see below)
|
||||
8. **User reviews written spec** — ask user to review the spec file before proceeding
|
||||
9. **Transition to implementation** — invoke writing-plans skill to create implementation plan
|
||||
|
||||
## Process Flow
|
||||
|
||||
```dot
|
||||
digraph brainstorming {
|
||||
"Explore project context" [shape=box];
|
||||
"Visual questions ahead?" [shape=diamond];
|
||||
"Offer Visual Companion\n(own message, no other content)" [shape=box];
|
||||
"Ask clarifying questions" [shape=box];
|
||||
"Propose 2-3 approaches" [shape=box];
|
||||
"Present design sections" [shape=box];
|
||||
"User approves design?" [shape=diamond];
|
||||
"Write design doc" [shape=box];
|
||||
"Spec self-review\n(fix inline)" [shape=box];
|
||||
"User reviews spec?" [shape=diamond];
|
||||
"Invoke writing-plans skill" [shape=doublecircle];
|
||||
|
||||
"Explore project context" -> "Visual questions ahead?";
|
||||
"Visual questions ahead?" -> "Offer Visual Companion\n(own message, no other content)" [label="yes"];
|
||||
"Visual questions ahead?" -> "Ask clarifying questions" [label="no"];
|
||||
"Offer Visual Companion\n(own message, no other content)" -> "Ask clarifying questions";
|
||||
"Ask clarifying questions" -> "Propose 2-3 approaches";
|
||||
"Propose 2-3 approaches" -> "Present design sections";
|
||||
"Present design sections" -> "User approves design?";
|
||||
"User approves design?" -> "Present design sections" [label="no, revise"];
|
||||
"User approves design?" -> "Write design doc" [label="yes"];
|
||||
"Write design doc" -> "Spec self-review\n(fix inline)";
|
||||
"Spec self-review\n(fix inline)" -> "User reviews spec?";
|
||||
"User reviews spec?" -> "Write design doc" [label="changes requested"];
|
||||
"User reviews spec?" -> "Invoke writing-plans skill" [label="approved"];
|
||||
}
|
||||
```
|
||||
|
||||
**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans.
|
||||
|
||||
## The Process
|
||||
|
||||
**Understanding the idea:**
|
||||
|
||||
- Check out the current project state first (files, docs, recent commits)
|
||||
- Before asking detailed questions, assess scope: if the request describes multiple independent subsystems (e.g., "build a platform with chat, file storage, billing, and analytics"), flag this immediately. Don't spend questions refining details of a project that needs to be decomposed first.
|
||||
- If the project is too large for a single spec, help the user decompose into sub-projects: what are the independent pieces, how do they relate, what order should they be built? Then brainstorm the first sub-project through the normal design flow. Each sub-project gets its own spec → plan → implementation cycle.
|
||||
@@ -21,24 +78,28 @@ Start by understanding the current project context, then ask questions one at a
|
||||
- Focus on understanding: purpose, constraints, success criteria
|
||||
|
||||
**Exploring approaches:**
|
||||
|
||||
- Propose 2-3 different approaches with trade-offs
|
||||
- Present options conversationally with your recommendation and reasoning
|
||||
- Lead with your recommended option and explain why
|
||||
|
||||
**Presenting the design:**
|
||||
|
||||
- Once you believe you understand what you're building, present the design
|
||||
- Break it into sections of 200-300 words
|
||||
- Scale each section to its complexity: a few sentences if straightforward, up to 200-300 words if nuanced
|
||||
- Ask after each section whether it looks right so far
|
||||
- Cover: architecture, components, data flow, error handling, testing
|
||||
- Be ready to go back and clarify if something doesn't make sense
|
||||
|
||||
**Design for isolation and clarity:**
|
||||
|
||||
- Break the system into smaller units that each have one clear purpose, communicate through well-defined interfaces, and can be understood and tested independently
|
||||
- For each unit, you should be able to answer: what does it do, how do you use it, and what does it depend on?
|
||||
- Can someone understand what a unit does without reading its internals? Can you change the internals without breaking consumers? If not, the boundaries need work.
|
||||
- Smaller, well-bounded units are also easier for you to work with - you reason better about code you can hold in context at once, and your edits are more reliable when files are focused. When a file grows large, that's often a signal that it's doing too much.
|
||||
|
||||
**Working in existing codebases:**
|
||||
|
||||
- Explore the current structure before proposing changes. Follow existing patterns.
|
||||
- Where existing code has problems that affect the work (e.g., a file that's grown too large, unclear boundaries, tangled responsibilities), include targeted improvements as part of the design - the way a good developer improves code they're working in.
|
||||
- Don't propose unrelated refactoring. Stay focused on what serves the current goal.
|
||||
@@ -46,23 +107,33 @@ Start by understanding the current project context, then ask questions one at a
|
||||
## After the Design
|
||||
|
||||
**Documentation:**
|
||||
|
||||
- Write the validated design (spec) to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`
|
||||
- (User preferences for spec location override this default)
|
||||
- Use elements-of-style:writing-clearly-and-concisely skill if available
|
||||
- Commit the design document to git
|
||||
|
||||
**Spec Review Loop:**
|
||||
After writing the spec document:
|
||||
1. Dispatch spec-document-reviewer subagent (see spec-document-reviewer-prompt.md)
|
||||
2. If Issues Found: fix, re-dispatch, repeat until Approved
|
||||
3. If loop exceeds 5 iterations, surface to human for guidance
|
||||
**Spec Self-Review:**
|
||||
After writing the spec document, look at it with fresh eyes:
|
||||
|
||||
**Implementation (if continuing):**
|
||||
- Ask: "Ready to set up for implementation?"
|
||||
- Use superpowers:using-git-worktrees to create isolated workspace
|
||||
- **REQUIRED:** Use superpowers:writing-plans to create detailed implementation plan
|
||||
- Do NOT use platform planning features (e.g., EnterPlanMode, plan mode)
|
||||
- Do NOT start implementing directly - the writing-plans skill comes first
|
||||
1. **Placeholder scan:** Any "TBD", "TODO", incomplete sections, or vague requirements? Fix them.
|
||||
2. **Internal consistency:** Do any sections contradict each other? Does the architecture match the feature descriptions?
|
||||
3. **Scope check:** Is this focused enough for a single implementation plan, or does it need decomposition?
|
||||
4. **Ambiguity check:** Could any requirement be interpreted two different ways? If so, pick one and make it explicit.
|
||||
|
||||
Fix any issues inline. No need to re-review — just fix and move on.
|
||||
|
||||
**User Review Gate:**
|
||||
After the spec review loop passes, ask the user to review the written spec before proceeding:
|
||||
|
||||
> "Spec written and committed to `<path>`. Please review it and let me know if you want to make any changes before we start writing out the implementation plan."
|
||||
|
||||
Wait for the user's response. If they request changes, make them and re-run the spec review loop. Only proceed once the user approves.
|
||||
|
||||
**Implementation:**
|
||||
|
||||
- Invoke the writing-plans skill to create a detailed implementation plan
|
||||
- Do NOT invoke any other skill. writing-plans is the next step.
|
||||
|
||||
## Key Principles
|
||||
|
||||
@@ -70,15 +141,24 @@ After writing the spec document:
|
||||
- **Multiple choice preferred** - Easier to answer than open-ended when possible
|
||||
- **YAGNI ruthlessly** - Remove unnecessary features from all designs
|
||||
- **Explore alternatives** - Always propose 2-3 approaches before settling
|
||||
- **Incremental validation** - Present design in sections, validate each
|
||||
- **Incremental validation** - Present design, get approval before moving on
|
||||
- **Be flexible** - Go back and clarify when something doesn't make sense
|
||||
|
||||
## Visual Companion (Claude Code Only)
|
||||
## Visual Companion
|
||||
|
||||
A browser-based visual companion for showing mockups, diagrams, and options during brainstorming. Use it whenever visual representation would make feedback easier than text descriptions alone.
|
||||
A browser-based companion for showing mockups, diagrams, and visual options during brainstorming. Available as a tool — not a mode. Accepting the companion means it's available for questions that benefit from visual treatment; it does NOT mean every question goes through the browser.
|
||||
|
||||
**When the topic involves visual decisions, ask:**
|
||||
> "This involves some visual decisions. I can show mockups in a browser window so you can see options and give feedback visually. This feature is still new — it can be token-intensive and a bit slow, but it works well for layout, design, and architecture questions. Want to try it? (Requires opening a local URL)"
|
||||
**Offering the companion:** When you anticipate that upcoming questions will involve visual content (mockups, layouts, diagrams), offer it once for consent:
|
||||
> "Some of what we're working on might be easier to explain if I can show it to you in a web browser. I can put together mockups, diagrams, comparisons, and other visuals as we go. This feature is still new and can be token-intensive. Want to try it? (Requires opening a local URL)"
|
||||
|
||||
If they agree, read the detailed guide before proceeding:
|
||||
`${CLAUDE_PLUGIN_ROOT}/skills/brainstorming/visual-companion.md`
|
||||
**This offer MUST be its own message.** Do not combine it with clarifying questions, context summaries, or any other content. The message should contain ONLY the offer above and nothing else. Wait for the user's response before continuing. If they decline, proceed with text-only brainstorming.
|
||||
|
||||
**Per-question decision:** Even after the user accepts, decide FOR EACH QUESTION whether to use the browser or the terminal. The test: **would the user understand this better by seeing it than reading it?**
|
||||
|
||||
- **Use the browser** for content that IS visual — mockups, wireframes, layout comparisons, architecture diagrams, side-by-side visual designs
|
||||
- **Use the terminal** for content that is text — requirements questions, conceptual choices, tradeoff lists, A/B/C/D text options, scope decisions
|
||||
|
||||
A question about a UI topic is not automatically a visual question. "What does personality mean in this context?" is a conceptual question — use the terminal. "Which wizard layout works better?" is a visual question — use the browser.
|
||||
|
||||
If they agree to the companion, read the detailed guide before proceeding:
|
||||
`skills/brainstorming/visual-companion.md`
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Brainstorm Companion</title>
|
||||
<meta charset="utf-8">
|
||||
<title>Superpowers Brainstorming</title>
|
||||
<style>
|
||||
/*
|
||||
* BRAINSTORM COMPANION FRAME TEMPLATE
|
||||
*
|
||||
* This template provides a consistent frame with:
|
||||
* - OS-aware light/dark theming
|
||||
* - Fixed header and feedback footer
|
||||
* - Fixed header and selection indicator bar
|
||||
* - Scrollable main content area
|
||||
* - CSS helpers for common UI patterns
|
||||
*
|
||||
* CLAUDE: Replace the contents of #claude-content with your content.
|
||||
* Keep the header, main wrapper, and feedback-footer intact.
|
||||
* Content is injected via placeholder comment in #frame-content.
|
||||
*/
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
@@ -77,39 +77,23 @@
|
||||
.header .status::before { content: ''; width: 6px; height: 6px; background: var(--success); border-radius: 50%; }
|
||||
|
||||
.main { flex: 1; overflow-y: auto; }
|
||||
#claude-content { padding: 2rem; min-height: 100%; }
|
||||
#frame-content { padding: 2rem; min-height: 100%; }
|
||||
|
||||
.feedback-footer {
|
||||
.indicator-bar {
|
||||
background: var(--bg-secondary);
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 0.75rem 1.5rem;
|
||||
padding: 0.5rem 1.5rem;
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.feedback-footer label { display: block; font-size: 0.65rem; color: var(--text-secondary); margin-bottom: 0.4rem; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
.feedback-row { display: flex; gap: 0.5rem; }
|
||||
.feedback-footer textarea {
|
||||
flex: 1;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
color: var(--text-primary);
|
||||
font-family: inherit;
|
||||
font-size: 0.85rem;
|
||||
resize: none;
|
||||
height: 36px;
|
||||
.indicator-bar span {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
.feedback-footer textarea:focus { outline: none; border-color: var(--accent); }
|
||||
.feedback-footer button {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0 1rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
.indicator-bar .selected-text {
|
||||
color: var(--accent);
|
||||
font-weight: 500;
|
||||
}
|
||||
.feedback-footer button:hover { background: var(--accent-hover); }
|
||||
|
||||
/* ===== TYPOGRAPHY ===== */
|
||||
h2 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.5rem; }
|
||||
@@ -212,24 +196,18 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>Brainstorm Companion</h1>
|
||||
<h1><a href="https://github.com/obra/superpowers" style="color: inherit; text-decoration: none;">Superpowers Brainstorming</a></h1>
|
||||
<div class="status">Connected</div>
|
||||
</div>
|
||||
|
||||
<div class="main">
|
||||
<div id="claude-content">
|
||||
<!-- CLAUDE: Replace this content -->
|
||||
<h2>Visual Brainstorming</h2>
|
||||
<p class="subtitle">Claude will show mockups and options here.</p>
|
||||
<div id="frame-content">
|
||||
<!-- CONTENT -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="feedback-footer">
|
||||
<label>Feedback for Claude</label>
|
||||
<div class="feedback-row">
|
||||
<textarea id="feedback" placeholder="Add notes (optional)..." onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();send()}"></textarea>
|
||||
<button onclick="send()">Send</button>
|
||||
</div>
|
||||
<div class="indicator-bar">
|
||||
<span id="indicator-text">Click an option above, then return to the terminal</span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
88
skills/brainstorming/scripts/helper.js
Normal file
88
skills/brainstorming/scripts/helper.js
Normal file
@@ -0,0 +1,88 @@
|
||||
(function() {
|
||||
const WS_URL = 'ws://' + window.location.host;
|
||||
let ws = null;
|
||||
let eventQueue = [];
|
||||
|
||||
function connect() {
|
||||
ws = new WebSocket(WS_URL);
|
||||
|
||||
ws.onopen = () => {
|
||||
eventQueue.forEach(e => ws.send(JSON.stringify(e)));
|
||||
eventQueue = [];
|
||||
};
|
||||
|
||||
ws.onmessage = (msg) => {
|
||||
const data = JSON.parse(msg.data);
|
||||
if (data.type === 'reload') {
|
||||
window.location.reload();
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
}
|
||||
|
||||
function sendEvent(event) {
|
||||
event.timestamp = Date.now();
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify(event));
|
||||
} else {
|
||||
eventQueue.push(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Capture clicks on choice elements
|
||||
document.addEventListener('click', (e) => {
|
||||
const target = e.target.closest('[data-choice]');
|
||||
if (!target) return;
|
||||
|
||||
sendEvent({
|
||||
type: 'click',
|
||||
text: target.textContent.trim(),
|
||||
choice: target.dataset.choice,
|
||||
id: target.id || null
|
||||
});
|
||||
|
||||
// Update indicator bar (defer so toggleSelect runs first)
|
||||
setTimeout(() => {
|
||||
const indicator = document.getElementById('indicator-text');
|
||||
if (!indicator) return;
|
||||
const container = target.closest('.options') || target.closest('.cards');
|
||||
const selected = container ? container.querySelectorAll('.selected') : [];
|
||||
if (selected.length === 0) {
|
||||
indicator.textContent = 'Click an option above, then return to the terminal';
|
||||
} else if (selected.length === 1) {
|
||||
const label = selected[0].querySelector('h3, .content h3, .card-body h3')?.textContent?.trim() || selected[0].dataset.choice;
|
||||
indicator.innerHTML = '<span class="selected-text">' + label + ' selected</span> — return to terminal to continue';
|
||||
} else {
|
||||
indicator.innerHTML = '<span class="selected-text">' + selected.length + ' selected</span> — return to terminal to continue';
|
||||
}
|
||||
}, 0);
|
||||
});
|
||||
|
||||
// Frame UI: selection tracking
|
||||
window.selectedChoice = null;
|
||||
|
||||
window.toggleSelect = function(el) {
|
||||
const container = el.closest('.options') || el.closest('.cards');
|
||||
const multi = container && container.dataset.multiselect !== undefined;
|
||||
if (container && !multi) {
|
||||
container.querySelectorAll('.option, .card').forEach(o => o.classList.remove('selected'));
|
||||
}
|
||||
if (multi) {
|
||||
el.classList.toggle('selected');
|
||||
} else {
|
||||
el.classList.add('selected');
|
||||
}
|
||||
window.selectedChoice = el.dataset.choice;
|
||||
};
|
||||
|
||||
// Expose API for explicit use
|
||||
window.brainstorm = {
|
||||
send: sendEvent,
|
||||
choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata })
|
||||
};
|
||||
|
||||
connect();
|
||||
})();
|
||||
354
skills/brainstorming/scripts/server.cjs
Normal file
354
skills/brainstorming/scripts/server.cjs
Normal file
@@ -0,0 +1,354 @@
|
||||
const crypto = require('crypto');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// ========== WebSocket Protocol (RFC 6455) ==========
|
||||
|
||||
const OPCODES = { TEXT: 0x01, CLOSE: 0x08, PING: 0x09, PONG: 0x0A };
|
||||
const WS_MAGIC = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
|
||||
|
||||
function computeAcceptKey(clientKey) {
|
||||
return crypto.createHash('sha1').update(clientKey + WS_MAGIC).digest('base64');
|
||||
}
|
||||
|
||||
function encodeFrame(opcode, payload) {
|
||||
const fin = 0x80;
|
||||
const len = payload.length;
|
||||
let header;
|
||||
|
||||
if (len < 126) {
|
||||
header = Buffer.alloc(2);
|
||||
header[0] = fin | opcode;
|
||||
header[1] = len;
|
||||
} else if (len < 65536) {
|
||||
header = Buffer.alloc(4);
|
||||
header[0] = fin | opcode;
|
||||
header[1] = 126;
|
||||
header.writeUInt16BE(len, 2);
|
||||
} else {
|
||||
header = Buffer.alloc(10);
|
||||
header[0] = fin | opcode;
|
||||
header[1] = 127;
|
||||
header.writeBigUInt64BE(BigInt(len), 2);
|
||||
}
|
||||
|
||||
return Buffer.concat([header, payload]);
|
||||
}
|
||||
|
||||
function decodeFrame(buffer) {
|
||||
if (buffer.length < 2) return null;
|
||||
|
||||
const secondByte = buffer[1];
|
||||
const opcode = buffer[0] & 0x0F;
|
||||
const masked = (secondByte & 0x80) !== 0;
|
||||
let payloadLen = secondByte & 0x7F;
|
||||
let offset = 2;
|
||||
|
||||
if (!masked) throw new Error('Client frames must be masked');
|
||||
|
||||
if (payloadLen === 126) {
|
||||
if (buffer.length < 4) return null;
|
||||
payloadLen = buffer.readUInt16BE(2);
|
||||
offset = 4;
|
||||
} else if (payloadLen === 127) {
|
||||
if (buffer.length < 10) return null;
|
||||
payloadLen = Number(buffer.readBigUInt64BE(2));
|
||||
offset = 10;
|
||||
}
|
||||
|
||||
const maskOffset = offset;
|
||||
const dataOffset = offset + 4;
|
||||
const totalLen = dataOffset + payloadLen;
|
||||
if (buffer.length < totalLen) return null;
|
||||
|
||||
const mask = buffer.slice(maskOffset, dataOffset);
|
||||
const data = Buffer.alloc(payloadLen);
|
||||
for (let i = 0; i < payloadLen; i++) {
|
||||
data[i] = buffer[dataOffset + i] ^ mask[i % 4];
|
||||
}
|
||||
|
||||
return { opcode, payload: data, bytesConsumed: totalLen };
|
||||
}
|
||||
|
||||
// ========== Configuration ==========
|
||||
|
||||
const PORT = process.env.BRAINSTORM_PORT || (49152 + Math.floor(Math.random() * 16383));
|
||||
const HOST = process.env.BRAINSTORM_HOST || '127.0.0.1';
|
||||
const URL_HOST = process.env.BRAINSTORM_URL_HOST || (HOST === '127.0.0.1' ? 'localhost' : HOST);
|
||||
const SESSION_DIR = process.env.BRAINSTORM_DIR || '/tmp/brainstorm';
|
||||
const CONTENT_DIR = path.join(SESSION_DIR, 'content');
|
||||
const STATE_DIR = path.join(SESSION_DIR, 'state');
|
||||
let ownerPid = process.env.BRAINSTORM_OWNER_PID ? Number(process.env.BRAINSTORM_OWNER_PID) : null;
|
||||
|
||||
const MIME_TYPES = {
|
||||
'.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript',
|
||||
'.json': 'application/json', '.png': 'image/png', '.jpg': 'image/jpeg',
|
||||
'.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml'
|
||||
};
|
||||
|
||||
// ========== Templates and Constants ==========
|
||||
|
||||
const WAITING_PAGE = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head><meta charset="utf-8"><title>Brainstorm Companion</title>
|
||||
<style>body { font-family: system-ui, sans-serif; padding: 2rem; max-width: 800px; margin: 0 auto; }
|
||||
h1 { color: #333; } p { color: #666; }</style>
|
||||
</head>
|
||||
<body><h1>Brainstorm Companion</h1>
|
||||
<p>Waiting for the agent to push a screen...</p></body></html>`;
|
||||
|
||||
const frameTemplate = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf-8');
|
||||
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
|
||||
const helperInjection = '<script>\n' + helperScript + '\n</script>';
|
||||
|
||||
// ========== Helper Functions ==========
|
||||
|
||||
function isFullDocument(html) {
|
||||
const trimmed = html.trimStart().toLowerCase();
|
||||
return trimmed.startsWith('<!doctype') || trimmed.startsWith('<html');
|
||||
}
|
||||
|
||||
function wrapInFrame(content) {
|
||||
return frameTemplate.replace('<!-- CONTENT -->', content);
|
||||
}
|
||||
|
||||
function getNewestScreen() {
|
||||
const files = fs.readdirSync(CONTENT_DIR)
|
||||
.filter(f => f.endsWith('.html'))
|
||||
.map(f => {
|
||||
const fp = path.join(CONTENT_DIR, f);
|
||||
return { path: fp, mtime: fs.statSync(fp).mtime.getTime() };
|
||||
})
|
||||
.sort((a, b) => b.mtime - a.mtime);
|
||||
return files.length > 0 ? files[0].path : null;
|
||||
}
|
||||
|
||||
// ========== HTTP Request Handler ==========
|
||||
|
||||
function handleRequest(req, res) {
|
||||
touchActivity();
|
||||
if (req.method === 'GET' && req.url === '/') {
|
||||
const screenFile = getNewestScreen();
|
||||
let html = screenFile
|
||||
? (raw => isFullDocument(raw) ? raw : wrapInFrame(raw))(fs.readFileSync(screenFile, 'utf-8'))
|
||||
: WAITING_PAGE;
|
||||
|
||||
if (html.includes('</body>')) {
|
||||
html = html.replace('</body>', helperInjection + '\n</body>');
|
||||
} else {
|
||||
html += helperInjection;
|
||||
}
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
||||
res.end(html);
|
||||
} else if (req.method === 'GET' && req.url.startsWith('/files/')) {
|
||||
const fileName = req.url.slice(7);
|
||||
const filePath = path.join(CONTENT_DIR, path.basename(fileName));
|
||||
if (!fs.existsSync(filePath)) {
|
||||
res.writeHead(404);
|
||||
res.end('Not found');
|
||||
return;
|
||||
}
|
||||
const ext = path.extname(filePath).toLowerCase();
|
||||
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
|
||||
res.writeHead(200, { 'Content-Type': contentType });
|
||||
res.end(fs.readFileSync(filePath));
|
||||
} else {
|
||||
res.writeHead(404);
|
||||
res.end('Not found');
|
||||
}
|
||||
}
|
||||
|
||||
// ========== WebSocket Connection Handling ==========
|
||||
|
||||
const clients = new Set();
|
||||
|
||||
function handleUpgrade(req, socket) {
|
||||
const key = req.headers['sec-websocket-key'];
|
||||
if (!key) { socket.destroy(); return; }
|
||||
|
||||
const accept = computeAcceptKey(key);
|
||||
socket.write(
|
||||
'HTTP/1.1 101 Switching Protocols\r\n' +
|
||||
'Upgrade: websocket\r\n' +
|
||||
'Connection: Upgrade\r\n' +
|
||||
'Sec-WebSocket-Accept: ' + accept + '\r\n\r\n'
|
||||
);
|
||||
|
||||
let buffer = Buffer.alloc(0);
|
||||
clients.add(socket);
|
||||
|
||||
socket.on('data', (chunk) => {
|
||||
buffer = Buffer.concat([buffer, chunk]);
|
||||
while (buffer.length > 0) {
|
||||
let result;
|
||||
try {
|
||||
result = decodeFrame(buffer);
|
||||
} catch (e) {
|
||||
socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0)));
|
||||
clients.delete(socket);
|
||||
return;
|
||||
}
|
||||
if (!result) break;
|
||||
buffer = buffer.slice(result.bytesConsumed);
|
||||
|
||||
switch (result.opcode) {
|
||||
case OPCODES.TEXT:
|
||||
handleMessage(result.payload.toString());
|
||||
break;
|
||||
case OPCODES.CLOSE:
|
||||
socket.end(encodeFrame(OPCODES.CLOSE, Buffer.alloc(0)));
|
||||
clients.delete(socket);
|
||||
return;
|
||||
case OPCODES.PING:
|
||||
socket.write(encodeFrame(OPCODES.PONG, result.payload));
|
||||
break;
|
||||
case OPCODES.PONG:
|
||||
break;
|
||||
default: {
|
||||
const closeBuf = Buffer.alloc(2);
|
||||
closeBuf.writeUInt16BE(1003);
|
||||
socket.end(encodeFrame(OPCODES.CLOSE, closeBuf));
|
||||
clients.delete(socket);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('close', () => clients.delete(socket));
|
||||
socket.on('error', () => clients.delete(socket));
|
||||
}
|
||||
|
||||
function handleMessage(text) {
|
||||
let event;
|
||||
try {
|
||||
event = JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error('Failed to parse WebSocket message:', e.message);
|
||||
return;
|
||||
}
|
||||
touchActivity();
|
||||
console.log(JSON.stringify({ source: 'user-event', ...event }));
|
||||
if (event.choice) {
|
||||
const eventsFile = path.join(STATE_DIR, 'events');
|
||||
fs.appendFileSync(eventsFile, JSON.stringify(event) + '\n');
|
||||
}
|
||||
}
|
||||
|
||||
function broadcast(msg) {
|
||||
const frame = encodeFrame(OPCODES.TEXT, Buffer.from(JSON.stringify(msg)));
|
||||
for (const socket of clients) {
|
||||
try { socket.write(frame); } catch (e) { clients.delete(socket); }
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Activity Tracking ==========
|
||||
|
||||
const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
|
||||
let lastActivity = Date.now();
|
||||
|
||||
function touchActivity() {
|
||||
lastActivity = Date.now();
|
||||
}
|
||||
|
||||
// ========== File Watching ==========
|
||||
|
||||
const debounceTimers = new Map();
|
||||
|
||||
// ========== Server Startup ==========
|
||||
|
||||
function startServer() {
|
||||
if (!fs.existsSync(CONTENT_DIR)) fs.mkdirSync(CONTENT_DIR, { recursive: true });
|
||||
if (!fs.existsSync(STATE_DIR)) fs.mkdirSync(STATE_DIR, { recursive: true });
|
||||
|
||||
// Track known files to distinguish new screens from updates.
|
||||
// macOS fs.watch reports 'rename' for both new files and overwrites,
|
||||
// so we can't rely on eventType alone.
|
||||
const knownFiles = new Set(
|
||||
fs.readdirSync(CONTENT_DIR).filter(f => f.endsWith('.html'))
|
||||
);
|
||||
|
||||
const server = http.createServer(handleRequest);
|
||||
server.on('upgrade', handleUpgrade);
|
||||
|
||||
const watcher = fs.watch(CONTENT_DIR, (eventType, filename) => {
|
||||
if (!filename || !filename.endsWith('.html')) return;
|
||||
|
||||
if (debounceTimers.has(filename)) clearTimeout(debounceTimers.get(filename));
|
||||
debounceTimers.set(filename, setTimeout(() => {
|
||||
debounceTimers.delete(filename);
|
||||
const filePath = path.join(CONTENT_DIR, filename);
|
||||
|
||||
if (!fs.existsSync(filePath)) return; // file was deleted
|
||||
touchActivity();
|
||||
|
||||
if (!knownFiles.has(filename)) {
|
||||
knownFiles.add(filename);
|
||||
const eventsFile = path.join(STATE_DIR, 'events');
|
||||
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
||||
console.log(JSON.stringify({ type: 'screen-added', file: filePath }));
|
||||
} else {
|
||||
console.log(JSON.stringify({ type: 'screen-updated', file: filePath }));
|
||||
}
|
||||
|
||||
broadcast({ type: 'reload' });
|
||||
}, 100));
|
||||
});
|
||||
watcher.on('error', (err) => console.error('fs.watch error:', err.message));
|
||||
|
||||
function shutdown(reason) {
|
||||
console.log(JSON.stringify({ type: 'server-stopped', reason }));
|
||||
const infoFile = path.join(STATE_DIR, 'server-info');
|
||||
if (fs.existsSync(infoFile)) fs.unlinkSync(infoFile);
|
||||
fs.writeFileSync(
|
||||
path.join(STATE_DIR, 'server-stopped'),
|
||||
JSON.stringify({ reason, timestamp: Date.now() }) + '\n'
|
||||
);
|
||||
watcher.close();
|
||||
clearInterval(lifecycleCheck);
|
||||
server.close(() => process.exit(0));
|
||||
}
|
||||
|
||||
function ownerAlive() {
|
||||
if (!ownerPid) return true;
|
||||
try { process.kill(ownerPid, 0); return true; } catch (e) { return e.code === 'EPERM'; }
|
||||
}
|
||||
|
||||
// Check every 60s: exit if owner process died or idle for 30 minutes
|
||||
const lifecycleCheck = setInterval(() => {
|
||||
if (!ownerAlive()) shutdown('owner process exited');
|
||||
else if (Date.now() - lastActivity > IDLE_TIMEOUT_MS) shutdown('idle timeout');
|
||||
}, 60 * 1000);
|
||||
lifecycleCheck.unref();
|
||||
|
||||
// Validate owner PID at startup. If it's already dead, the PID resolution
|
||||
// was wrong (common on WSL, Tailscale SSH, and cross-user scenarios).
|
||||
// Disable monitoring and rely on the idle timeout instead.
|
||||
if (ownerPid) {
|
||||
try { process.kill(ownerPid, 0); }
|
||||
catch (e) {
|
||||
if (e.code !== 'EPERM') {
|
||||
console.log(JSON.stringify({ type: 'owner-pid-invalid', pid: ownerPid, reason: 'dead at startup' }));
|
||||
ownerPid = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
const info = JSON.stringify({
|
||||
type: 'server-started', port: Number(PORT), host: HOST,
|
||||
url_host: URL_HOST, url: 'http://' + URL_HOST + ':' + PORT,
|
||||
screen_dir: CONTENT_DIR, state_dir: STATE_DIR
|
||||
});
|
||||
console.log(info);
|
||||
fs.writeFileSync(path.join(STATE_DIR, 'server-info'), info + '\n');
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
startServer();
|
||||
}
|
||||
|
||||
module.exports = { computeAcceptKey, encodeFrame, decodeFrame, OPCODES };
|
||||
148
skills/brainstorming/scripts/start-server.sh
Executable file
148
skills/brainstorming/scripts/start-server.sh
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env bash
|
||||
# Start the brainstorm server and output connection info
|
||||
# Usage: start-server.sh [--project-dir <path>] [--host <bind-host>] [--url-host <display-host>] [--foreground] [--background]
|
||||
#
|
||||
# Starts server on a random high port, outputs JSON with URL.
|
||||
# Each session gets its own directory to avoid conflicts.
|
||||
#
|
||||
# Options:
|
||||
# --project-dir <path> Store session files under <path>/.superpowers/brainstorm/
|
||||
# instead of /tmp. Files persist after server stops.
|
||||
# --host <bind-host> Host/interface to bind (default: 127.0.0.1).
|
||||
# Use 0.0.0.0 in remote/containerized environments.
|
||||
# --url-host <host> Hostname shown in returned URL JSON.
|
||||
# --foreground Run server in the current terminal (no backgrounding).
|
||||
# --background Force background mode (overrides Codex auto-foreground).
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
# Parse arguments
|
||||
PROJECT_DIR=""
|
||||
FOREGROUND="false"
|
||||
FORCE_BACKGROUND="false"
|
||||
BIND_HOST="127.0.0.1"
|
||||
URL_HOST=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--project-dir)
|
||||
PROJECT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
--host)
|
||||
BIND_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
--url-host)
|
||||
URL_HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
--foreground|--no-daemon)
|
||||
FOREGROUND="true"
|
||||
shift
|
||||
;;
|
||||
--background|--daemon)
|
||||
FORCE_BACKGROUND="true"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo "{\"error\": \"Unknown argument: $1\"}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "$URL_HOST" ]]; then
|
||||
if [[ "$BIND_HOST" == "127.0.0.1" || "$BIND_HOST" == "localhost" ]]; then
|
||||
URL_HOST="localhost"
|
||||
else
|
||||
URL_HOST="$BIND_HOST"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Some environments reap detached/background processes. Auto-foreground when detected.
|
||||
if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then
|
||||
FOREGROUND="true"
|
||||
fi
|
||||
|
||||
# Windows/Git Bash reaps nohup background processes. Auto-foreground when detected.
|
||||
if [[ "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then
|
||||
case "${OSTYPE:-}" in
|
||||
msys*|cygwin*|mingw*) FOREGROUND="true" ;;
|
||||
esac
|
||||
if [[ -n "${MSYSTEM:-}" ]]; then
|
||||
FOREGROUND="true"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Generate unique session directory
|
||||
SESSION_ID="$$-$(date +%s)"
|
||||
|
||||
if [[ -n "$PROJECT_DIR" ]]; then
|
||||
SESSION_DIR="${PROJECT_DIR}/.superpowers/brainstorm/${SESSION_ID}"
|
||||
else
|
||||
SESSION_DIR="/tmp/brainstorm-${SESSION_ID}"
|
||||
fi
|
||||
|
||||
STATE_DIR="${SESSION_DIR}/state"
|
||||
PID_FILE="${STATE_DIR}/server.pid"
|
||||
LOG_FILE="${STATE_DIR}/server.log"
|
||||
|
||||
# Create fresh session directory with content and state peers
|
||||
mkdir -p "${SESSION_DIR}/content" "$STATE_DIR"
|
||||
|
||||
# Kill any existing server
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
old_pid=$(cat "$PID_FILE")
|
||||
kill "$old_pid" 2>/dev/null
|
||||
rm -f "$PID_FILE"
|
||||
fi
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# Resolve the harness PID (grandparent of this script).
|
||||
# $PPID is the ephemeral shell the harness spawned to run us — it dies
|
||||
# when this script exits. The harness itself is $PPID's parent.
|
||||
OWNER_PID="$(ps -o ppid= -p "$PPID" 2>/dev/null | tr -d ' ')"
|
||||
if [[ -z "$OWNER_PID" || "$OWNER_PID" == "1" ]]; then
|
||||
OWNER_PID="$PPID"
|
||||
fi
|
||||
|
||||
# Foreground mode for environments that reap detached/background processes.
|
||||
if [[ "$FOREGROUND" == "true" ]]; then
|
||||
echo "$$" > "$PID_FILE"
|
||||
env BRAINSTORM_DIR="$SESSION_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Start server, capturing output to log file
|
||||
# Use nohup to survive shell exit; disown to remove from job table
|
||||
nohup env BRAINSTORM_DIR="$SESSION_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" BRAINSTORM_OWNER_PID="$OWNER_PID" node server.cjs > "$LOG_FILE" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
disown "$SERVER_PID" 2>/dev/null
|
||||
echo "$SERVER_PID" > "$PID_FILE"
|
||||
|
||||
# Wait for server-started message (check log file)
|
||||
for i in {1..50}; do
|
||||
if grep -q "server-started" "$LOG_FILE" 2>/dev/null; then
|
||||
# Verify server is still alive after a short window (catches process reapers)
|
||||
alive="true"
|
||||
for _ in {1..20}; do
|
||||
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||
alive="false"
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
if [[ "$alive" != "true" ]]; then
|
||||
echo "{\"error\": \"Server started but was killed. Retry in a persistent terminal with: $SCRIPT_DIR/start-server.sh${PROJECT_DIR:+ --project-dir $PROJECT_DIR} --host $BIND_HOST --url-host $URL_HOST --foreground\"}"
|
||||
exit 1
|
||||
fi
|
||||
grep "server-started" "$LOG_FILE" | head -1
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
# Timeout - server didn't start
|
||||
echo '{"error": "Server failed to start within 5 seconds"}'
|
||||
exit 1
|
||||
56
skills/brainstorming/scripts/stop-server.sh
Executable file
56
skills/brainstorming/scripts/stop-server.sh
Executable file
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env bash
|
||||
# Stop the brainstorm server and clean up
|
||||
# Usage: stop-server.sh <session_dir>
|
||||
#
|
||||
# Kills the server process. Only deletes session directory if it's
|
||||
# under /tmp (ephemeral). Persistent directories (.superpowers/) are
|
||||
# kept so mockups can be reviewed later.
|
||||
|
||||
SESSION_DIR="$1"
|
||||
|
||||
if [[ -z "$SESSION_DIR" ]]; then
|
||||
echo '{"error": "Usage: stop-server.sh <session_dir>"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
STATE_DIR="${SESSION_DIR}/state"
|
||||
PID_FILE="${STATE_DIR}/server.pid"
|
||||
|
||||
if [[ -f "$PID_FILE" ]]; then
|
||||
pid=$(cat "$PID_FILE")
|
||||
|
||||
# Try to stop gracefully, fallback to force if still alive
|
||||
kill "$pid" 2>/dev/null || true
|
||||
|
||||
# Wait for graceful shutdown (up to ~2s)
|
||||
for i in {1..20}; do
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
break
|
||||
fi
|
||||
sleep 0.1
|
||||
done
|
||||
|
||||
# If still running, escalate to SIGKILL
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
|
||||
# Give SIGKILL a moment to take effect
|
||||
sleep 0.1
|
||||
fi
|
||||
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
echo '{"status": "failed", "error": "process still running"}'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "$PID_FILE" "${STATE_DIR}/server.log"
|
||||
|
||||
# Only delete ephemeral /tmp directories
|
||||
if [[ "$SESSION_DIR" == /tmp/* ]]; then
|
||||
rm -rf "$SESSION_DIR"
|
||||
fi
|
||||
|
||||
echo '{"status": "stopped"}'
|
||||
else
|
||||
echo '{"status": "not_running"}'
|
||||
fi
|
||||
@@ -7,7 +7,7 @@ Use this template when dispatching a spec document reviewer subagent.
|
||||
**Dispatch after:** Spec document is written to docs/superpowers/specs/
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Review spec document"
|
||||
prompt: |
|
||||
You are a spec document reviewer. Verify this spec is complete and ready for planning.
|
||||
@@ -19,32 +19,31 @@ Task tool (general-purpose):
|
||||
| Category | What to Look For |
|
||||
|----------|------------------|
|
||||
| Completeness | TODOs, placeholders, "TBD", incomplete sections |
|
||||
| Coverage | Missing error handling, edge cases, integration points |
|
||||
| Consistency | Internal contradictions, conflicting requirements |
|
||||
| Clarity | Ambiguous requirements |
|
||||
| YAGNI | Unrequested features, over-engineering |
|
||||
| Clarity | Requirements ambiguous enough to cause someone to build the wrong thing |
|
||||
| Scope | Focused enough for a single plan — not covering multiple independent subsystems |
|
||||
| Architecture | Units with clear boundaries, well-defined interfaces, independently understandable and testable |
|
||||
| YAGNI | Unrequested features, over-engineering |
|
||||
|
||||
## CRITICAL
|
||||
## Calibration
|
||||
|
||||
Look especially hard for:
|
||||
- Any TODO markers or placeholder text
|
||||
- Sections saying "to be defined later" or "will spec when X is done"
|
||||
- Sections noticeably less detailed than others
|
||||
- Units that lack clear boundaries or interfaces — can you understand what each unit does without reading its internals?
|
||||
**Only flag issues that would cause real problems during implementation planning.**
|
||||
A missing section, a contradiction, or a requirement so ambiguous it could be
|
||||
interpreted two different ways — those are issues. Minor wording improvements,
|
||||
stylistic preferences, and "sections less detailed than others" are not.
|
||||
|
||||
Approve unless there are serious gaps that would lead to a flawed plan.
|
||||
|
||||
## Output Format
|
||||
|
||||
## Spec Review
|
||||
|
||||
**Status:** ✅ Approved | ❌ Issues Found
|
||||
**Status:** Approved | Issues Found
|
||||
|
||||
**Issues (if any):**
|
||||
- [Section X]: [specific issue] - [why it matters]
|
||||
- [Section X]: [specific issue] - [why it matters for planning]
|
||||
|
||||
**Recommendations (advisory):**
|
||||
- [suggestions that don't block approval]
|
||||
**Recommendations (advisory, do not block approval):**
|
||||
- [suggestions for improvement]
|
||||
```
|
||||
|
||||
**Reviewer returns:** Status, Issues (if any), Recommendations
|
||||
|
||||
@@ -4,67 +4,134 @@ Browser-based visual brainstorming companion for showing mockups, diagrams, and
|
||||
|
||||
## When to Use
|
||||
|
||||
Use the visual companion when seeing beats describing:
|
||||
- **UI mockups** — layouts, navigation, component designs
|
||||
- **Architecture diagrams** — system components, data flow, relationships
|
||||
- **Complex choices** — multi-option decisions with visual trade-offs
|
||||
- **Design polish** — when the question is about look and feel
|
||||
- **Spatial relationships** — file structures, database schemas, state machines
|
||||
Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?**
|
||||
|
||||
Don't use it for simple text questions, code review, or when the user prefers terminal-only interaction.
|
||||
**Use the browser** when the content itself is visual:
|
||||
|
||||
- **UI mockups** — wireframes, layouts, navigation structures, component designs
|
||||
- **Architecture diagrams** — system components, data flow, relationship maps
|
||||
- **Side-by-side visual comparisons** — comparing two layouts, two color schemes, two design directions
|
||||
- **Design polish** — when the question is about look and feel, spacing, visual hierarchy
|
||||
- **Spatial relationships** — state machines, flowcharts, entity relationships rendered as diagrams
|
||||
|
||||
**Use the terminal** when the content is text or tabular:
|
||||
|
||||
- **Requirements and scope questions** — "what does X mean?", "which features are in scope?"
|
||||
- **Conceptual A/B/C choices** — picking between approaches described in words
|
||||
- **Tradeoff lists** — pros/cons, comparison tables
|
||||
- **Technical decisions** — API design, data modeling, architectural approach selection
|
||||
- **Clarifying questions** — anything where the answer is words, not a visual preference
|
||||
|
||||
A question *about* a UI topic is not automatically a visual question. "What kind of wizard do you want?" is conceptual — use the terminal. "Which of these wizard layouts feels right?" is visual — use the browser.
|
||||
|
||||
## How It Works
|
||||
|
||||
The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content, the user sees it in their browser, clicks options or types feedback, and you receive their response as JSON.
|
||||
The server watches a directory for HTML files and serves the newest one to the browser. You write HTML content to `screen_dir`, the user sees it in their browser and can click to select options. Selections are recorded to `state_dir/events` that you read on your next turn.
|
||||
|
||||
**Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, feedback footer, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page.
|
||||
**Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, selection indicator, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page.
|
||||
|
||||
## Starting a Session
|
||||
|
||||
```bash
|
||||
# Start server with persistence (mockups saved to project)
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh --project-dir /path/to/project
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
|
||||
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
|
||||
# "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000"}
|
||||
# "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/content",
|
||||
# "state_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000/state"}
|
||||
```
|
||||
|
||||
Save `screen_dir` from the response. Tell user to open the URL.
|
||||
Save `screen_dir` and `state_dir` from the response. Tell user to open the URL.
|
||||
|
||||
**Finding connection info:** The server writes its startup JSON to `$STATE_DIR/server-info`. If you launched the server in the background and didn't capture stdout, read that file to get the URL and port. When using `--project-dir`, check `<project>/.superpowers/brainstorm/` for the session directory.
|
||||
|
||||
**Note:** Pass the project root as `--project-dir` so mockups persist in `.superpowers/brainstorm/` and survive server restarts. Without it, files go to `/tmp` and get cleaned up. Remind the user to add `.superpowers/` to `.gitignore` if it's not already there.
|
||||
|
||||
**Launching the server by platform:**
|
||||
|
||||
**Claude Code:**
|
||||
```bash
|
||||
# Default mode works — the script backgrounds the server itself.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
On Windows, the script auto-detects and switches to foreground mode (which blocks the tool call). Use `run_in_background: true` on the Bash tool call so the server survives across conversation turns, then read `$STATE_DIR/server-info` on the next turn to get the URL and port.
|
||||
|
||||
**Codex:**
|
||||
```bash
|
||||
# Codex reaps background processes. The script auto-detects CODEX_CI and
|
||||
# switches to foreground mode. Run it normally — no extra flags needed.
|
||||
scripts/start-server.sh --project-dir /path/to/project
|
||||
```
|
||||
|
||||
**Gemini CLI:**
|
||||
```bash
|
||||
# Use --foreground and set is_background: true on your shell tool call
|
||||
# so the process survives across turns
|
||||
scripts/start-server.sh --project-dir /path/to/project --foreground
|
||||
```
|
||||
|
||||
**Copilot CLI:**
|
||||
```bash
|
||||
# Use --foreground and start the server via the bash tool with mode: "async"
|
||||
# so the process survives across turns. Capture the returned shellId for
|
||||
# read_bash / stop_bash if you need to interact with it later.
|
||||
scripts/start-server.sh --project-dir /path/to/project --foreground
|
||||
```
|
||||
|
||||
**Other environments:** The server must keep running in the background across conversation turns. If your environment reaps detached processes, use `--foreground` and launch the command with your platform's background execution mechanism.
|
||||
|
||||
If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host:
|
||||
|
||||
```bash
|
||||
scripts/start-server.sh \
|
||||
--project-dir /path/to/project \
|
||||
--host 0.0.0.0 \
|
||||
--url-host localhost
|
||||
```
|
||||
|
||||
Use `--url-host` to control what hostname is printed in the returned URL JSON.
|
||||
|
||||
## The Loop
|
||||
|
||||
1. **Start watcher first** (background bash) — avoids race condition:
|
||||
```bash
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/wait-for-feedback.sh $SCREEN_DIR
|
||||
```
|
||||
|
||||
2. **Write HTML** to a new file in `screen_dir`:
|
||||
1. **Check server is alive**, then **write HTML** to a new file in `screen_dir`:
|
||||
- Before each write, check that `$STATE_DIR/server-info` exists. If it doesn't (or `$STATE_DIR/server-stopped` exists), the server has shut down — restart it with `start-server.sh` before continuing. The server auto-exits after 30 minutes of inactivity.
|
||||
- Use semantic filenames: `platform.html`, `visual-style.html`, `layout.html`
|
||||
- **Never reuse filenames** — each screen gets a fresh file
|
||||
- Use Write tool — **never use cat/heredoc** (dumps noise into terminal)
|
||||
- Use your file-creation tool — **never use cat/heredoc** (dumps noise into terminal)
|
||||
- Server automatically serves the newest file
|
||||
|
||||
3. **Tell user what to expect:**
|
||||
2. **Tell user what to expect and end your turn:**
|
||||
- Remind them of the URL (every step, not just first)
|
||||
- Give a brief text summary of what's on screen (e.g., "Showing 3 layout options for the homepage")
|
||||
- Ask them to respond in the terminal: "Take a look and let me know what you think. Click to select an option if you'd like."
|
||||
|
||||
4. **Wait for feedback** — call `TaskOutput(task_id, block=true, timeout=600000)`
|
||||
- If timeout, call TaskOutput again (watcher still running)
|
||||
- After 3 timeouts (30 min), say "Let me know when you want to continue"
|
||||
3. **On your next turn** — after the user responds in the terminal:
|
||||
- Read `$STATE_DIR/events` if it exists — this contains the user's browser interactions (clicks, selections) as JSON lines
|
||||
- Merge with the user's terminal text to get the full picture
|
||||
- The terminal message is the primary feedback; `state_dir/events` provides structured interaction data
|
||||
|
||||
5. **Process feedback** — returns JSON like `{"choice": "a", "feedback": "make header smaller"}`
|
||||
4. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated.
|
||||
|
||||
6. **Iterate or advance** — if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to the next question when the current step is validated.
|
||||
5. **Unload when returning to terminal** — when the next step doesn't need the browser (e.g., a clarifying question, a tradeoff discussion), push a waiting screen to clear the stale content:
|
||||
|
||||
7. Repeat until done.
|
||||
```html
|
||||
<!-- filename: waiting.html (or waiting-2.html, etc.) -->
|
||||
<div style="display:flex;align-items:center;justify-content:center;min-height:60vh">
|
||||
<p class="subtitle">Continuing in terminal...</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
This prevents the user from staring at a resolved choice while the conversation has moved on. When the next visual question comes up, push a new content file as usual.
|
||||
|
||||
6. Repeat until done.
|
||||
|
||||
## Writing Content Fragments
|
||||
|
||||
Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, feedback footer, interactive JS).
|
||||
Write just the content that goes inside the page. The server wraps it in the frame template automatically (header, theme CSS, selection indicator, and all interactive infrastructure).
|
||||
|
||||
**Minimal example:**
|
||||
|
||||
```html
|
||||
<h2>Which layout works better?</h2>
|
||||
<p class="subtitle">Consider readability and visual hierarchy</p>
|
||||
@@ -94,6 +161,7 @@ That's it. No `<html>`, no CSS, no `<script>` tags needed. The server provides a
|
||||
The frame template provides these CSS classes for your content:
|
||||
|
||||
### Options (A/B/C choices)
|
||||
|
||||
```html
|
||||
<div class="options">
|
||||
<div class="option" data-choice="a" onclick="toggleSelect(this)">
|
||||
@@ -106,7 +174,16 @@ The frame template provides these CSS classes for your content:
|
||||
</div>
|
||||
```
|
||||
|
||||
**Multi-select:** Add `data-multiselect` to the container to let users select multiple options. Each click toggles the item. The indicator bar shows the count.
|
||||
|
||||
```html
|
||||
<div class="options" data-multiselect>
|
||||
<!-- same option markup — users can select/deselect multiple -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Cards (visual designs)
|
||||
|
||||
```html
|
||||
<div class="cards">
|
||||
<div class="card" data-choice="design1" onclick="toggleSelect(this)">
|
||||
@@ -120,6 +197,7 @@ The frame template provides these CSS classes for your content:
|
||||
```
|
||||
|
||||
### Mockup container
|
||||
|
||||
```html
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">Preview: Dashboard Layout</div>
|
||||
@@ -128,6 +206,7 @@ The frame template provides these CSS classes for your content:
|
||||
```
|
||||
|
||||
### Split view (side-by-side)
|
||||
|
||||
```html
|
||||
<div class="split">
|
||||
<div class="mockup"><!-- left --></div>
|
||||
@@ -136,6 +215,7 @@ The frame template provides these CSS classes for your content:
|
||||
```
|
||||
|
||||
### Pros/Cons
|
||||
|
||||
```html
|
||||
<div class="pros-cons">
|
||||
<div class="pros"><h4>Pros</h4><ul><li>Benefit</li></ul></div>
|
||||
@@ -144,6 +224,7 @@ The frame template provides these CSS classes for your content:
|
||||
```
|
||||
|
||||
### Mock elements (wireframe building blocks)
|
||||
|
||||
```html
|
||||
<div class="mock-nav">Logo | Home | About | Contact</div>
|
||||
<div style="display: flex;">
|
||||
@@ -156,22 +237,26 @@ The frame template provides these CSS classes for your content:
|
||||
```
|
||||
|
||||
### Typography and sections
|
||||
|
||||
- `h2` — page title
|
||||
- `h3` — section heading
|
||||
- `.subtitle` — secondary text below title
|
||||
- `.section` — content block with bottom margin
|
||||
- `.label` — small uppercase label text
|
||||
|
||||
## User Feedback Format
|
||||
## Browser Events Format
|
||||
|
||||
```json
|
||||
{
|
||||
"choice": "option-id",
|
||||
"feedback": "user notes"
|
||||
}
|
||||
When the user clicks options in the browser, their interactions are recorded to `$STATE_DIR/events` (one JSON object per line). The file is cleared automatically when you push a new screen.
|
||||
|
||||
```jsonl
|
||||
{"type":"click","choice":"a","text":"Option A - Simple Layout","timestamp":1706000101}
|
||||
{"type":"click","choice":"c","text":"Option C - Complex Grid","timestamp":1706000108}
|
||||
{"type":"click","choice":"b","text":"Option B - Hybrid","timestamp":1706000115}
|
||||
```
|
||||
|
||||
Both fields are optional — user may select without notes, or send notes without a selection.
|
||||
The full event stream shows the user's exploration path — they may click multiple options before settling. The last `choice` event is typically the final selection, but the pattern of clicks can reveal hesitation or preferences worth asking about.
|
||||
|
||||
If `$STATE_DIR/events` doesn't exist, the user didn't interact with the browser — use only their terminal text.
|
||||
|
||||
## Design Tips
|
||||
|
||||
@@ -192,12 +277,12 @@ Both fields are optional — user may select without notes, or send notes withou
|
||||
## Cleaning Up
|
||||
|
||||
```bash
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/stop-server.sh $SCREEN_DIR
|
||||
scripts/stop-server.sh $SESSION_DIR
|
||||
```
|
||||
|
||||
If the session used `--project-dir`, mockup files persist in `.superpowers/brainstorm/` for later reference. Only `/tmp` sessions get deleted on stop.
|
||||
|
||||
## Reference
|
||||
|
||||
- Frame template (CSS reference): `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/frame-template.html`
|
||||
- Helper script (JS API): `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/helper.js`
|
||||
- Frame template (CSS reference): `scripts/frame-template.html`
|
||||
- Helper script (client-side): `scripts/helper.js`
|
||||
|
||||
@@ -7,6 +7,8 @@ description: Use when facing 2+ independent tasks that can be worked on without
|
||||
|
||||
## Overview
|
||||
|
||||
You delegate tasks to specialized agents with isolated context. By precisely crafting their instructions and context, you ensure they stay focused and succeed at their task. They should never inherit your session's context or history — you construct exactly what they need. This also preserves your own context for coordination work.
|
||||
|
||||
When you have multiple unrelated failures (different test files, different subsystems, different bugs), investigating them sequentially wastes time. Each investigation is independent and can happen in parallel.
|
||||
|
||||
**Core principle:** Dispatch one agent per independent problem domain. Let them work concurrently.
|
||||
@@ -63,14 +65,17 @@ Each agent gets:
|
||||
|
||||
### 3. Dispatch in Parallel
|
||||
|
||||
```typescript
|
||||
// In Claude Code / AI environment
|
||||
Task("Fix agent-tool-abort.test.ts failures")
|
||||
Task("Fix batch-completion-behavior.test.ts failures")
|
||||
Task("Fix tool-approval-race-conditions.test.ts failures")
|
||||
// All three run concurrently
|
||||
Issue all three subagent dispatches in the same response — they run in parallel:
|
||||
|
||||
```text
|
||||
Subagent (general-purpose): "Fix agent-tool-abort.test.ts failures"
|
||||
Subagent (general-purpose): "Fix batch-completion-behavior.test.ts failures"
|
||||
Subagent (general-purpose): "Fix tool-approval-race-conditions.test.ts failures"
|
||||
# All three run concurrently.
|
||||
```
|
||||
|
||||
Multiple dispatch calls in one response = parallel execution. One per response = sequential.
|
||||
|
||||
### 4. Review and Integrate
|
||||
|
||||
When agents return:
|
||||
|
||||
@@ -7,22 +7,21 @@ description: Use when you have a written implementation plan to execute in a sep
|
||||
|
||||
## Overview
|
||||
|
||||
Load plan, review critically, execute tasks in batches, report for review between batches.
|
||||
|
||||
**Core principle:** Batch execution with checkpoints for architect review.
|
||||
Load plan, review critically, execute all tasks, report when complete.
|
||||
|
||||
**Announce at start:** "I'm using the executing-plans skill to implement this plan."
|
||||
|
||||
**Note:** Tell your human partner that Superpowers works much better with access to subagents. The quality of its work will be significantly higher if run on a platform with subagent support (Claude Code, Codex CLI, Codex App, Copilot CLI, and Gemini CLI all qualify; see the per-platform tool refs in `../using-superpowers/references/`). If subagents are available, use superpowers:subagent-driven-development instead of this skill.
|
||||
|
||||
## The Process
|
||||
|
||||
### Step 1: Load and Review Plan
|
||||
1. Read plan file
|
||||
2. Review critically - identify any questions or concerns about the plan
|
||||
3. If concerns: Raise them with your human partner before starting
|
||||
4. If no concerns: Create TodoWrite and proceed
|
||||
4. If no concerns: Create todos for the plan items and proceed
|
||||
|
||||
### Step 2: Execute Batch
|
||||
**Default: First 3 tasks**
|
||||
### Step 2: Execute Tasks
|
||||
|
||||
For each task:
|
||||
1. Mark as in_progress
|
||||
@@ -30,19 +29,7 @@ For each task:
|
||||
3. Run verifications as specified
|
||||
4. Mark as completed
|
||||
|
||||
### Step 3: Report
|
||||
When batch complete:
|
||||
- Show what was implemented
|
||||
- Show verification output
|
||||
- Say: "Ready for feedback."
|
||||
|
||||
### Step 4: Continue
|
||||
Based on feedback:
|
||||
- Apply changes if needed
|
||||
- Execute next batch
|
||||
- Repeat until complete
|
||||
|
||||
### Step 5: Complete Development
|
||||
### Step 3: Complete Development
|
||||
|
||||
After all tasks complete and verified:
|
||||
- Announce: "I'm using the finishing-a-development-branch skill to complete this work."
|
||||
@@ -52,7 +39,7 @@ After all tasks complete and verified:
|
||||
## When to Stop and Ask for Help
|
||||
|
||||
**STOP executing immediately when:**
|
||||
- Hit a blocker mid-batch (missing dependency, test fails, instruction unclear)
|
||||
- Hit a blocker (missing dependency, test fails, instruction unclear)
|
||||
- Plan has critical gaps preventing starting
|
||||
- You don't understand an instruction
|
||||
- Verification fails repeatedly
|
||||
@@ -72,13 +59,12 @@ After all tasks complete and verified:
|
||||
- Follow plan steps exactly
|
||||
- Don't skip verifications
|
||||
- Reference skills when plan says to
|
||||
- Between batches: just report and wait
|
||||
- Stop when blocked, don't guess
|
||||
- Never start implementation on main/master branch without explicit user consent
|
||||
|
||||
## 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
|
||||
|
||||
@@ -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/` or `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/` or `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
|
||||
|
||||
@@ -27,7 +27,7 @@ WHEN receiving code review feedback:
|
||||
## Forbidden Responses
|
||||
|
||||
**NEVER:**
|
||||
- "You're absolutely right!" (explicit CLAUDE.md violation)
|
||||
- "You're absolutely right!" (explicit instruction-file violation)
|
||||
- "Great point!" / "Excellent feedback!" (performative)
|
||||
- "Let me implement that now" (before verification)
|
||||
|
||||
@@ -126,7 +126,7 @@ Push back when:
|
||||
- Reference working tests/code
|
||||
- Involve your human partner if architectural
|
||||
|
||||
**Signal if uncomfortable pushing back out loud:** "Strange things are afoot at the Circle K"
|
||||
**If you're uncomfortable pushing back out loud:** Name that tension, then tell your partner about the issue you've seen. They'll appreciate your honesty.
|
||||
|
||||
## Acknowledging Correct Feedback
|
||||
|
||||
|
||||
@@ -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.
|
||||
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`
|
||||
Dispatch a `general-purpose` subagent, filling the template at [code-reviewer.md](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:**
|
||||
@@ -102,4 +100,4 @@ You: [Fix progress indicators]
|
||||
- Show code/tests that prove it works
|
||||
- Request clarification
|
||||
|
||||
See template at: requesting-code-review/code-reviewer.md
|
||||
See template at: [code-reviewer.md](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
|
||||
```
|
||||
Subagent (general-purpose):
|
||||
description: "Review code changes"
|
||||
prompt: |
|
||||
You are a Senior Code Reviewer with expertise in software architecture,
|
||||
design patterns, and best practices. Your job is to review completed work
|
||||
against its plan or requirements and identify issues before they cascade.
|
||||
|
||||
{DESCRIPTION}
|
||||
## What Was Implemented
|
||||
|
||||
## Requirements/Plan
|
||||
{DESCRIPTION}
|
||||
|
||||
{PLAN_REFERENCE}
|
||||
## Requirements / Plan
|
||||
|
||||
## Git Range to Review
|
||||
{PLAN_OR_REQUIREMENTS}
|
||||
|
||||
**Base:** {BASE_SHA}
|
||||
**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
|
||||
|
||||
|
||||
@@ -7,8 +7,12 @@ description: Use when executing implementation plans with independent tasks in t
|
||||
|
||||
Execute plan by dispatching fresh subagent per task, with two-stage review after each: spec compliance review first, then code quality review.
|
||||
|
||||
**Why subagents:** You delegate tasks to specialized agents with isolated context. By precisely crafting their instructions and context, you ensure they stay focused and succeed at their task. They should never inherit your session's context or history — you construct exactly what they need. This also preserves your own context for coordination work.
|
||||
|
||||
**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
|
||||
@@ -53,15 +57,15 @@ digraph process {
|
||||
"Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [shape=box];
|
||||
"Code quality reviewer subagent approves?" [shape=diamond];
|
||||
"Implementer subagent fixes quality issues" [shape=box];
|
||||
"Mark task complete in TodoWrite" [shape=box];
|
||||
"Mark task complete in todo list" [shape=box];
|
||||
}
|
||||
|
||||
"Read plan, extract all tasks with full text, note context, create TodoWrite" [shape=box];
|
||||
"Read plan, extract all tasks with full text, note context, create todos" [shape=box];
|
||||
"More tasks remain?" [shape=diamond];
|
||||
"Dispatch final code reviewer subagent for entire implementation" [shape=box];
|
||||
"Use superpowers:finishing-a-development-branch" [shape=box style=filled fillcolor=lightgreen];
|
||||
|
||||
"Read plan, extract all tasks with full text, note context, create TodoWrite" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
||||
"Read plan, extract all tasks with full text, note context, create todos" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
||||
"Dispatch implementer subagent (./implementer-prompt.md)" -> "Implementer subagent asks questions?";
|
||||
"Implementer subagent asks questions?" -> "Answer questions, provide context" [label="yes"];
|
||||
"Answer questions, provide context" -> "Dispatch implementer subagent (./implementer-prompt.md)";
|
||||
@@ -74,8 +78,8 @@ digraph process {
|
||||
"Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" -> "Code quality reviewer subagent approves?";
|
||||
"Code quality reviewer subagent approves?" -> "Implementer subagent fixes quality issues" [label="no"];
|
||||
"Implementer subagent fixes quality issues" -> "Dispatch code quality reviewer subagent (./code-quality-reviewer-prompt.md)" [label="re-review"];
|
||||
"Code quality reviewer subagent approves?" -> "Mark task complete in TodoWrite" [label="yes"];
|
||||
"Mark task complete in TodoWrite" -> "More tasks remain?";
|
||||
"Code quality reviewer subagent approves?" -> "Mark task complete in todo list" [label="yes"];
|
||||
"Mark task complete in todo list" -> "More tasks remain?";
|
||||
"More tasks remain?" -> "Dispatch implementer subagent (./implementer-prompt.md)" [label="yes"];
|
||||
"More tasks remain?" -> "Dispatch final code reviewer subagent for entire implementation" [label="no"];
|
||||
"Dispatch final code reviewer subagent for entire implementation" -> "Use superpowers:finishing-a-development-branch";
|
||||
@@ -117,9 +121,9 @@ Implementer subagents report one of four statuses. Handle each appropriately:
|
||||
|
||||
## Prompt Templates
|
||||
|
||||
- `./implementer-prompt.md` - Dispatch implementer subagent
|
||||
- `./spec-reviewer-prompt.md` - Dispatch spec compliance reviewer subagent
|
||||
- `./code-quality-reviewer-prompt.md` - Dispatch code quality reviewer subagent
|
||||
- [implementer-prompt.md](implementer-prompt.md) - Dispatch implementer subagent
|
||||
- [spec-reviewer-prompt.md](spec-reviewer-prompt.md) - Dispatch spec compliance reviewer subagent
|
||||
- [code-quality-reviewer-prompt.md](code-quality-reviewer-prompt.md) - Dispatch code quality reviewer subagent
|
||||
|
||||
## Example Workflow
|
||||
|
||||
@@ -128,7 +132,7 @@ You: I'm using Subagent-Driven Development to execute this plan.
|
||||
|
||||
[Read plan file once: docs/superpowers/plans/feature-plan.md]
|
||||
[Extract all 5 tasks with full text and context]
|
||||
[Create TodoWrite with all tasks]
|
||||
[Create todos for all tasks]
|
||||
|
||||
Task 1: Hook installation script
|
||||
|
||||
@@ -263,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
|
||||
|
||||
@@ -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):
|
||||
Use template at requesting-code-review/code-reviewer.md
|
||||
Subagent (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:**
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Use this template when dispatching an implementer subagent.
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Implement Task N: [task name]"
|
||||
prompt: |
|
||||
You are implementing Task N: [task name]
|
||||
|
||||
@@ -5,7 +5,7 @@ Use this template when dispatching a spec compliance reviewer subagent.
|
||||
**Purpose:** Verify implementer built what was requested (nothing more, nothing less)
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
Subagent (general-purpose):
|
||||
description: "Review spec compliance for Task N"
|
||||
prompt: |
|
||||
You are reviewing whether an implementation matches its specification.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -356,7 +356,7 @@ Never fix bugs without a test.
|
||||
|
||||
## Testing Anti-Patterns
|
||||
|
||||
When adding mocks or test utilities, read @testing-anti-patterns.md to avoid common pitfalls:
|
||||
When adding mocks or test utilities, read [testing-anti-patterns.md](testing-anti-patterns.md) to avoid common pitfalls:
|
||||
- Testing mock behavior instead of real behavior
|
||||
- Adding test-only methods to production classes
|
||||
- Mocking without understanding dependencies
|
||||
|
||||
@@ -1,104 +1,105 @@
|
||||
---
|
||||
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 2 (Project Setup). Do NOT create another worktree.
|
||||
|
||||
### 3. Ask User
|
||||
Report with branch state:
|
||||
- On a branch: "Already in isolated workspace at `<path>` on branch `<name>`."
|
||||
- Detached HEAD: "Already in isolated workspace at `<path>` (detached HEAD, externally managed). Branch creation needed at finish time."
|
||||
|
||||
If no directory exists and no CLAUDE.md preference:
|
||||
**If `GIT_DIR == GIT_COMMON` (or in a submodule):** You are in a normal repo checkout.
|
||||
|
||||
```
|
||||
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 2.
|
||||
|
||||
## Safety Verification
|
||||
## Step 1: Create Isolated Workspace
|
||||
|
||||
### For Project-Local Directories (.worktrees or worktrees)
|
||||
**You have two mechanisms. Try them in this order.**
|
||||
|
||||
### 1a. Native Worktree Tools (preferred)
|
||||
|
||||
The user has asked for an isolated workspace (Step 0 consent). Do you already have a way to create a worktree? It might be a tool with a name like `EnterWorktree`, `WorktreeCreate`, a `/worktree` command, or a `--worktree` flag. If you do, use it and skip to Step 2.
|
||||
|
||||
Native tools handle directory placement, branch creation, and cleanup automatically. Using `git worktree add` when you have a native tool creates phantom state your harness can't see or manage.
|
||||
|
||||
Only proceed to Step 1b if you have no native worktree tool available.
|
||||
|
||||
### 1b. Git Worktree Fallback
|
||||
|
||||
**Only use this if Step 1a does not apply** — you have no native worktree tool available. Create a worktree manually using git.
|
||||
|
||||
#### Directory Selection
|
||||
|
||||
Follow this priority order. Explicit user preference always beats observed filesystem state.
|
||||
|
||||
1. **Check your instructions for a declared worktree directory preference.** If the user has already specified one, use it without asking.
|
||||
|
||||
2. **Check for an existing project-local worktree directory:**
|
||||
```bash
|
||||
ls -d .worktrees 2>/dev/null # Preferred (hidden)
|
||||
ls -d worktrees 2>/dev/null # Alternative
|
||||
```
|
||||
If found, use it. If both exist, `.worktrees` wins.
|
||||
|
||||
3. **If there is no other guidance available**, default to `.worktrees/` at the project root.
|
||||
|
||||
#### Safety Verification (project-local directories only)
|
||||
|
||||
**MUST verify directory is ignored before creating worktree:**
|
||||
|
||||
```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)
|
||||
|
||||
No .gitignore verification needed - outside project entirely.
|
||||
|
||||
## Creation Steps
|
||||
|
||||
### 1. Detect Project Name
|
||||
#### Create the Worktree
|
||||
|
||||
```bash
|
||||
project=$(basename "$(git rev-parse --show-toplevel)")
|
||||
```
|
||||
# Determine path based on chosen location
|
||||
path="$LOCATION/$BRANCH_NAME"
|
||||
|
||||
### 2. Create Worktree
|
||||
|
||||
```bash
|
||||
# Determine full path
|
||||
case $LOCATION in
|
||||
.worktrees|worktrees)
|
||||
path="$LOCATION/$BRANCH_NAME"
|
||||
;;
|
||||
~/.config/superpowers/worktrees/*)
|
||||
path="~/.config/superpowers/worktrees/$project/$BRANCH_NAME"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Create worktree with new branch
|
||||
git worktree add "$path" -b "$BRANCH_NAME"
|
||||
cd "$path"
|
||||
```
|
||||
|
||||
### 3. Run Project Setup
|
||||
**Sandbox fallback:** If `git worktree add` fails with a permission error (sandbox denial), tell the user the sandbox blocked worktree creation and you're working in the current directory instead. Then run setup and baseline tests in place.
|
||||
|
||||
## Step 2: Project Setup
|
||||
|
||||
Auto-detect and run appropriate setup:
|
||||
|
||||
@@ -117,23 +118,20 @@ if [ -f pyproject.toml ]; then poetry install; fi
|
||||
if [ -f go.mod ]; then go mod download; fi
|
||||
```
|
||||
|
||||
### 4. Verify Clean Baseline
|
||||
## Step 3: Verify Clean Baseline
|
||||
|
||||
Run tests to ensure worktree starts clean:
|
||||
Run tests to ensure workspace starts clean:
|
||||
|
||||
```bash
|
||||
# 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 +143,31 @@ 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/` |
|
||||
| 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 +176,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: explicit instructions > existing project-local directory > 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: explicit instructions > existing project-local directory > 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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: using-superpowers
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring skill invocation before ANY response including clarifying questions
|
||||
---
|
||||
|
||||
<SUBAGENT-STOP>
|
||||
@@ -19,21 +19,29 @@ This is not negotiable. This is not optional. You cannot rationalize your way ou
|
||||
|
||||
Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:
|
||||
|
||||
1. **User's explicit instructions** (CLAUDE.md, direct requests) — highest priority
|
||||
1. **User's explicit instructions** (CLAUDE.md, GEMINI.md, AGENTS.md, direct requests) — highest priority
|
||||
2. **Superpowers skills** — override default system behavior where they conflict
|
||||
3. **Default system prompt** — lowest priority
|
||||
|
||||
If CLAUDE.md says "don't use TDD" and a skill says "always use TDD," follow CLAUDE.md. The user is in control.
|
||||
If CLAUDE.md, GEMINI.md, or AGENTS.md says "don't use TDD" and a skill says "always use TDD," follow the user's instructions. The user is in control.
|
||||
|
||||
## How to Access Skills
|
||||
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you—follow it directly. Never use the Read tool on skill files.
|
||||
**Never read skill files manually with file tools** — always use your platform's skill-loading mechanism so the skill is properly activated.
|
||||
|
||||
**In Claude Code:** Use the `Skill` tool. When you invoke a skill, its content is loaded and presented to you — follow it directly.
|
||||
|
||||
**In Codex:** Skills load natively. Follow the instructions presented when a skill activates.
|
||||
|
||||
**In Copilot CLI:** Use the `skill` tool. Skills are auto-discovered from installed plugins.
|
||||
|
||||
**In Gemini CLI:** Skills activate via the `activate_skill` tool. Gemini loads skill metadata at session start and activates the full content on demand.
|
||||
|
||||
**In other environments:** Check your platform's documentation for how skills are loaded.
|
||||
|
||||
## Platform Adaptation
|
||||
|
||||
Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools.md` for tool equivalents.
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file") rather than naming any one runtime's tools. For per-platform tool equivalents and instructions-file conventions, see [claude-code-tools.md](references/claude-code-tools.md), [codex-tools.md](references/codex-tools.md), [copilot-tools.md](references/copilot-tools.md), [gemini-tools.md](references/gemini-tools.md), and [pi-tools.md](references/pi-tools.md). Gemini CLI users get the tool mapping loaded automatically via GEMINI.md.
|
||||
|
||||
# Using Skills
|
||||
|
||||
@@ -44,22 +52,30 @@ Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools
|
||||
```dot
|
||||
digraph skill_flow {
|
||||
"User message received" [shape=doublecircle];
|
||||
"About to enter plan mode?" [shape=doublecircle];
|
||||
"Already brainstormed?" [shape=diamond];
|
||||
"Invoke brainstorming skill" [shape=box];
|
||||
"Might any skill apply?" [shape=diamond];
|
||||
"Invoke Skill tool" [shape=box];
|
||||
"Invoke the skill" [shape=box];
|
||||
"Announce: 'Using [skill] to [purpose]'" [shape=box];
|
||||
"Has checklist?" [shape=diamond];
|
||||
"Create TodoWrite todo per item" [shape=box];
|
||||
"Create a todo per item" [shape=box];
|
||||
"Follow skill exactly" [shape=box];
|
||||
"Respond (including clarifications)" [shape=doublecircle];
|
||||
|
||||
"About to enter plan mode?" -> "Already brainstormed?";
|
||||
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
|
||||
"Already brainstormed?" -> "Might any skill apply?" [label="yes"];
|
||||
"Invoke brainstorming skill" -> "Might any skill apply?";
|
||||
|
||||
"User message received" -> "Might any skill apply?";
|
||||
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Invoke the skill" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
|
||||
"Invoke Skill tool" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Invoke the skill" -> "Announce: 'Using [skill] to [purpose]'";
|
||||
"Announce: 'Using [skill] to [purpose]'" -> "Has checklist?";
|
||||
"Has checklist?" -> "Create TodoWrite todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Create a todo per item" [label="yes"];
|
||||
"Has checklist?" -> "Follow skill exactly" [label="no"];
|
||||
"Create TodoWrite todo per item" -> "Follow skill exactly";
|
||||
"Create a todo per item" -> "Follow skill exactly";
|
||||
}
|
||||
```
|
||||
|
||||
@@ -81,7 +97,6 @@ These thoughts mean STOP—you're rationalizing:
|
||||
| "I'll just do this one thing first" | Check BEFORE doing anything. |
|
||||
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
|
||||
| "I know what that means" | Knowing the concept ≠ using the skill. Invoke it. |
|
||||
| "Let me enter plan mode first" | If a skill handles planning (writing-plans, brainstorming), use the skill directly. EnterPlanMode is redundant — never layer it with a planning skill. |
|
||||
|
||||
## Skill Priority
|
||||
|
||||
|
||||
50
skills/using-superpowers/references/claude-code-tools.md
Normal file
50
skills/using-superpowers/references/claude-code-tools.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Claude Code Tool Mapping
|
||||
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Claude Code these resolve to the tools below.
|
||||
|
||||
## Tools
|
||||
|
||||
| Action skills request | Claude Code tool |
|
||||
|----------------------|------------------|
|
||||
| Read a file | `Read` |
|
||||
| Create a new file | `Write` |
|
||||
| Edit a file | `Edit` |
|
||||
| Run a shell command | `Bash` |
|
||||
| Search file contents | `Grep` |
|
||||
| Find files by name | `Glob` |
|
||||
| Fetch a URL | `WebFetch` |
|
||||
| Search the web | `WebSearch` |
|
||||
| Invoke a skill | `Skill` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `Agent` (older releases named this `Task`) |
|
||||
| Multiple parallel dispatches | Multiple `Agent` calls in one response |
|
||||
| Task tracking ("create a todo", "mark complete") | `TaskCreate`, `TaskUpdate`, `TaskList`, `TaskGet`; `TodoWrite` in `claude -p` / Agent SDK unless `CLAUDE_CODE_ENABLE_TASKS=1` is set |
|
||||
| Background-process / subagent lifecycle (read output, cancel) | `TaskOutput`, `TaskStop` — these are distinct from the todo tools above and apply to running shells, agents, and remote sessions |
|
||||
|
||||
## Instructions file
|
||||
|
||||
When a skill mentions "your instructions file", on Claude Code this is **`CLAUDE.md`**. Claude Code walks up the directory tree from the current working directory and concatenates every `CLAUDE.md` and `CLAUDE.local.md` it finds along the way. Standard locations:
|
||||
|
||||
| Scope | Location |
|
||||
|-------|----------|
|
||||
| Project (team-shared) | `./CLAUDE.md` or `./.claude/CLAUDE.md` |
|
||||
| User global | `~/.claude/CLAUDE.md` |
|
||||
| Local-private (gitignored) | `./CLAUDE.local.md` |
|
||||
| Managed policy (org-wide) | `/Library/Application Support/ClaudeCode/CLAUDE.md` (macOS), `/etc/claude-code/CLAUDE.md` (Linux/WSL), `C:\Program Files\ClaudeCode\CLAUDE.md` (Windows) |
|
||||
|
||||
CLAUDE.md files can pull in additional content with `@path/to/file` imports (relative or absolute, max five hops deep). Subdirectory `CLAUDE.md` files are also discovered automatically and loaded on-demand when Claude Code reads files in those subdirectories.
|
||||
|
||||
Claude Code does **not** read `AGENTS.md` directly. If a project already maintains `AGENTS.md` for other agents, import it from `CLAUDE.md` so both runtimes share the same instructions:
|
||||
|
||||
```markdown
|
||||
@AGENTS.md
|
||||
|
||||
## Claude Code
|
||||
|
||||
(Claude-Code-specific instructions go here.)
|
||||
```
|
||||
|
||||
For path-scoped rules and larger-project organization, see `.claude/rules/` (rules can be scoped to specific files via `paths` frontmatter and load on demand).
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`~/.claude/skills/`**. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter) plus any supporting files. Claude Code does not currently recognize the cross-runtime `~/.agents/skills/` path that Codex, Copilot CLI, and Gemini CLI read; if you're relying on cross-runtime support in the future, verify against the [official skills docs](https://code.claude.com/docs/en/skills).
|
||||
@@ -1,25 +1,72 @@
|
||||
# Codex Tool Mapping
|
||||
|
||||
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Codex these resolve to the tools below.
|
||||
|
||||
| Skill references | Codex equivalent |
|
||||
|-----------------|------------------|
|
||||
| `Task` tool (dispatch subagent) | `spawn_agent` |
|
||||
| Multiple `Task` calls (parallel) | Multiple `spawn_agent` calls |
|
||||
| Task returns result | `wait` |
|
||||
| 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 |
|
||||
| `Read`, `Write`, `Edit` (files) | Use your native file tools |
|
||||
| `Bash` (run commands) | Use your native shell tools |
|
||||
| Action skills request | Codex equivalent |
|
||||
|----------------------|------------------|
|
||||
| Read a file | `shell` (e.g., `cat`, `head`, `tail`) — Codex reads files via shell |
|
||||
| Create / edit / delete a file | `apply_patch` (structured diff for create, update, delete) |
|
||||
| Run a shell command | `shell` |
|
||||
| Search file contents | `shell` (e.g., `grep`, `rg`) |
|
||||
| Find files by name | `shell` (e.g., `find`, `ls`) |
|
||||
| Fetch a URL | `shell` with `curl` / `wget` — Codex has no native fetch tool |
|
||||
| Search the web | `web_search` (enabled by default; configurable in `config.toml` via the top-level `web_search` setting — `live`, `cached`, or `disabled`) |
|
||||
| Invoke a skill | Skills load natively — just follow the instructions |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `spawn_agent` (see [Subagent dispatch requires multi-agent support](#subagent-dispatch-requires-multi-agent-support)) |
|
||||
| Multiple parallel dispatches | Multiple `spawn_agent` calls in one response |
|
||||
| Wait for subagent result | `wait_agent` |
|
||||
| Free up subagent slot when done | `close_agent` |
|
||||
| Task tracking ("create a todo", "mark complete") | `update_plan` |
|
||||
|
||||
## Subagent dispatch requires collab
|
||||
## Instructions file
|
||||
|
||||
When a skill mentions "your instructions file", on Codex this is **`AGENTS.md`** at the project root. Codex also reads `~/.codex/AGENTS.md` for global context, and an `AGENTS.override.md` (in the project tree or `~/.codex/`) takes precedence when present. Codex walks from the project root down to the current working directory, concatenating `AGENTS.md` files it finds along the way, up to `project_doc_max_bytes` (32 KiB by default).
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`$CODEX_HOME/skills/`** (default `~/.codex/skills/`). Codex also reads the cross-runtime path **`~/.agents/skills/`** (shared with Copilot CLI and Gemini CLI). When both directories exist at the same scope, Codex loads them both as separate skill catalogs — Codex's docs don't currently document a precedence between them. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
|
||||
|
||||
## Subagent dispatch requires multi-agent support
|
||||
|
||||
Add to your Codex config (`~/.codex/config.toml`):
|
||||
|
||||
```toml
|
||||
[features]
|
||||
collab = true
|
||||
multi_agent = true
|
||||
```
|
||||
|
||||
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
This enables `spawn_agent`, `wait_agent`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.
|
||||
|
||||
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
|
||||
|
||||
Skills that create worktrees or finish branches should detect their
|
||||
environment with read-only git commands before proceeding:
|
||||
|
||||
```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)
|
||||
```
|
||||
|
||||
- `GIT_DIR != GIT_COMMON` → already in a linked worktree (skip creation)
|
||||
- `BRANCH` empty → detached HEAD (cannot branch/push/PR from sandbox)
|
||||
|
||||
See `using-git-worktrees` Step 0 and `finishing-a-development-branch`
|
||||
Step 1 for how each skill uses these signals.
|
||||
|
||||
## Codex App Finishing
|
||||
|
||||
When the sandbox blocks branch/push operations (detached HEAD in an
|
||||
externally managed worktree), the agent commits all work and informs
|
||||
the user to use the App's native controls:
|
||||
|
||||
- **"Create branch"** — names the branch, then commit/push/PR via App UI
|
||||
- **"Hand off to local"** — transfers work to the user's local checkout
|
||||
|
||||
The agent can still run tests, stage files, and output suggested branch
|
||||
names, commit messages, and PR descriptions for the user to copy.
|
||||
|
||||
49
skills/using-superpowers/references/copilot-tools.md
Normal file
49
skills/using-superpowers/references/copilot-tools.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Copilot CLI Tool Mapping
|
||||
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Copilot CLI these resolve to the tools below.
|
||||
|
||||
| Action skills request | Copilot CLI equivalent |
|
||||
|----------------------|----------------------|
|
||||
| Read a file | `view` |
|
||||
| Create / edit / delete a file | `apply_patch` (Copilot CLI has no separate create/edit/write tools) |
|
||||
| Run a shell command | `bash` |
|
||||
| Search file contents | `rg` (ripgrep; Copilot CLI does not expose a `grep` tool) |
|
||||
| Find files by name | `glob` |
|
||||
| Fetch a URL | `web_fetch` |
|
||||
| Search the web | `web_search` |
|
||||
| Invoke a skill | `skill` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `task` with `agent_type: "general-purpose"` (other accepted types: `explore`, `task`, `code-review`, `research`, `configure-copilot`) |
|
||||
| Multiple parallel dispatches | Multiple `task` calls in one response |
|
||||
| Subagent status/output/control | `read_agent`, `list_agents`, `write_agent` |
|
||||
| Task tracking ("create a todo", "mark complete") | `update_todo` |
|
||||
| Enter / exit plan mode | No equivalent — stay in the main session |
|
||||
|
||||
## Instructions file
|
||||
|
||||
When a skill mentions "your instructions file", on Copilot CLI this is **`AGENTS.md`** at the repository root. If both `AGENTS.md` and `.github/copilot-instructions.md` are present, Copilot reads both.
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`~/.copilot/skills/`**. Copilot CLI also recognizes the cross-runtime alias **`~/.agents/skills/`**, which is shared with Codex and Gemini CLI. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
|
||||
|
||||
## Async shell sessions
|
||||
|
||||
Copilot CLI supports persistent async shell sessions:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `bash` with `mode: "async"` (and optionally `detach: true`) | Start a long-running command in the background; returns a `shellId` |
|
||||
| `write_bash` | Send input to a running async session |
|
||||
| `read_bash` | Read output from an async session |
|
||||
| `stop_bash` | Terminate an async session |
|
||||
| `list_bash` | List all active shell sessions |
|
||||
|
||||
## Additional Copilot CLI tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `store_memory` | Persist facts about the codebase for future sessions |
|
||||
| `report_intent` | Update the UI status line with current intent |
|
||||
| `sql` | Query the session's SQLite database (todos, metadata) |
|
||||
| `fetch_copilot_cli_documentation` | Look up Copilot CLI documentation |
|
||||
| GitHub MCP tools (`github-mcp-server-*`) | Native GitHub API access (issues, PRs, code search) |
|
||||
63
skills/using-superpowers/references/gemini-tools.md
Normal file
63
skills/using-superpowers/references/gemini-tools.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Gemini CLI Tool Mapping
|
||||
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Gemini CLI these resolve to the tools below.
|
||||
|
||||
| Action skills request | Gemini CLI equivalent |
|
||||
|----------------------|----------------------|
|
||||
| Read a file | `read_file` |
|
||||
| Read multiple files at once | `read_many_files` |
|
||||
| Create a new file | `write_file` |
|
||||
| Edit a file | `replace` |
|
||||
| Run a shell command | `run_shell_command` |
|
||||
| Search file contents | `grep_search` |
|
||||
| Find files by name | `glob` |
|
||||
| List files and subdirectories | `list_directory` |
|
||||
| Fetch a URL | `web_fetch` |
|
||||
| Search the web | `google_web_search` |
|
||||
| Invoke a skill | `activate_skill` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | `invoke_agent` with `agent_name: "generalist"` (invocable via `@generalist` chat syntax — see [Subagent support](#subagent-support)) |
|
||||
| Multiple parallel dispatches | Multiple `invoke_agent` calls in the same response |
|
||||
| Task tracking ("create a todo", "mark complete") | `write_todos` (statuses: pending, in_progress, completed, cancelled, blocked) |
|
||||
|
||||
## Instructions file
|
||||
|
||||
When a skill mentions "your instructions file", on Gemini CLI this is **`GEMINI.md`**. Gemini CLI loads `GEMINI.md` hierarchically: global at `~/.gemini/GEMINI.md`, project-level files in workspace directories and their ancestors, and sub-directory `GEMINI.md` files when a tool accesses files in those directories.
|
||||
|
||||
## Personal skills directory
|
||||
|
||||
User-level skills live at **`~/.gemini/skills/`**, with **`~/.agents/skills/`** as a cross-runtime alias (shared with Codex and Copilot CLI). When both directories exist at the same scope, `.agents/skills/` takes precedence. Each skill is a subdirectory containing a `SKILL.md` (with `name` and `description` frontmatter).
|
||||
|
||||
## Subagent support
|
||||
|
||||
Gemini CLI dispatches subagents through the `invoke_agent` tool, which takes `agent_name` and `prompt` parameters. The same dispatch is also surfaced as a chat-syntax shortcut: typing `@generalist <prompt>` is equivalent to calling `invoke_agent` with `agent_name: "generalist"`. Built-in agent names include `generalist`, `cli_help`, `codebase_investigator`, and (with browser tooling enabled) `browser_agent`.
|
||||
|
||||
Skills dispatch with `Subagent (general-purpose):` and either reference a prompt-template file (e.g., `superpowers:subagent-driven-development`'s `./implementer-prompt.md`) or supply an inline prompt. On Gemini CLI:
|
||||
|
||||
| Skill dispatch form | Gemini CLI equivalent |
|
||||
|---------------------|----------------------|
|
||||
| References a `*-prompt.md` template (implementer, spec-reviewer, code-quality-reviewer, code-reviewer, etc.) | Fill the template, then `invoke_agent` with `agent_name: "generalist"` and the filled prompt |
|
||||
| References `superpowers:requesting-code-review`'s `./code-reviewer.md` | `invoke_agent` with `agent_name: "generalist"` and the filled review template |
|
||||
| Inline prompt (no template referenced) | `invoke_agent` with `agent_name: "generalist"` and your inline prompt |
|
||||
|
||||
### Prompt filling
|
||||
|
||||
Skills provide prompt templates with placeholders like `{WHAT_WAS_IMPLEMENTED}` or `[FULL TEXT of task]`. Fill all placeholders before passing the complete prompt to `invoke_agent`. The prompt template itself contains the agent's role, review criteria, and expected output format — the subagent will follow it.
|
||||
|
||||
### Parallel dispatch
|
||||
|
||||
Gemini CLI supports parallel subagent dispatch. Issue multiple `invoke_agent` calls in the same response (or multiple `@generalist` invocations in one prompt) to run independent subagent work in parallel. Keep dependent tasks sequential, but do not serialize independent subagent tasks just to preserve a simpler history.
|
||||
|
||||
## Additional Gemini CLI tools
|
||||
|
||||
These tools are unique to Gemini CLI:
|
||||
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| `save_memory` (legacy) | Persist facts across sessions when `experimental.memoryV2 = false` |
|
||||
| `get_internal_docs` | Look up Gemini CLI's bundled documentation |
|
||||
| `ask_user` | Pose structured questions to the user (text / single-select / multi-select) |
|
||||
| `enter_plan_mode` / `exit_plan_mode` | Switch into and out of read-only plan mode |
|
||||
| `update_topic` | Update the current conversation's topic / strategic-intent metadata |
|
||||
| `complete_task` | Signal that a Gemini subagent has completed and return its result to the parent agent |
|
||||
| `tracker_create_task`, `tracker_update_task`, `tracker_get_task`, `tracker_list_tasks`, `tracker_add_dependency`, `tracker_visualize` | Rich task tracker with dependency and visualization support |
|
||||
| `read_mcp_resource`, `list_mcp_resources` | MCP resource access |
|
||||
28
skills/using-superpowers/references/pi-tools.md
Normal file
28
skills/using-superpowers/references/pi-tools.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Pi Tool Mapping
|
||||
|
||||
Skills speak in actions ("dispatch a subagent", "create a todo", "read a file"). On Pi these resolve to the tools below.
|
||||
|
||||
| Action skills request | Pi equivalent |
|
||||
| --- | --- |
|
||||
| Invoke a skill | Pi native skills: load the relevant `SKILL.md` with `read`, or let the human use `/skill:name` |
|
||||
| Read a file | `read` |
|
||||
| Create a file | `write` |
|
||||
| Edit a file | `edit` |
|
||||
| Run a shell command | `bash` |
|
||||
| Search file contents | `grep` when active; otherwise `bash` with `rg`/`grep` |
|
||||
| Find files by name | `find` or `bash` with shell globs |
|
||||
| List files and subdirectories | `ls` when active; otherwise `bash` with `ls` |
|
||||
| Dispatch a subagent (`Subagent (general-purpose):` template) | Use an installed subagent tool such as `subagent` from `pi-subagents` if available |
|
||||
| Task tracking ("create a todo", "mark complete") | Use an installed todo/task tool if available, otherwise track tasks in the plan or `TODO.md` |
|
||||
|
||||
## Skills
|
||||
|
||||
Pi discovers skills from configured skill directories and installed Pi packages. A Superpowers Pi package should expose `skills/` through its `pi.skills` manifest entry. Pi does not expose Claude Code's `Skill` tool, but the agent should still follow the Superpowers rule: when a skill applies, load and follow it before responding.
|
||||
|
||||
## Subagents
|
||||
|
||||
Pi core does not ship a standard subagent tool. The `pi-subagents` package is a strong optional companion and provides a `subagent` tool with single-agent, chain, parallel, async, forked-context, and resume/status workflows. If no subagent tool is available, do not fabricate `Task` calls; execute sequentially in the current session or explain that the optional subagent capability is not installed.
|
||||
|
||||
## Task lists
|
||||
|
||||
Pi core does not ship a standard task-list tool. If a todo/task extension is installed, use its documented tool. Otherwise use Superpowers plan files, checklists in Markdown, or a repo-local `TODO.md` for task tracking. Older Superpowers docs may refer to `TodoWrite`; treat that as the task-tracking action above.
|
||||
@@ -5,8 +5,6 @@ description: Use when you have a spec or requirements for a multi-step task, bef
|
||||
|
||||
# Writing Plans
|
||||
|
||||
**IMPORTANT:** Invoke this skill directly — do NOT use EnterPlanMode or platform plan mode. This skill has its own workflow and approval checkpoint (execution handoff). Layering plan mode on top is redundant and restrictive.
|
||||
|
||||
## Overview
|
||||
|
||||
Write comprehensive implementation plans assuming the engineer has zero context for our codebase and questionable taste. Document everything they need to know: which files to touch for each task, code, testing, docs they might need to check, how to test it. Give them the whole plan as bite-sized tasks. DRY. YAGNI. TDD. Frequent commits.
|
||||
@@ -15,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)
|
||||
@@ -51,7 +49,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
||||
```markdown
|
||||
# [Feature Name] Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
> **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:** [One sentence describing what this builds]
|
||||
|
||||
@@ -64,7 +62,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
||||
|
||||
## Task Structure
|
||||
|
||||
```markdown
|
||||
````markdown
|
||||
### Task N: [Component Name]
|
||||
|
||||
**Files:**
|
||||
@@ -103,47 +101,52 @@ Expected: PASS
|
||||
git add tests/path/test.py src/path/file.py
|
||||
git commit -m "feat: add specific feature"
|
||||
```
|
||||
```
|
||||
````
|
||||
|
||||
## No Placeholders
|
||||
|
||||
Every step must contain the actual content an engineer needs. These are **plan failures** — never write them:
|
||||
- "TBD", "TODO", "implement later", "fill in details"
|
||||
- "Add appropriate error handling" / "add validation" / "handle edge cases"
|
||||
- "Write tests for the above" (without actual test code)
|
||||
- "Similar to Task N" (repeat the code — the engineer may be reading tasks out of order)
|
||||
- Steps that describe what to do without showing how (code blocks required for code steps)
|
||||
- References to types, functions, or methods not defined in any task
|
||||
|
||||
## Remember
|
||||
- Exact file paths always
|
||||
- Complete code in plan (not "add validation")
|
||||
- Complete code in every step — if a step changes code, show the code
|
||||
- Exact commands with expected output
|
||||
- Reference relevant skills with @ syntax
|
||||
- DRY, YAGNI, TDD, frequent commits
|
||||
|
||||
## Plan Review Loop
|
||||
## Self-Review
|
||||
|
||||
After completing each chunk of the plan:
|
||||
After writing the complete plan, look at the spec with fresh eyes and check the plan against it. This is a checklist you run yourself — not a subagent dispatch.
|
||||
|
||||
1. Dispatch plan-document-reviewer subagent (see plan-document-reviewer-prompt.md) for the current chunk
|
||||
- Provide: chunk content, path to spec document
|
||||
2. If ❌ Issues Found:
|
||||
- Fix the issues in the chunk
|
||||
- Re-dispatch reviewer for that chunk
|
||||
- Repeat until ✅ Approved
|
||||
3. If ✅ Approved: proceed to next chunk (or execution handoff if last chunk)
|
||||
**1. Spec coverage:** Skim each section/requirement in the spec. Can you point to a task that implements it? List any gaps.
|
||||
|
||||
**Chunk boundaries:** Use `## Chunk N: <name>` headings to delimit chunks. Each chunk should be ≤1000 lines and logically self-contained.
|
||||
**2. Placeholder scan:** Search your plan for red flags — any of the patterns from the "No Placeholders" section above. Fix them.
|
||||
|
||||
**Review loop guidance:**
|
||||
- Same agent that wrote the plan fixes it (preserves context)
|
||||
- If loop exceeds 5 iterations, surface to human for guidance
|
||||
- Reviewers are advisory - explain disagreements if you believe feedback is incorrect
|
||||
**3. Type consistency:** Do the types, method signatures, and property names you used in later tasks match what you defined in earlier tasks? A function called `clearLayers()` in Task 3 but `clearFullLayers()` in Task 7 is a bug.
|
||||
|
||||
If you find issues, fix them inline. No need to re-review — just fix and move on. If you find a spec requirement with no task, add the task.
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
After saving the plan:
|
||||
After saving the plan, offer execution choice:
|
||||
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Ready to execute?"**
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Two execution options:**
|
||||
|
||||
**Execution path depends on harness capabilities:**
|
||||
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**If harness has subagents (Claude Code, etc.):**
|
||||
- **REQUIRED:** Use superpowers:subagent-driven-development
|
||||
- Do NOT offer a choice - subagent-driven is the standard approach
|
||||
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
|
||||
|
||||
**Which approach?"**
|
||||
|
||||
**If Subagent-Driven chosen:**
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:subagent-driven-development
|
||||
- Fresh subagent per task + two-stage review
|
||||
|
||||
**If harness does NOT have subagents:**
|
||||
- Execute plan in current session using superpowers:executing-plans
|
||||
**If Inline Execution chosen:**
|
||||
- **REQUIRED SUB-SKILL:** Use superpowers:executing-plans
|
||||
- Batch execution with checkpoints for review
|
||||
|
||||
@@ -2,17 +2,17 @@
|
||||
|
||||
Use this template when dispatching a plan document reviewer subagent.
|
||||
|
||||
**Purpose:** Verify the plan chunk is complete, matches the spec, and has proper task decomposition.
|
||||
**Purpose:** Verify the plan is complete, matches the spec, and has proper task decomposition.
|
||||
|
||||
**Dispatch after:** Each plan chunk is written
|
||||
**Dispatch after:** The complete plan is written.
|
||||
|
||||
```
|
||||
Task tool (general-purpose):
|
||||
description: "Review plan chunk N"
|
||||
Subagent (general-purpose):
|
||||
description: "Review plan document"
|
||||
prompt: |
|
||||
You are a plan document reviewer. Verify this plan chunk is complete and ready for implementation.
|
||||
You are a plan document reviewer. Verify this plan is complete and ready for implementation.
|
||||
|
||||
**Plan chunk to review:** [PLAN_FILE_PATH] - Chunk N only
|
||||
**Plan to review:** [PLAN_FILE_PATH]
|
||||
**Spec for reference:** [SPEC_FILE_PATH]
|
||||
|
||||
## What to Check
|
||||
@@ -20,33 +20,30 @@ Task tool (general-purpose):
|
||||
| Category | What to Look For |
|
||||
|----------|------------------|
|
||||
| Completeness | TODOs, placeholders, incomplete tasks, missing steps |
|
||||
| Spec Alignment | Chunk covers relevant spec requirements, no scope creep |
|
||||
| Task Decomposition | Tasks atomic, clear boundaries, steps actionable |
|
||||
| File Structure | Files have clear single responsibilities, split by responsibility not layer |
|
||||
| File Size | Would any new or modified file likely grow large enough to be hard to reason about as a whole? |
|
||||
| Task Syntax | Checkbox syntax (`- [ ]`) on steps for tracking |
|
||||
| Chunk Size | Each chunk under 1000 lines |
|
||||
| Spec Alignment | Plan covers spec requirements, no major scope creep |
|
||||
| Task Decomposition | Tasks have clear boundaries, steps are actionable |
|
||||
| Buildability | Could an engineer follow this plan without getting stuck? |
|
||||
|
||||
## CRITICAL
|
||||
## Calibration
|
||||
|
||||
Look especially hard for:
|
||||
- Any TODO markers or placeholder text
|
||||
- Steps that say "similar to X" without actual content
|
||||
- Incomplete task definitions
|
||||
- Missing verification steps or expected outputs
|
||||
- Files planned to hold multiple responsibilities or likely to grow unwieldy
|
||||
**Only flag issues that would cause real problems during implementation.**
|
||||
An implementer building the wrong thing or getting stuck is an issue.
|
||||
Minor wording, stylistic preferences, and "nice to have" suggestions are not.
|
||||
|
||||
Approve unless there are serious gaps — missing requirements from the spec,
|
||||
contradictory steps, placeholder content, or tasks so vague they can't be acted on.
|
||||
|
||||
## Output Format
|
||||
|
||||
## Plan Review - Chunk N
|
||||
## Plan Review
|
||||
|
||||
**Status:** Approved | Issues Found
|
||||
|
||||
**Issues (if any):**
|
||||
- [Task X, Step Y]: [specific issue] - [why it matters]
|
||||
- [Task X, Step Y]: [specific issue] - [why it matters for implementation]
|
||||
|
||||
**Recommendations (advisory):**
|
||||
- [suggestions that don't block approval]
|
||||
**Recommendations (advisory, do not block approval):**
|
||||
- [suggestions for improvement]
|
||||
```
|
||||
|
||||
**Reviewer returns:** Status, Issues (if any), Recommendations
|
||||
|
||||
@@ -9,7 +9,7 @@ description: Use when creating new skills, editing existing skills, or verifying
|
||||
|
||||
**Writing skills IS Test-Driven Development applied to process documentation.**
|
||||
|
||||
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.agents/skills/` for Codex)**
|
||||
**Personal skills live in your runtime's skills directory** — see [claude-code-tools.md](../using-superpowers/references/claude-code-tools.md), [codex-tools.md](../using-superpowers/references/codex-tools.md), [copilot-tools.md](../using-superpowers/references/copilot-tools.md), or [gemini-tools.md](../using-superpowers/references/gemini-tools.md) for the path on your runtime. Codex, Copilot CLI, and Gemini CLI all also recognize `~/.agents/skills/` as a cross-runtime alias.
|
||||
|
||||
You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).
|
||||
|
||||
@@ -21,7 +21,7 @@ You write test cases (pressure scenarios with subagents), watch them fail (basel
|
||||
|
||||
## What is a Skill?
|
||||
|
||||
A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future Claude instances find and apply effective approaches.
|
||||
A **skill** is a reference guide for proven techniques, patterns, or tools. Skills help future agents find and apply effective approaches.
|
||||
|
||||
**Skills are:** Reusable techniques, patterns, tools, reference guides
|
||||
|
||||
@@ -55,7 +55,7 @@ The entire skill creation process follows RED-GREEN-REFACTOR.
|
||||
**Don't create for:**
|
||||
- One-off solutions
|
||||
- Standard practices well-documented elsewhere
|
||||
- Project-specific conventions (put in CLAUDE.md)
|
||||
- Project-specific conventions (put in your instructions file)
|
||||
- Mechanical constraints (if it's enforceable with regex/validation, automate it—save documentation for judgment calls)
|
||||
|
||||
## Skill Types
|
||||
@@ -93,13 +93,13 @@ skills/
|
||||
## SKILL.md Structure
|
||||
|
||||
**Frontmatter (YAML):**
|
||||
- Only two fields supported: `name` and `description`
|
||||
- Two required fields: `name` and `description` (see [agentskills.io/specification](https://agentskills.io/specification) for all supported fields)
|
||||
- Max 1024 characters total
|
||||
- `name`: Use letters, numbers, and hyphens only (no parentheses, special chars)
|
||||
- `description`: Third-person, describes ONLY when to use (NOT what it does)
|
||||
- Start with "Use when..." to focus on triggering conditions
|
||||
- Include specific symptoms, situations, and contexts
|
||||
- **NEVER summarize the skill's process or workflow** (see CSO section for why)
|
||||
- **NEVER summarize the skill's process or workflow** (see SDO section for why)
|
||||
- Keep under 500 characters if possible
|
||||
|
||||
```markdown
|
||||
@@ -137,13 +137,13 @@ Concrete results
|
||||
```
|
||||
|
||||
|
||||
## Claude Search Optimization (CSO)
|
||||
## Skill Discovery Optimization (SDO)
|
||||
|
||||
**Critical for discovery:** Future Claude needs to FIND your skill
|
||||
**Critical for discovery:** Future agents need to FIND your skill
|
||||
|
||||
### 1. Rich Description Field
|
||||
|
||||
**Purpose:** Claude reads description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?"
|
||||
**Purpose:** Your agent reads the description to decide which skills to load for a given task. Make it answer: "Should I read this skill right now?"
|
||||
|
||||
**Format:** Start with "Use when..." to focus on triggering conditions
|
||||
|
||||
@@ -151,14 +151,14 @@ Concrete results
|
||||
|
||||
The description should ONLY describe triggering conditions. Do NOT summarize the skill's process or workflow in the description.
|
||||
|
||||
**Why this matters:** Testing revealed that when a description summarizes the skill's workflow, Claude may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused Claude to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality).
|
||||
**Why this matters:** Testing revealed that when a description summarizes the skill's workflow, an agent may follow the description instead of reading the full skill content. A description saying "code review between tasks" caused an agent to do ONE review, even though the skill's flowchart clearly showed TWO reviews (spec compliance then code quality).
|
||||
|
||||
When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), Claude correctly read the flowchart and followed the two-stage review process.
|
||||
When the description was changed to just "Use when executing implementation plans with independent tasks" (no workflow summary), the agent correctly read the flowchart and followed the two-stage review process.
|
||||
|
||||
**The trap:** Descriptions that summarize workflow create a shortcut Claude will take. The skill body becomes documentation Claude skips.
|
||||
**The trap:** Descriptions that summarize workflow create a shortcut agents will take. The skill body becomes documentation agents skip.
|
||||
|
||||
```yaml
|
||||
# ❌ BAD: Summarizes workflow - Claude may follow this instead of reading skill
|
||||
# ❌ BAD: Summarizes workflow - agents may follow this instead of reading skill
|
||||
description: Use when executing plans - dispatches subagent per task with code review between tasks
|
||||
|
||||
# ❌ BAD: Too much process detail
|
||||
@@ -198,7 +198,7 @@ description: Use when using React Router and handling authentication redirects
|
||||
|
||||
### 2. Keyword Coverage
|
||||
|
||||
Use words Claude would search for:
|
||||
Use words an agent would search for:
|
||||
- Error messages: "Hook timed out", "ENOTEMPTY", "race condition"
|
||||
- Symptoms: "flaky", "hanging", "zombie", "pollution"
|
||||
- Synonyms: "timeout/hang/freeze", "cleanup/teardown/afterEach"
|
||||
@@ -275,7 +275,7 @@ wc -w skills/path/SKILL.md
|
||||
- `creating-skills`, `testing-skills`, `debugging-with-logs`
|
||||
- Active, describes the action you're taking
|
||||
|
||||
### 4. Cross-Referencing Other Skills
|
||||
### 5. Cross-Referencing Other Skills
|
||||
|
||||
**When writing documentation that references other skills:**
|
||||
|
||||
@@ -313,7 +313,7 @@ digraph when_flowchart {
|
||||
- Linear instructions → Numbered lists
|
||||
- Labels without semantic meaning (step1, helper2)
|
||||
|
||||
See @graphviz-conventions.dot for graphviz style rules.
|
||||
See `graphviz-conventions.dot` in this directory for graphviz style rules.
|
||||
|
||||
**Visualizing for your human partner:** Use `render-graphs.js` in this directory to render a skill's flowcharts to SVG:
|
||||
```bash
|
||||
@@ -522,7 +522,7 @@ Make it easy for agents to self-check when rationalizing:
|
||||
**All of these mean: Delete code. Start over with TDD.**
|
||||
```
|
||||
|
||||
### Update CSO for Violation Symptoms
|
||||
### Update SDO for Violation Symptoms
|
||||
|
||||
Add to description: symptoms of when you're ABOUT to violate the rule:
|
||||
|
||||
@@ -553,7 +553,7 @@ Run same scenarios WITH skill. Agent should now comply.
|
||||
|
||||
Agent found new rationalization? Add explicit counter. Re-test until bulletproof.
|
||||
|
||||
**Testing methodology:** See @testing-skills-with-subagents.md for the complete testing methodology:
|
||||
**Testing methodology:** See [testing-skills-with-subagents.md](testing-skills-with-subagents.md) for the complete testing methodology:
|
||||
- How to write pressure scenarios
|
||||
- Pressure types (time, sunk cost, authority, exhaustion)
|
||||
- Plugging holes systematically
|
||||
@@ -595,7 +595,7 @@ Deploying untested skills = deploying untested code. It's a violation of quality
|
||||
|
||||
## Skill Creation Checklist (TDD Adapted)
|
||||
|
||||
**IMPORTANT: Use TodoWrite to create todos for EACH checklist item below.**
|
||||
**IMPORTANT: Create a todo for EACH checklist item below.**
|
||||
|
||||
**RED Phase - Write Failing Test:**
|
||||
- [ ] Create pressure scenarios (3+ combined pressures for discipline skills)
|
||||
@@ -604,7 +604,7 @@ Deploying untested skills = deploying untested code. It's a violation of quality
|
||||
|
||||
**GREEN Phase - Write Minimal Skill:**
|
||||
- [ ] Name uses only letters, numbers, hyphens (no parentheses/special chars)
|
||||
- [ ] YAML frontmatter with only name and description (max 1024 chars)
|
||||
- [ ] YAML frontmatter with required `name` and `description` fields (max 1024 chars; see [spec](https://agentskills.io/specification))
|
||||
- [ ] Description starts with "Use when..." and includes specific triggers/symptoms
|
||||
- [ ] Description written in third person
|
||||
- [ ] Keywords throughout for search (errors, symptoms, tools)
|
||||
@@ -634,9 +634,10 @@ Deploying untested skills = deploying untested code. It's a violation of quality
|
||||
|
||||
## Discovery Workflow
|
||||
|
||||
How future Claude finds your skill:
|
||||
How future agents find your skill:
|
||||
|
||||
1. **Encounters problem** ("tests are flaky")
|
||||
2. **Searches skills** (greps descriptions, browses categories)
|
||||
3. **Finds SKILL** (description matches)
|
||||
4. **Scans overview** (is this relevant?)
|
||||
5. **Reads patterns** (quick reference table)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user