📦 deps(superpowers): vendor snapshot
Trigger Superpowers Sync / Run main sync script (push) Successful in 1m15s Details

This commit is contained in:
ci-bot 2026-03-10 01:59:00 +00:00
parent 4624c4be23
commit a76b713a70
53 changed files with 4504 additions and 91 deletions

View File

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

View File

@ -1,7 +1,7 @@
{
"name": "superpowers",
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
"version": "4.3.1",
"version": "5.0.0",
"author": {
"name": "Jesse Vincent",
"email": "jesse@fsck.com"

View File

@ -2,3 +2,6 @@
.private-journal/
.claude/
.DS_Store
node_modules/
inspo
triage/

View File

@ -28,6 +28,15 @@ Thanks!
**Note:** Installation differs by platform. Claude Code or Cursor have built-in plugin marketplaces. Codex and OpenCode require manual setup.
### Claude Code Official Marketplace
Superpowers is available via the [official Claude plugin marketplace](https://claude.com/plugins/superpowers)
Install the plugin from Claude marketplace:
```bash
/plugin install superpowers@claude-plugins-official
```
### Claude Code (via Plugin Marketplace)

View File

@ -1,5 +1,99 @@
# Superpowers Release Notes
## v5.0.0 (2026-03-09)
### Breaking Changes
**Specs and plans directory restructured**
- 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
**Subagent-driven development mandatory on capable harnesses**
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.
**Executing-plans no longer batches**
Removed the "execute 3 tasks then stop for review" pattern. Plans now execute continuously, stopping only for blockers.
**Slash commands deprecated**
`/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 brainstorming companion**
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.
- `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/`
**Document review system**
Automated review loops for spec and plan documents using subagent dispatch:
- `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/`
**Architecture guidance across the skill pipeline**
Design-for-isolation and file-size-awareness guidance added to brainstorming, writing-plans, and subagent-driven-development:
- **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
**Subagent-driven development improvements**
- **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 hierarchy**
Added explicit priority ordering to using-superpowers:
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
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

View File

@ -1,6 +1,6 @@
# Source
- Repo: https://github.com/obra/superpowers
- Ref: e4a2375cb705ca5800f0833528ce36a3faf9017a
- Snapshot: 2026-02-28
- Ref: 33e55e60b2efcb69509bc233dfc128112012b2c8
- Snapshot: 2026-03-10
- Notes: vendored into playbook branch thirdparty/skill

View File

@ -1,6 +1,5 @@
---
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
description: "Deprecated - use the superpowers:brainstorming skill instead"
---
Invoke the superpowers:brainstorming skill and follow it exactly as presented to you
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers brainstorming" skill instead.

View File

@ -1,6 +1,5 @@
---
description: Execute plan in batches with review checkpoints
disable-model-invocation: true
description: "Deprecated - use the superpowers:executing-plans skill instead"
---
Invoke the superpowers:executing-plans skill and follow it exactly as presented to you
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers executing-plans" skill instead.

View File

@ -1,6 +1,5 @@
---
description: Create detailed implementation plan with bite-sized tasks
disable-model-invocation: true
description: "Deprecated - use the superpowers:writing-plans skill instead"
---
Invoke the superpowers:writing-plans skill and follow it exactly as presented to you
Tell your human partner that this command is deprecated and will be removed in the next major release. They should ask you to use the "superpowers writing-plans" skill instead.

View File

@ -32,6 +32,12 @@ Fetch and follow instructions from https://raw.githubusercontent.com/obra/superp
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):

View File

@ -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.

View File

@ -0,0 +1,571 @@
# Visual Brainstorming Companion Implementation Plan
> **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.
**Architecture:** Claude writes HTML to a temp file. A local Node.js server watches that file and serves it with an auto-injected helper library. User interactions flow via WebSocket to server stdout, which Claude sees in background task output.
**Tech Stack:** Node.js, Express, ws (WebSocket), chokidar (file watching)
---
## Task 1: Create the Server Foundation
**Files:**
- Create: `lib/brainstorm-server/index.js`
- Create: `lib/brainstorm-server/package.json`
**Step 1: Create package.json**
```json
{
"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"
}
}
```
**Step 2: Create minimal server that starts**
```javascript
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 || 3333;
const SCREEN_FILE = process.env.BRAINSTORM_SCREEN || '/tmp/brainstorm/screen.html';
const SCREEN_DIR = path.dirname(SCREEN_FILE);
// Ensure screen directory exists
if (!fs.existsSync(SCREEN_DIR)) {
fs.mkdirSync(SCREEN_DIR, { recursive: true });
}
// Create default screen if none exists
if (!fs.existsSync(SCREEN_FILE)) {
fs.writeFileSync(SCREEN_FILE, `<!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 });
// Track connected browsers for reload notifications
const clients = new Set();
wss.on('connection', (ws) => {
clients.add(ws);
ws.on('close', () => clients.delete(ws));
ws.on('message', (data) => {
// User interaction event - write to stdout for Claude
const event = JSON.parse(data.toString());
console.log(JSON.stringify({ type: 'user-event', ...event }));
});
});
// Serve current screen with helper.js injected
app.get('/', (req, res) => {
let html = fs.readFileSync(SCREEN_FILE, 'utf-8');
// Inject helper script before </body>
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
const injection = `<script>\n${helperScript}\n</script>`;
if (html.includes('</body>')) {
html = html.replace('</body>', `${injection}\n</body>`);
} else {
html += injection;
}
res.type('html').send(html);
});
// Watch for screen file changes
chokidar.watch(SCREEN_FILE).on('change', () => {
console.log(JSON.stringify({ type: 'screen-updated', file: SCREEN_FILE }));
// Notify all browsers to reload
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}` }));
});
```
**Step 3: Run npm install**
Run: `cd lib/brainstorm-server && npm install`
Expected: Dependencies installed
**Step 4: Test server starts**
Run: `cd lib/brainstorm-server && timeout 3 node index.js || true`
Expected: See JSON with `server-started` and port info
**Step 5: Commit**
```bash
git add lib/brainstorm-server/
git commit -m "feat: add brainstorm server foundation"
```
---
## Task 2: Create the Helper Library
**Files:**
- Create: `lib/brainstorm-server/helper.js`
**Step 1: Create helper.js with event auto-capture**
```javascript
(function() {
const WS_URL = 'ws://' + window.location.host;
let ws = null;
let eventQueue = [];
function connect() {
ws = new WebSocket(WS_URL);
ws.onopen = () => {
// Send any queued events
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 = () => {
// Reconnect after 1 second
setTimeout(connect, 1000);
};
}
function send(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;
e.preventDefault();
send({
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; });
send({
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(() => {
send({
type: 'input',
name: target.name || null,
id: target.id || null,
value: target.value,
inputType: target.type || target.tagName.toLowerCase()
});
}, 500); // 500ms debounce
});
// Expose for explicit use if needed
window.brainstorm = {
send: send,
choice: (value, metadata = {}) => send({ type: 'choice', value, ...metadata })
};
connect();
})();
```
**Step 2: Verify helper.js is syntactically valid**
Run: `node -c lib/brainstorm-server/helper.js`
Expected: No syntax errors
**Step 3: Commit**
```bash
git add lib/brainstorm-server/helper.js
git commit -m "feat: add browser helper library for event capture"
```
---
## Task 3: Write Tests for the Server
**Files:**
- Create: `tests/brainstorm-server/server.test.js`
- Create: `tests/brainstorm-server/package.json`
**Step 1: Create test package.json**
```json
{
"name": "brainstorm-server-tests",
"version": "1.0.0",
"scripts": {
"test": "node server.test.js"
}
}
```
**Step 2: Write server tests**
```javascript
const { spawn } = require('child_process');
const http = require('http');
const WebSocket = require('ws');
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const SERVER_PATH = path.join(__dirname, '../../lib/brainstorm-server/index.js');
const TEST_PORT = 3334;
const TEST_SCREEN = '/tmp/brainstorm-test/screen.html';
// Clean up test directory
function cleanup() {
if (fs.existsSync(path.dirname(TEST_SCREEN))) {
fs.rmSync(path.dirname(TEST_SCREEN), { recursive: true });
}
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function fetch(url) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve({ status: res.statusCode, body: data }));
}).on('error', reject);
});
}
async function runTests() {
cleanup();
// Start server
const server = spawn('node', [SERVER_PATH], {
env: { ...process.env, BRAINSTORM_PORT: TEST_PORT, BRAINSTORM_SCREEN: TEST_SCREEN }
});
let stdout = '';
server.stdout.on('data', (data) => { stdout += data.toString(); });
server.stderr.on('data', (data) => { console.error('Server stderr:', data.toString()); });
await sleep(1000); // Wait for server to start
try {
// Test 1: Server starts and outputs JSON
console.log('Test 1: Server startup message');
assert(stdout.includes('server-started'), 'Should output server-started');
assert(stdout.includes(TEST_PORT.toString()), 'Should include port');
console.log(' PASS');
// Test 2: GET / returns HTML with helper injected
console.log('Test 2: Serves HTML with helper injected');
const res = await fetch(`http://localhost:${TEST_PORT}/`);
assert.strictEqual(res.status, 200);
assert(res.body.includes('brainstorm'), 'Should include brainstorm content');
assert(res.body.includes('WebSocket'), 'Should have helper.js injected');
console.log(' PASS');
// Test 3: WebSocket connection and event relay
console.log('Test 3: WebSocket relays events to stdout');
stdout = ''; // Reset stdout capture
const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
await new Promise(resolve => ws.on('open', resolve));
ws.send(JSON.stringify({ type: 'click', text: 'Test Button' }));
await sleep(100);
assert(stdout.includes('user-event'), 'Should relay user events');
assert(stdout.includes('Test Button'), 'Should include event data');
ws.close();
console.log(' PASS');
// Test 4: File change triggers reload notification
console.log('Test 4: File change notifies browsers');
const ws2 = new WebSocket(`ws://localhost:${TEST_PORT}`);
await new Promise(resolve => ws2.on('open', resolve));
let gotReload = false;
ws2.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === 'reload') gotReload = true;
});
// Modify the screen file
fs.writeFileSync(TEST_SCREEN, '<html><body>Updated</body></html>');
await sleep(500);
assert(gotReload, 'Should send reload message on file change');
ws2.close();
console.log(' PASS');
console.log('\nAll tests passed!');
} finally {
server.kill();
cleanup();
}
}
runTests().catch(err => {
console.error('Test failed:', err);
process.exit(1);
});
```
**Step 3: Run tests**
Run: `cd tests/brainstorm-server && npm install ws && node server.test.js`
Expected: All tests pass
**Step 4: Commit**
```bash
git add tests/brainstorm-server/
git commit -m "test: add brainstorm server integration tests"
```
---
## Task 4: Add Visual Companion to Brainstorming Skill
**Files:**
- Modify: `skills/brainstorming/SKILL.md`
- Create: `skills/brainstorming/visual-companion.md` (supporting doc)
**Step 1: Create the supporting documentation**
Create `skills/brainstorming/visual-companion.md`:
```markdown
# Visual Companion Reference
## Starting the Server
Run as a background job:
```bash
node ${PLUGIN_ROOT}/lib/brainstorm-server/index.js
```
Tell the user: "I've started a visual companion at http://localhost:3333 - open it in a browser."
## Pushing Screens
Write HTML to `/tmp/brainstorm/screen.html`. The server watches this file and auto-refreshes the browser.
## Reading User Responses
Check the background task output for JSON events:
```json
{"type":"user-event","type":"click","text":"Option A","choice":"optionA","timestamp":1234567890}
{"type":"user-event","type":"submit","data":{"notes":"My feedback"},"timestamp":1234567891}
```
Event types:
- **click**: User clicked button or `data-choice` element
- **submit**: User submitted form (includes all form data)
- **input**: User typed in field (debounced 500ms)
## HTML Patterns
### Choice Cards
```html
<div class="options">
<button data-choice="optionA">
<h3>Option A</h3>
<p>Description</p>
</button>
<button data-choice="optionB">
<h3>Option B</h3>
<p>Description</p>
</button>
</div>
```
### Interactive Mockup
```html
<div class="mockup">
<header data-choice="header">App Header</header>
<nav data-choice="nav">Navigation</nav>
<main data-choice="main">Content</main>
</div>
```
### Form with Notes
```html
<form>
<label>Priority: <input type="range" name="priority" min="1" max="5"></label>
<textarea name="notes" placeholder="Additional thoughts..."></textarea>
<button type="submit">Submit</button>
</form>
```
### Explicit JavaScript
```html
<button onclick="brainstorm.choice('custom', {extra: 'data'})">Custom</button>
```
```
**Step 2: Add visual companion section to brainstorming skill**
Add after "Key Principles" in `skills/brainstorming/SKILL.md`:
```markdown
## Visual Companion (Optional)
When brainstorming involves visual elements - UI mockups, wireframes, interactive prototypes - use the browser-based visual companion.
**When to use:**
- Presenting UI/UX options that benefit from visual comparison
- Showing wireframes or layout options
- Gathering structured feedback (ratings, forms)
- Prototyping click interactions
**How it works:**
1. Start the server as a background job
2. Tell user to open http://localhost:3333
3. Write HTML to `/tmp/brainstorm/screen.html` (auto-refreshes)
4. Check background task output for user interactions
The terminal remains the primary conversation interface. The browser is a visual aid.
**Reference:** See `visual-companion.md` in this skill directory for HTML patterns and API details.
```
**Step 3: Verify the edits**
Run: `grep -A5 "Visual Companion" skills/brainstorming/SKILL.md`
Expected: Shows the new section
**Step 4: Commit**
```bash
git add skills/brainstorming/
git commit -m "feat: add visual companion to brainstorming skill"
```
---
## Task 5: Add Server to Plugin Ignore (Optional Cleanup)
**Files:**
- Check if `.gitignore` needs node_modules exclusion for lib/brainstorm-server
**Step 1: Check current gitignore**
Run: `cat .gitignore 2>/dev/null || echo "No .gitignore"`
**Step 2: Add node_modules if needed**
If not already present, add:
```
lib/brainstorm-server/node_modules/
```
**Step 3: Commit if changed**
```bash
git add .gitignore
git commit -m "chore: ignore brainstorm-server node_modules"
```
---
## Summary
After completing all tasks:
1. **Server** at `lib/brainstorm-server/` - Node.js server that watches HTML file and relays events
2. **Helper library** auto-injected - captures clicks, forms, inputs
3. **Tests** at `tests/brainstorm-server/` - verifies server behavior
4. **Brainstorming skill** updated with visual companion section and `visual-companion.md` reference doc
**To use:**
1. Start server as background job: `node lib/brainstorm-server/index.js &`
2. Tell user to open `http://localhost:3333`
3. Write HTML to `/tmp/brainstorm/screen.html`
4. Check task output for user events

View File

@ -0,0 +1,301 @@
# Document Review System Implementation 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.
**Architecture:** Create reviewer prompt templates in each skill directory. Modify skill files to add review loops after document creation. Use Task tool with general-purpose subagent for reviewer dispatch.
**Tech Stack:** Markdown skill files, subagent dispatch via Task tool
**Spec:** docs/superpowers/specs/2026-01-22-document-review-system-design.md
---
## Chunk 1: Spec Document Reviewer
This chunk adds the spec document reviewer to the brainstorming skill.
### Task 1: Create Spec Document Reviewer Prompt Template
**Files:**
- Create: `skills/brainstorming/spec-document-reviewer-prompt.md`
- [ ] **Step 1:** Create the reviewer prompt template file
```markdown
# Spec Document Reviewer Prompt Template
Use this template when dispatching a spec document reviewer subagent.
**Purpose:** Verify the spec is complete, consistent, and ready for implementation planning.
**Dispatch after:** Spec document is written to docs/superpowers/specs/
```
Task tool (general-purpose):
description: "Review spec document"
prompt: |
You are a spec document reviewer. Verify this spec is complete and ready for planning.
**Spec to review:** [SPEC_FILE_PATH]
## What to Check
| 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 |
## CRITICAL
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
## Output Format
## Spec Review
**Status:** ✅ Approved | ❌ Issues Found
**Issues (if any):**
- [Section X]: [specific issue] - [why it matters]
**Recommendations (advisory):**
- [suggestions that don't block approval]
```
**Reviewer returns:** Status, Issues (if any), Recommendations
```
- [ ] **Step 2:** Verify the file was created correctly
Run: `cat skills/brainstorming/spec-document-reviewer-prompt.md | head -20`
Expected: Shows the header and purpose section
- [ ] **Step 3:** Commit
```bash
git add skills/brainstorming/spec-document-reviewer-prompt.md
git commit -m "feat: add spec document reviewer prompt template"
```
---
### Task 2: Add Review Loop to Brainstorming Skill
**Files:**
- Modify: `skills/brainstorming/SKILL.md`
- [ ] **Step 1:** Read the current brainstorming skill
Run: `cat skills/brainstorming/SKILL.md`
- [ ] **Step 2:** Add the review loop section after "After the Design"
Find the "After the Design" section and add a new "Spec Review Loop" section after documentation but before implementation:
```markdown
**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 the issues in the spec document
- Re-dispatch reviewer
- Repeat until ✅ Approved
3. If ✅ Approved: proceed to implementation setup
**Review loop guidance:**
- Same agent that wrote the spec 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
```
- [ ] **Step 3:** Verify the changes
Run: `grep -A 15 "Spec Review Loop" skills/brainstorming/SKILL.md`
Expected: Shows the new review loop section
- [ ] **Step 4:** Commit
```bash
git add skills/brainstorming/SKILL.md
git commit -m "feat: add spec review loop to brainstorming skill"
```
---
## Chunk 2: Plan Document Reviewer
This chunk adds the plan document reviewer to the writing-plans skill.
### Task 3: Create Plan Document Reviewer Prompt Template
**Files:**
- Create: `skills/writing-plans/plan-document-reviewer-prompt.md`
- [ ] **Step 1:** Create the reviewer prompt template file
```markdown
# Plan Document Reviewer Prompt Template
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.
**Dispatch after:** Each plan chunk is written
```
Task tool (general-purpose):
description: "Review plan chunk N"
prompt: |
You are a plan document reviewer. Verify this plan chunk is complete and ready for implementation.
**Plan chunk to review:** [PLAN_FILE_PATH] - Chunk N only
**Spec for reference:** [SPEC_FILE_PATH]
## What to Check
| 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 |
| Task Syntax | Checkbox syntax (`- [ ]`) on tasks and steps |
| Chunk Size | Each chunk under 1000 lines |
## CRITICAL
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
## Output Format
## Plan Review - Chunk N
**Status:** ✅ Approved | ❌ Issues Found
**Issues (if any):**
- [Task X, Step Y]: [specific issue] - [why it matters]
**Recommendations (advisory):**
- [suggestions that don't block approval]
```
**Reviewer returns:** Status, Issues (if any), Recommendations
```
- [ ] **Step 2:** Verify the file was created
Run: `cat skills/writing-plans/plan-document-reviewer-prompt.md | head -20`
Expected: Shows the header and purpose section
- [ ] **Step 3:** Commit
```bash
git add skills/writing-plans/plan-document-reviewer-prompt.md
git commit -m "feat: add plan document reviewer prompt template"
```
---
### Task 4: Add Review Loop to Writing-Plans Skill
**Files:**
- Modify: `skills/writing-plans/SKILL.md`
- [ ] **Step 1:** Read current skill file
Run: `cat skills/writing-plans/SKILL.md`
- [ ] **Step 2:** Add chunk-by-chunk review section
Add before the "Execution Handoff" section:
```markdown
## Plan Review Loop
After completing each chunk of the plan:
1. Dispatch plan-document-reviewer subagent 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)
**Chunk boundaries:** Use `## Chunk N: <name>` headings to delimit chunks. Each chunk should be ≤1000 lines and logically self-contained.
```
- [ ] **Step 3:** Update task syntax examples to use checkboxes
Change the Task Structure section to show checkbox syntax:
```markdown
### Task N: [Component Name]
- [ ] **Step 1:** Write the failing test
- File: `tests/path/test.py`
...
```
- [ ] **Step 4:** Verify the review loop section was added
Run: `grep -A 15 "Plan Review Loop" skills/writing-plans/SKILL.md`
Expected: Shows the new review loop section
- [ ] **Step 5:** Verify the task syntax examples were updated
Run: `grep -A 5 "Task N:" skills/writing-plans/SKILL.md`
Expected: Shows checkbox syntax `### Task N:`
- [ ] **Step 6:** Commit
```bash
git add skills/writing-plans/SKILL.md
git commit -m "feat: add plan review loop and checkbox syntax to writing-plans skill"
```
---
## Chunk 3: Update Plan Document Header
This chunk updates the plan document header template to reference the new checkbox syntax requirements.
### Task 5: Update Plan Header Template in Writing-Plans Skill
**Files:**
- Modify: `skills/writing-plans/SKILL.md`
- [ ] **Step 1:** Read current plan header template
Run: `grep -A 20 "Plan Document Header" skills/writing-plans/SKILL.md`
- [ ] **Step 2:** Update the header template to reference checkbox syntax
The plan header should note that tasks and steps use checkbox syntax. Update the header comment:
```markdown
> **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 agentic workers:" skills/writing-plans/SKILL.md`
Expected: Shows updated header with checkbox syntax mention
- [ ] **Step 4:** Commit
```bash
git add skills/writing-plans/SKILL.md
git commit -m "docs: update plan header to reference checkbox syntax"
```

View File

@ -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
```

View File

@ -0,0 +1,136 @@
# Document Review System Design
## Overview
Add two new review stages to the superpowers workflow:
1. **Spec Document Review** - After brainstorming, before writing-plans
2. **Plan Document Review** - After writing-plans, before implementation
Both follow the iterative loop pattern used by implementation reviews.
## Spec Document Reviewer
**Purpose:** Verify the spec is complete, consistent, and ready for implementation planning.
**Location:** `skills/brainstorming/spec-document-reviewer-prompt.md`
**What it checks for:**
| 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 |
**Output format:**
```
## Spec Review
**Status:** Approved | Issues Found
**Issues (if any):**
- [Section X]: [issue] - [why it matters]
**Recommendations (advisory):**
- [suggestions that don't block approval]
```
**Review loop:** Issues found -> brainstorming agent fixes -> re-review -> repeat until approved.
**Dispatch mechanism:** Use the Task tool with `subagent_type: general-purpose`. The reviewer prompt template provides the full prompt. The brainstorming skill's controller dispatches the reviewer.
## Plan Document Reviewer
**Purpose:** Verify the plan is complete, matches the spec, and has proper task decomposition.
**Location:** `skills/writing-plans/plan-document-reviewer-prompt.md`
**What it checks for:**
| Category | What to Look For |
|----------|------------------|
| Completeness | TODOs, placeholders, incomplete tasks |
| Spec Alignment | Plan covers spec requirements, no scope creep |
| Task Decomposition | Tasks atomic, clear boundaries |
| Task Syntax | Checkbox syntax on tasks and steps |
| Chunk Size | Each chunk under 1000 lines |
**Chunk definition:** A chunk is a logical grouping of tasks within the plan document, delimited by `## Chunk N: <name>` headings. The writing-plans skill creates these boundaries based on logical phases (e.g., "Foundation", "Core Features", "Integration"). Each chunk should be self-contained enough to review independently.
**Spec alignment verification:** The reviewer receives both:
1. The plan document (or current chunk)
2. The path to the spec document for reference
The reviewer reads both and compares requirements coverage.
**Output format:** Same as spec reviewer, but scoped to the current chunk.
**Review process (chunk-by-chunk):**
1. Writing-plans creates chunk N
2. Controller dispatches plan-document-reviewer with chunk N content and spec path
3. Reviewer reads chunk and spec, returns verdict
4. If issues: writing-plans agent fixes chunk N, goto step 2
5. If approved: proceed to chunk N+1
6. Repeat until all chunks approved
**Dispatch mechanism:** Same as spec reviewer - Task tool with `subagent_type: general-purpose`.
## Updated Workflow
```
brainstorming -> spec -> SPEC REVIEW LOOP -> writing-plans -> plan -> PLAN REVIEW LOOP -> implementation
```
**Spec Review Loop:**
1. Spec complete
2. Dispatch reviewer
3. If issues: fix -> goto 2
4. If approved: proceed
**Plan Review Loop:**
1. Chunk N complete
2. Dispatch reviewer for chunk N
3. If issues: fix -> goto 2
4. If approved: next chunk or implementation
## Markdown Task Syntax
Tasks and steps use checkbox syntax:
```markdown
- [ ] ### Task 1: Name
- [ ] **Step 1:** Description
- File: path
- Command: cmd
```
## Error Handling
**Review loop termination:**
- No hard iteration limit - loops continue until reviewer approves
- If loop exceeds 5 iterations, the controller should surface this to the human for guidance
- The human can choose to: continue iterating, approve with known issues, or abort
**Disagreement handling:**
- Reviewers are advisory - they flag issues but don't block
- If the agent believes reviewer feedback is incorrect, it should explain why in its fix
- If disagreement persists after 3 iterations on the same issue, surface to human
**Malformed reviewer output:**
- Controller should validate reviewer output has required fields (Status, Issues if applicable)
- If malformed, re-dispatch reviewer with a note about expected format
- After 2 malformed responses, surface to human
## Files to Change
**New files:**
- `skills/brainstorming/spec-document-reviewer-prompt.md`
- `skills/writing-plans/plan-document-reviewer-prompt.md`
**Modified files:**
- `skills/brainstorming/SKILL.md` - add review loop after spec written
- `skills/writing-plans/SKILL.md` - add chunk-by-chunk review loop, update task syntax examples

View File

@ -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.

View File

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html>
<head>
<title>Superpowers Brainstorming</title>
<style>
/*
* BRAINSTORM COMPANION FRAME TEMPLATE
*
* This template provides a consistent frame with:
* - OS-aware light/dark theming
* - Fixed header and selection indicator bar
* - Scrollable main content area
* - CSS helpers for common UI patterns
*
* Content is injected via placeholder comment in #claude-content.
*/
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; overflow: hidden; }
/* ===== THEME VARIABLES ===== */
:root {
--bg-primary: #f5f5f7;
--bg-secondary: #ffffff;
--bg-tertiary: #e5e5e7;
--border: #d1d1d6;
--text-primary: #1d1d1f;
--text-secondary: #86868b;
--text-tertiary: #aeaeb2;
--accent: #0071e3;
--accent-hover: #0077ed;
--success: #34c759;
--warning: #ff9f0a;
--error: #ff3b30;
--selected-bg: #e8f4fd;
--selected-border: #0071e3;
}
@media (prefers-color-scheme: dark) {
:root {
--bg-primary: #1d1d1f;
--bg-secondary: #2d2d2f;
--bg-tertiary: #3d3d3f;
--border: #424245;
--text-primary: #f5f5f7;
--text-secondary: #86868b;
--text-tertiary: #636366;
--accent: #0a84ff;
--accent-hover: #409cff;
--selected-bg: rgba(10, 132, 255, 0.15);
--selected-border: #0a84ff;
}
}
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
display: flex;
flex-direction: column;
line-height: 1.5;
}
/* ===== FRAME STRUCTURE ===== */
.header {
background: var(--bg-secondary);
padding: 0.5rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.header h1 { font-size: 0.85rem; font-weight: 500; color: var(--text-secondary); }
.header .status { font-size: 0.7rem; color: var(--success); display: flex; align-items: center; gap: 0.4rem; }
.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%; }
.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;
}
/* ===== TYPOGRAPHY ===== */
h2 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.5rem; }
h3 { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.25rem; }
.subtitle { color: var(--text-secondary); margin-bottom: 1.5rem; }
.section { margin-bottom: 2rem; }
.label { font-size: 0.7rem; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
/* ===== OPTIONS (for A/B/C choices) ===== */
.options { display: flex; flex-direction: column; gap: 0.75rem; }
.option {
background: var(--bg-secondary);
border: 2px solid var(--border);
border-radius: 12px;
padding: 1rem 1.25rem;
cursor: pointer;
transition: all 0.15s ease;
display: flex;
align-items: flex-start;
gap: 1rem;
}
.option:hover { border-color: var(--accent); }
.option.selected { background: var(--selected-bg); border-color: var(--selected-border); }
.option .letter {
background: var(--bg-tertiary);
color: var(--text-secondary);
width: 1.75rem; height: 1.75rem;
border-radius: 6px;
display: flex; align-items: center; justify-content: center;
font-weight: 600; font-size: 0.85rem; flex-shrink: 0;
}
.option.selected .letter { background: var(--accent); color: white; }
.option .content { flex: 1; }
.option .content h3 { font-size: 0.95rem; margin-bottom: 0.15rem; }
.option .content p { color: var(--text-secondary); font-size: 0.85rem; margin: 0; }
/* ===== CARDS (for showing designs/mockups) ===== */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; }
.card {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
cursor: pointer;
transition: all 0.15s ease;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
.card.selected { border-color: var(--selected-border); border-width: 2px; }
.card-image { background: var(--bg-tertiary); aspect-ratio: 16/10; display: flex; align-items: center; justify-content: center; }
.card-body { padding: 1rem; }
.card-body h3 { margin-bottom: 0.25rem; }
.card-body p { color: var(--text-secondary); font-size: 0.85rem; }
/* ===== MOCKUP CONTAINER ===== */
.mockup {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
overflow: hidden;
margin-bottom: 1.5rem;
}
.mockup-header {
background: var(--bg-tertiary);
padding: 0.5rem 1rem;
font-size: 0.75rem;
color: var(--text-secondary);
border-bottom: 1px solid var(--border);
}
.mockup-body { padding: 1.5rem; }
/* ===== SPLIT VIEW (side-by-side comparison) ===== */
.split { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
@media (max-width: 700px) { .split { grid-template-columns: 1fr; } }
/* ===== PROS/CONS ===== */
.pros-cons { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1rem 0; }
.pros, .cons { background: var(--bg-secondary); border-radius: 8px; padding: 1rem; }
.pros h4 { color: var(--success); font-size: 0.85rem; margin-bottom: 0.5rem; }
.cons h4 { color: var(--error); font-size: 0.85rem; margin-bottom: 0.5rem; }
.pros ul, .cons ul { margin-left: 1.25rem; font-size: 0.85rem; color: var(--text-secondary); }
.pros li, .cons li { margin-bottom: 0.25rem; }
/* ===== PLACEHOLDER (for mockup areas) ===== */
.placeholder {
background: var(--bg-tertiary);
border: 2px dashed var(--border);
border-radius: 8px;
padding: 2rem;
text-align: center;
color: var(--text-tertiary);
}
/* ===== INLINE MOCKUP ELEMENTS ===== */
.mock-nav { background: var(--accent); color: white; padding: 0.75rem 1rem; display: flex; gap: 1.5rem; font-size: 0.9rem; }
.mock-sidebar { background: var(--bg-tertiary); padding: 1rem; min-width: 180px; }
.mock-content { padding: 1.5rem; flex: 1; }
.mock-button { background: var(--accent); color: white; border: none; padding: 0.5rem 1rem; border-radius: 6px; font-size: 0.85rem; }
.mock-input { background: var(--bg-primary); border: 1px solid var(--border); border-radius: 6px; padding: 0.5rem; width: 100%; }
</style>
</head>
<body>
<div class="header">
<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">
<!-- CONTENT -->
</div>
</div>
<div class="indicator-bar">
<span id="indicator-text">Click an option above, then return to the terminal</span>
</div>
</body>
</html>

View 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();
})();

View File

@ -0,0 +1,141 @@
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 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';
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('<!-- CONTENT -->', content);
}
// 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 }));
// 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');
}
});
});
// 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')) {
// 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 }));
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, HOST, () => {
console.log(JSON.stringify({
type: 'server-started',
port: PORT,
host: HOST,
url_host: URL_HOST,
url: `http://${URL_HOST}:${PORT}`,
screen_dir: SCREEN_DIR
}));
});

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
{
"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"
}
}

View File

@ -0,0 +1,129 @@
#!/bin/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
# Codex environments may reap detached/background processes. Prefer foreground by default.
if [[ -n "${CODEX_CI:-}" && "$FOREGROUND" != "true" && "$FORCE_BACKGROUND" != "true" ]]; then
FOREGROUND="true"
fi
# 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
cd "$SCRIPT_DIR"
# Foreground mode for environments that reap detached/background processes.
if [[ "$FOREGROUND" == "true" ]]; then
echo "$$" > "$PID_FILE"
env BRAINSTORM_DIR="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" node index.js
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="$SCREEN_DIR" BRAINSTORM_HOST="$BIND_HOST" BRAINSTORM_URL_HOST="$URL_HOST" node index.js > "$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

View File

@ -0,0 +1,31 @@
#!/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

View File

@ -5,8 +5,6 @@ description: "You MUST use this before any creative work - creating features, bu
# Brainstorming Ideas Into Designs
## Overview
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 and get user approval.
@ -24,17 +22,20 @@ Every project goes through this process. A todo list, a single-function utility,
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. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria
3. **Propose 2-3 approaches** — with trade-offs and your recommendation
4. **Present design** — in sections scaled to their complexity, get user approval after each section
5. **Write design doc** — save to `docs/plans/YYYY-MM-DD-<topic>-design.md` and commit
6. **Transition to implementation** — invoke writing-plans skill to create implementation plan
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. **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];
@ -42,7 +43,10 @@ digraph brainstorming {
"Write design doc" [shape=box];
"Invoke writing-plans skill" [shape=doublecircle];
"Explore project context" -> "Ask clarifying questions";
"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?";
@ -57,32 +61,60 @@ digraph brainstorming {
## The Process
**Understanding the idea:**
- Check out the current project state first (files, docs, recent commits)
- Ask questions one at a time to refine the idea
- 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.
- For appropriately-scoped projects, ask questions one at a time to refine the idea
- Prefer multiple choice questions when possible, but open-ended is fine too
- Only one question per message - if a topic needs more exploration, break it into multiple questions
- 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
- 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.
## After the Design
**Documentation:**
- Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md`
- 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
**Implementation:**
- Invoke the writing-plans skill to create a detailed implementation plan
- Do NOT invoke any other skill. writing-plans is the next step.
@ -94,3 +126,22 @@ digraph brainstorming {
- **Explore alternatives** - Always propose 2-3 approaches before settling
- **Incremental validation** - Present design, get approval before moving on
- **Be flexible** - Go back and clarify when something doesn't make sense
## Visual Companion
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.
**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)"
**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`

View File

@ -0,0 +1,50 @@
# Spec Document Reviewer Prompt Template
Use this template when dispatching a spec document reviewer subagent.
**Purpose:** Verify the spec is complete, consistent, and ready for implementation planning.
**Dispatch after:** Spec document is written to docs/superpowers/specs/
```
Task tool (general-purpose):
description: "Review spec document"
prompt: |
You are a spec document reviewer. Verify this spec is complete and ready for planning.
**Spec to review:** [SPEC_FILE_PATH]
## What to Check
| 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 |
| Scope | Focused enough for a single plan — not covering multiple independent subsystems |
| Architecture | Units with clear boundaries, well-defined interfaces, independently understandable and testable |
## CRITICAL
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?
## Output Format
## Spec Review
**Status:** ✅ Approved | ❌ Issues Found
**Issues (if any):**
- [Section X]: [specific issue] - [why it matters]
**Recommendations (advisory):**
- [suggestions that don't block approval]
```
**Reviewer returns:** Status, Issues (if any), Recommendations

View File

@ -0,0 +1,260 @@
# Visual Companion Guide
Browser-based visual brainstorming companion for showing mockups, diagrams, and options.
## When to Use
Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?**
**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 and can click to select options. Selections are recorded to a `.events` file that you read on your next turn.
**Content fragments vs full documents:** If your HTML file starts with `<!DOCTYPE` or `<html`, the server serves it as-is (just injects the helper script). Otherwise, the server automatically wraps your content in the frame template — adding the header, CSS theme, selection indicator, and all interactive infrastructure. **Write content fragments by default.** Only write full documents when you need complete control over the page.
## 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
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
# "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000"}
```
Save `screen_dir` from the response. Tell user to open the URL.
**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.
**Codex behavior:** In Codex (`CODEX_CI=1`), `start-server.sh` auto-switches to foreground mode by default because background jobs may be reaped. Use `--background` only if your environment reliably preserves detached processes.
**If background processes are reaped in your environment:** run in foreground from a persistent terminal session:
```bash
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh --project-dir /path/to/project --foreground
```
In `--foreground` mode, the command stays attached and serves until interrupted.
If the URL is unreachable from your browser (common in remote/containerized setups), bind a non-loopback host:
```bash
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/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. **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. **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:
```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, selection indicator, and all interactive infrastructure).
**Minimal example:**
```html
<h2>Which layout works better?</h2>
<p class="subtitle">Consider readability and visual hierarchy</p>
<div class="options">
<div class="option" data-choice="a" onclick="toggleSelect(this)">
<div class="letter">A</div>
<div class="content">
<h3>Single Column</h3>
<p>Clean, focused reading experience</p>
</div>
</div>
<div class="option" data-choice="b" onclick="toggleSelect(this)">
<div class="letter">B</div>
<div class="content">
<h3>Two Column</h3>
<p>Sidebar navigation with main content</p>
</div>
</div>
</div>
```
That's it. No `<html>`, no CSS, no `<script>` tags needed. The server provides all of that.
## CSS Classes Available
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)">
<div class="letter">A</div>
<div class="content">
<h3>Title</h3>
<p>Description</p>
</div>
</div>
</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)">
<div class="card-image"><!-- mockup content --></div>
<div class="card-body">
<h3>Name</h3>
<p>Description</p>
</div>
</div>
</div>
```
### Mockup container
```html
<div class="mockup">
<div class="mockup-header">Preview: Dashboard Layout</div>
<div class="mockup-body"><!-- your mockup HTML --></div>
</div>
```
### Split view (side-by-side)
```html
<div class="split">
<div class="mockup"><!-- left --></div>
<div class="mockup"><!-- right --></div>
</div>
```
### Pros/Cons
```html
<div class="pros-cons">
<div class="pros"><h4>Pros</h4><ul><li>Benefit</li></ul></div>
<div class="cons"><h4>Cons</h4><ul><li>Drawback</li></ul></div>
</div>
```
### Mock elements (wireframe building blocks)
```html
<div class="mock-nav">Logo | Home | About | Contact</div>
<div style="display: flex;">
<div class="mock-sidebar">Navigation</div>
<div class="mock-content">Main content area</div>
</div>
<button class="mock-button">Action Button</button>
<input class="mock-input" placeholder="Input field">
<div class="placeholder">Placeholder area</div>
```
### 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
## 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.
## Design Tips
- **Scale fidelity to the question** — wireframes for layout, polish for polish questions
- **Explain the question on each page** — "Which layout feels more professional?" not just "Pick one"
- **Iterate before advancing** — if feedback changes current screen, write a new version
- **2-4 options max** per screen
- **Use real content when it matters** — for a photography portfolio, use actual images (Unsplash). Placeholder content obscures design issues.
- **Keep mockups simple** — focus on layout and structure, not pixel-perfect design
## File Naming
- Use semantic names: `platform.html`, `visual-style.html`, `layout.html`
- Never reuse filenames — each screen must be a new file
- For iterations: append version suffix like `layout-v2.html`, `layout-v3.html`
- Server serves newest file by modification time
## Cleaning Up
```bash
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/stop-server.sh $SCREEN_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 (client-side): `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/helper.js`

View File

@ -7,12 +7,12 @@ 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 (such as Claude Code or Codex). If subagents are available, use superpowers:subagent-driven-development instead of this skill.
## The Process
### Step 1: Load and Review Plan
@ -21,8 +21,7 @@ Load plan, review critically, execute tasks in batches, report for review betwee
3. If concerns: Raise them with your human partner before starting
4. If no concerns: Create TodoWrite 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,7 +59,6 @@ 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

View File

@ -58,7 +58,7 @@ HEAD_SHA=$(git rev-parse HEAD)
[Dispatch superpowers:code-reviewer subagent]
WHAT_WAS_IMPLEMENTED: Verification and repair functions for conversation index
PLAN_OR_REQUIREMENTS: Task 2 from docs/plans/deployment-plan.md
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

View File

@ -82,6 +82,39 @@ digraph process {
}
```
## Model Selection
Use the least powerful model that can handle each role to conserve cost and increase speed.
**Mechanical implementation tasks** (isolated functions, clear specs, 1-2 files): use a fast, cheap model. Most implementation tasks are mechanical when the plan is well-specified.
**Integration and judgment tasks** (multi-file coordination, pattern matching, debugging): use a standard model.
**Architecture, design, and review tasks**: use the most capable available model.
**Task complexity signals:**
- Touches 1-2 files with a complete spec → cheap model
- Touches multiple files with integration concerns → standard model
- Requires design judgment or broad codebase understanding → most capable model
## Handling Implementer Status
Implementer subagents report one of four statuses. Handle each appropriately:
**DONE:** Proceed to spec compliance review.
**DONE_WITH_CONCERNS:** The implementer completed the work but flagged doubts. Read the concerns before proceeding. If the concerns are about correctness or scope, address them before review. If they're observations (e.g., "this file is getting large"), note them and proceed to review.
**NEEDS_CONTEXT:** The implementer needs information that wasn't provided. Provide the missing context and re-dispatch.
**BLOCKED:** The implementer cannot complete the task. Assess the blocker:
1. If it's a context problem, provide more context and re-dispatch with the same model
2. If the task requires more reasoning, re-dispatch with a more capable model
3. If the task is too large, break it into smaller pieces
4. If the plan itself is wrong, escalate to the human
**Never** ignore an escalation or force the same model to retry without changes. If the implementer said it's stuck, something needs to change.
## Prompt Templates
- `./implementer-prompt.md` - Dispatch implementer subagent
@ -93,7 +126,7 @@ digraph process {
```
You: I'm using Subagent-Driven Development to execute this plan.
[Read plan file once: docs/plans/feature-plan.md]
[Read plan file once: docs/superpowers/plans/feature-plan.md]
[Extract all 5 tasks with full text and context]
[Create TodoWrite with all tasks]

View File

@ -17,4 +17,10 @@ Task tool (superpowers:code-reviewer):
DESCRIPTION: [task summary]
```
**In addition to standard code quality concerns, the reviewer should check:**
- Does each file have one clear responsibility with a well-defined interface?
- Are units decomposed so they can be understood and tested independently?
- Is the implementation following the file structure from the plan?
- Did this implementation create new files that are already large, or significantly grow existing files? (Don't flag pre-existing file sizes — focus on what this change contributed.)
**Code reviewer returns:** Strengths, Issues (Critical/Important/Minor), Assessment

View File

@ -41,6 +41,36 @@ Task tool (general-purpose):
**While you work:** If you encounter something unexpected or unclear, **ask questions**.
It's always OK to pause and clarify. Don't guess or make assumptions.
## Code Organization
You reason best about code you can hold in context at once, and your edits are more
reliable when files are focused. Keep this in mind:
- Follow the file structure defined in the plan
- Each file should have one clear responsibility with a well-defined interface
- If a file you're creating is growing beyond the plan's intent, stop and report
it as DONE_WITH_CONCERNS — don't split files on your own without plan guidance
- If an existing file you're modifying is already large or tangled, work carefully
and note it as a concern in your report
- In existing codebases, follow established patterns. Improve code you're touching
the way a good developer would, but don't restructure things outside your task.
## When You're in Over Your Head
It is always OK to stop and say "this is too hard for me." Bad work is worse than
no work. You will not be penalized for escalating.
**STOP and escalate when:**
- The task requires architectural decisions with multiple valid approaches
- You need to understand code beyond what was provided and can't find clarity
- You feel uncertain about whether your approach is correct
- The task involves restructuring existing code in ways the plan didn't anticipate
- You've been reading file after file trying to understand the system without progress
**How to escalate:** Report back with status BLOCKED or NEEDS_CONTEXT. Describe
specifically what you're stuck on, what you've tried, and what kind of help you need.
The controller can provide more context, re-dispatch with a more capable model,
or break the task into smaller pieces.
## Before Reporting Back: Self-Review
Review your work with fresh eyes. Ask yourself:
@ -70,9 +100,14 @@ Task tool (general-purpose):
## Report Format
When done, report:
- What you implemented
- **Status:** DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
- What you implemented (or what you attempted, if blocked)
- What you tested and test results
- Files changed
- Self-review findings (if any)
- Any issues or concerns
Use DONE_WITH_CONCERNS if you completed the work but have doubts about correctness.
Use BLOCKED if you cannot complete the task. Use NEEDS_CONTEXT if you need
information that wasn't provided. Never silently produce work you're unsure about.
```

View File

@ -3,6 +3,10 @@ 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
---
<SUBAGENT-STOP>
If you were dispatched as a subagent to execute a specific task, skip this skill.
</SUBAGENT-STOP>
<EXTREMELY-IMPORTANT>
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY MUST invoke the skill.
@ -11,12 +15,26 @@ IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
This is not negotiable. This is not optional. You cannot rationalize your way out of this.
</EXTREMELY-IMPORTANT>
## Instruction Priority
Superpowers skills override default system prompt behavior, but **user instructions always take precedence**:
1. **User's explicit instructions** (CLAUDE.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 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.
**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.
# Using Skills
## The Rule

View File

@ -0,0 +1,25 @@
# Codex Tool Mapping
Skills use Claude Code tool names. When you encounter these in a skill, use your platform equivalent:
| 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 |
## Subagent dispatch requires collab
Add to your Codex config (`~/.codex/config.toml`):
```toml
[features]
collab = true
```
This enables `spawn_agent`, `wait`, and `close_agent` for skills like `dispatching-parallel-agents` and `subagent-driven-development`.

View File

@ -15,7 +15,23 @@ Assume they are a skilled developer, but know almost nothing about our toolset o
**Context:** This should be run in a dedicated worktree (created by brainstorming skill).
**Save plans to:** `docs/plans/YYYY-MM-DD-<feature-name>.md`
**Save plans to:** `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md`
- (User preferences for plan location override this default)
## Scope Check
If the spec covers multiple independent subsystems, it should have been broken into sub-project specs during brainstorming. If it wasn't, suggest breaking this into separate plans — one per subsystem. Each plan should produce working, testable software on its own.
## File Structure
Before defining tasks, map out which files will be created or modified and what each one is responsible for. This is where decomposition decisions get locked in.
- Design units with clear boundaries and well-defined interfaces. Each file should have one clear responsibility.
- You reason best about code you can hold in context at once, and your edits are more reliable when files are focused. Prefer smaller, focused files over large ones that do too much.
- Files that change together should live together. Split by responsibility, not by technical layer.
- In existing codebases, follow established patterns. If the codebase uses large files, don't unilaterally restructure - but if a file you're modifying has grown unwieldy, including a split in the plan is reasonable.
This structure informs the task decomposition. Each task should produce self-contained changes that make sense independently.
## Bite-Sized Task Granularity
@ -33,7 +49,7 @@ Assume they are a skilled developer, but know almost nothing about our toolset o
```markdown
# [Feature Name] Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
> **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:** [One sentence describing what this builds]
@ -54,7 +70,7 @@ Assume they are a skilled developer, but know almost nothing about our toolset o
- Modify: `exact/path/to/existing.py:123-145`
- Test: `tests/exact/path/to/test.py`
**Step 1: Write the failing test**
- [ ] **Step 1: Write the failing test**
```python
def test_specific_behavior():
@ -62,24 +78,24 @@ def test_specific_behavior():
assert result == expected
```
**Step 2: Run test to verify it fails**
- [ ] **Step 2: Run test to verify it fails**
Run: `pytest tests/path/test.py::test_name -v`
Expected: FAIL with "function not defined"
**Step 3: Write minimal implementation**
- [ ] **Step 3: Write minimal implementation**
```python
def function(input):
return expected
```
**Step 4: Run test to verify it passes**
- [ ] **Step 4: Run test to verify it passes**
Run: `pytest tests/path/test.py::test_name -v`
Expected: PASS
**Step 5: Commit**
- [ ] **Step 5: Commit**
```bash
git add tests/path/test.py src/path/file.py
@ -94,23 +110,38 @@ git commit -m "feat: add specific feature"
- Reference relevant skills with @ syntax
- DRY, YAGNI, TDD, frequent commits
## Plan Review Loop
After completing each chunk of the plan:
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)
**Chunk boundaries:** Use `## Chunk N: <name>` headings to delimit chunks. Each chunk should be ≤1000 lines and logically self-contained.
**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
## Execution Handoff
After saving the plan, offer execution choice:
After saving the plan:
**"Plan complete and saved to `docs/plans/<filename>.md`. Two execution options:**
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Ready to execute?"**
**1. Subagent-Driven (this session)** - I dispatch fresh subagent per task, review between tasks, fast iteration
**Execution path depends on harness capabilities:**
**2. Parallel Session (separate)** - Open new session with executing-plans, batch execution with checkpoints
**If harness has subagents (Claude Code, etc.):**
- **REQUIRED:** Use superpowers:subagent-driven-development
- Do NOT offer a choice - subagent-driven is the standard approach
- Fresh subagent per task + two-stage review
**Which approach?"**
**If Subagent-Driven chosen:**
- **REQUIRED SUB-SKILL:** Use superpowers:subagent-driven-development
- Stay in this session
- Fresh subagent per task + code review
**If Parallel Session chosen:**
- Guide them to open new session in worktree
- **REQUIRED SUB-SKILL:** New session uses superpowers:executing-plans
**If harness does NOT have subagents:**
- Execute plan in current session using superpowers:executing-plans
- Batch execution with checkpoints for review

View File

@ -0,0 +1,52 @@
# Plan Document Reviewer Prompt Template
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.
**Dispatch after:** Each plan chunk is written
```
Task tool (general-purpose):
description: "Review plan chunk N"
prompt: |
You are a plan document reviewer. Verify this plan chunk is complete and ready for implementation.
**Plan chunk to review:** [PLAN_FILE_PATH] - Chunk N only
**Spec for reference:** [SPEC_FILE_PATH]
## What to Check
| 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 |
## CRITICAL
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
## Output Format
## Plan Review - Chunk N
**Status:** Approved | Issues Found
**Issues (if any):**
- [Task X, Step Y]: [specific issue] - [why it matters]
**Recommendations (advisory):**
- [suggestions that don't block approval]
```
**Reviewer returns:** Status, Issues (if any), Recommendations

View File

@ -0,0 +1,36 @@
{
"name": "brainstorm-server-tests",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "brainstorm-server-tests",
"version": "1.0.0",
"dependencies": {
"ws": "^8.19.0"
}
},
"node_modules/ws": {
"version": "8.19.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}

View File

@ -0,0 +1,10 @@
{
"name": "brainstorm-server-tests",
"version": "1.0.0",
"scripts": {
"test": "node server.test.js"
},
"dependencies": {
"ws": "^8.19.0"
}
}

View File

@ -0,0 +1,192 @@
const { spawn } = require('child_process');
const http = require('http');
const WebSocket = require('ws');
const fs = require('fs');
const path = require('path');
const assert = require('assert');
const SERVER_PATH = path.join(__dirname, '../../lib/brainstorm-server/index.js');
const TEST_PORT = 3334;
const TEST_DIR = '/tmp/brainstorm-test';
function cleanup() {
if (fs.existsSync(TEST_DIR)) {
fs.rmSync(TEST_DIR, { recursive: true });
}
}
async function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function fetch(url) {
return new Promise((resolve, reject) => {
http.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve({ status: res.statusCode, body: data }));
}).on('error', reject);
});
}
function startServer() {
return spawn('node', [SERVER_PATH], {
env: { ...process.env, BRAINSTORM_PORT: TEST_PORT, BRAINSTORM_DIR: TEST_DIR }
});
}
async function runTests() {
cleanup();
fs.mkdirSync(TEST_DIR, { recursive: true });
const server = startServer();
let stdout = '';
let stderr = '';
server.stdout.on('data', (data) => { stdout += data.toString(); });
server.stderr.on('data', (data) => { stderr += data.toString(); });
// Wait for server to start (up to 3 seconds)
for (let i = 0; i < 30; i++) {
if (stdout.includes('server-started')) break;
await sleep(100);
}
if (stderr) console.error('Server stderr:', stderr);
try {
// Test 1: Server starts and outputs JSON
console.log('Test 1: Server startup message');
assert(stdout.includes('server-started'), 'Should output server-started');
assert(stdout.includes(TEST_PORT.toString()), 'Should include port');
console.log(' PASS');
// Test 2: GET / returns waiting page with helper injected when no screens exist
console.log('Test 2: Serves waiting page with helper injected');
const res = await fetch(`http://localhost:${TEST_PORT}/`);
assert.strictEqual(res.status, 200);
assert(res.body.includes('Waiting for Claude'), 'Should show waiting message');
assert(res.body.includes('WebSocket'), 'Should have helper.js injected');
console.log(' PASS');
// Test 3: WebSocket connection and event relay
console.log('Test 3: WebSocket relays events to stdout');
stdout = '';
const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
await new Promise(resolve => ws.on('open', resolve));
ws.send(JSON.stringify({ type: 'click', text: 'Test Button' }));
await sleep(300);
assert(stdout.includes('"source":"user-event"'), 'Should relay user events with source field');
assert(stdout.includes('Test Button'), 'Should include event data');
ws.close();
console.log(' PASS');
// Test 4: File change triggers reload notification
console.log('Test 4: File change notifies browsers');
const ws2 = new WebSocket(`ws://localhost:${TEST_PORT}`);
await new Promise(resolve => ws2.on('open', resolve));
let gotReload = false;
ws2.on('message', (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === 'reload') gotReload = true;
});
fs.writeFileSync(path.join(TEST_DIR, 'test-screen.html'), '<html><body>Full doc</body></html>');
await sleep(500);
assert(gotReload, 'Should send reload message on file change');
ws2.close();
console.log(' PASS');
// 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');
// 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');
// Test 5: Full HTML document served as-is (not wrapped)
console.log('Test 5: Full HTML document served without frame wrapping');
const fullDoc = '<!DOCTYPE html>\n<html><head><title>Custom</title></head><body><h1>Custom Page</h1></body></html>';
fs.writeFileSync(path.join(TEST_DIR, 'full-doc.html'), fullDoc);
await sleep(300);
const fullRes = await fetch(`http://localhost:${TEST_PORT}/`);
assert(fullRes.body.includes('<h1>Custom Page</h1>'), 'Should contain original content');
assert(fullRes.body.includes('WebSocket'), 'Should still inject helper.js');
// Should NOT have the frame template's indicator bar
assert(!fullRes.body.includes('indicator-bar') || fullDoc.includes('indicator-bar'),
'Should not wrap full documents in frame template');
console.log(' PASS');
// Test 6: Bare HTML fragment gets wrapped in frame template
console.log('Test 6: Content fragment wrapped in frame template');
const fragment = '<h2>Pick a layout</h2>\n<p class="subtitle">Choose one</p>\n<div class="options"><div class="option" data-choice="a"><div class="letter">A</div><div class="content"><h3>Simple</h3></div></div></div>';
fs.writeFileSync(path.join(TEST_DIR, 'fragment.html'), fragment);
await sleep(300);
const fragRes = await fetch(`http://localhost:${TEST_PORT}/`);
// Should have the frame template structure
assert(fragRes.body.includes('indicator-bar'), 'Fragment should get indicator bar from frame');
assert(!fragRes.body.includes('<!-- CONTENT -->'), 'Content placeholder should be replaced');
// Should have the original content inside
assert(fragRes.body.includes('Pick a layout'), 'Fragment content should be present');
assert(fragRes.body.includes('data-choice="a"'), 'Fragment content should be intact');
// Should have helper.js injected
assert(fragRes.body.includes('WebSocket'), 'Fragment should have helper.js injected');
console.log(' PASS');
// Test 7: Helper.js includes toggleSelect and send functions
console.log('Test 7: Helper.js provides toggleSelect and send');
const helperContent = fs.readFileSync(
path.join(__dirname, '../../lib/brainstorm-server/helper.js'), 'utf-8'
);
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');
console.log(' PASS');
// 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');
console.log('\nAll tests passed!');
} finally {
server.kill();
cleanup();
}
}
runTests().catch(err => {
console.error('Test failed:', err);
process.exit(1);
});

View File

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

View File

@ -143,7 +143,7 @@ cleanup_test_project() {
create_test_plan() {
local project_dir="$1"
local plan_name="${2:-test-plan}"
local plan_file="$project_dir/docs/plans/$plan_name.md"
local plan_file="$project_dir/docs/superpowers/plans/$plan_name.md"
mkdir -p "$(dirname "$plan_file")"

View File

@ -42,10 +42,10 @@ cat > package.json <<'EOF'
}
EOF
mkdir -p src test docs/plans
mkdir -p src test docs/superpowers/plans
# Create a simple implementation plan
cat > docs/plans/implementation-plan.md <<'EOF'
cat > docs/superpowers/plans/implementation-plan.md <<'EOF'
# Test Implementation Plan
This is a minimal plan to test the subagent-driven-development workflow.
@ -121,7 +121,7 @@ OUTPUT_FILE="$TEST_PROJECT/claude-output.txt"
# Create prompt file
cat > "$TEST_PROJECT/prompt.txt" <<'EOF'
I want you to execute the implementation plan at docs/plans/implementation-plan.md using the subagent-driven-development skill.
I want you to execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
IMPORTANT: Follow the skill exactly. I will be verifying that you:
1. Read the plan once at the beginning
@ -136,7 +136,7 @@ EOF
# Note: We use a longer timeout since this is integration testing
# Use --allowed-tools to enable tool usage in headless mode
# IMPORTANT: Run from superpowers directory so local dev skills are available
PROMPT="Change to directory $TEST_PROJECT and then execute the implementation plan at docs/plans/implementation-plan.md using the subagent-driven-development skill.
PROMPT="Change to directory $TEST_PROJECT and then execute the implementation plan at docs/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
IMPORTANT: Follow the skill exactly. I will be verifying that you:
1. Read the plan once at the beginning

View File

@ -1,3 +1,3 @@
The plan is done. docs/plans/auth-system.md has everything.
The plan is done. docs/superpowers/plans/auth-system.md has everything.
Do subagent-driven development on this - start with Task 1, dispatch a subagent, then we'll review.

View File

@ -1,4 +1,4 @@
Great, the plan is complete. I've saved it to docs/plans/auth-system.md.
Great, the plan is complete. I've saved it to docs/superpowers/plans/auth-system.md.
Here's a summary of what we designed:
- Task 1: Add User Model with email/password fields

View File

@ -1,5 +1,5 @@
[Previous assistant message]:
Plan complete and saved to docs/plans/auth-system.md.
Plan complete and saved to docs/superpowers/plans/auth-system.md.
Two execution options:
1. Subagent-Driven (this session) - I dispatch a fresh subagent per task, review between tasks, fast iteration within this conversation

View File

@ -1,4 +1,4 @@
I have my implementation plan ready at docs/plans/auth-system.md.
I have my implementation plan ready at docs/superpowers/plans/auth-system.md.
I want to use subagent-driven-development to execute it. That means:
- Dispatch a fresh subagent for each task in the plan

View File

@ -1,3 +1,3 @@
I have a plan at docs/plans/auth-system.md that's ready to implement.
I have a plan at docs/superpowers/plans/auth-system.md that's ready to implement.
subagent-driven-development, please

View File

@ -1,3 +1,3 @@
Plan is at docs/plans/auth-system.md.
Plan is at docs/superpowers/plans/auth-system.md.
subagent-driven-development, please. Don't waste time - just read the plan and start dispatching subagents immediately.

View File

@ -12,7 +12,7 @@ OUTPUT_DIR="/tmp/superpowers-tests/${TIMESTAMP}/explicit-skill-requests/claude-d
mkdir -p "$OUTPUT_DIR"
PROJECT_DIR="$OUTPUT_DIR/project"
mkdir -p "$PROJECT_DIR/docs/plans"
mkdir -p "$PROJECT_DIR/docs/superpowers/plans"
echo "=== Test: Claude Describes SDD First ==="
echo "Output dir: $OUTPUT_DIR"
@ -21,7 +21,7 @@ echo ""
cd "$PROJECT_DIR"
# Create a plan
cat > "$PROJECT_DIR/docs/plans/auth-system.md" << 'EOF'
cat > "$PROJECT_DIR/docs/superpowers/plans/auth-system.md" << 'EOF'
# Auth System Implementation Plan
## Task 1: Add User Model
@ -36,7 +36,7 @@ EOF
# Turn 1: Have Claude describe execution options including SDD
echo ">>> Turn 1: Ask Claude to describe execution options..."
claude -p "I have a plan at docs/plans/auth-system.md. Tell me about my options for executing it, including what subagent-driven-development means and how it works." \
claude -p "I have a plan at docs/superpowers/plans/auth-system.md. Tell me about my options for executing it, including what subagent-driven-development means and how it works." \
--model haiku \
--plugin-dir "$PLUGIN_DIR" \
--dangerously-skip-permissions \

View File

@ -12,7 +12,7 @@ OUTPUT_DIR="/tmp/superpowers-tests/${TIMESTAMP}/explicit-skill-requests/extended
mkdir -p "$OUTPUT_DIR"
PROJECT_DIR="$OUTPUT_DIR/project"
mkdir -p "$PROJECT_DIR/docs/plans"
mkdir -p "$PROJECT_DIR/docs/superpowers/plans"
echo "=== Extended Multi-Turn Test ==="
echo "Output dir: $OUTPUT_DIR"

View File

@ -12,7 +12,7 @@ OUTPUT_DIR="/tmp/superpowers-tests/${TIMESTAMP}/explicit-skill-requests/haiku"
mkdir -p "$OUTPUT_DIR"
PROJECT_DIR="$OUTPUT_DIR/project"
mkdir -p "$PROJECT_DIR/docs/plans"
mkdir -p "$PROJECT_DIR/docs/superpowers/plans"
mkdir -p "$PROJECT_DIR/.claude"
echo "=== Haiku Model Test with User CLAUDE.md ==="
@ -31,7 +31,7 @@ else
fi
# Create a dummy plan file
cat > "$PROJECT_DIR/docs/plans/auth-system.md" << 'EOF'
cat > "$PROJECT_DIR/docs/superpowers/plans/auth-system.md" << 'EOF'
# Auth System Implementation Plan
## Task 1: Add User Model

View File

@ -16,7 +16,7 @@ mkdir -p "$OUTPUT_DIR"
# Create project directory (conversation is cwd-based)
PROJECT_DIR="$OUTPUT_DIR/project"
mkdir -p "$PROJECT_DIR/docs/plans"
mkdir -p "$PROJECT_DIR/docs/superpowers/plans"
echo "=== Multi-Turn Explicit Skill Request Test ==="
echo "Output dir: $OUTPUT_DIR"
@ -27,7 +27,7 @@ echo ""
cd "$PROJECT_DIR"
# Create a dummy plan file
cat > "$PROJECT_DIR/docs/plans/auth-system.md" << 'EOF'
cat > "$PROJECT_DIR/docs/superpowers/plans/auth-system.md" << 'EOF'
# Auth System Implementation Plan
## Task 1: Add User Model
@ -59,7 +59,7 @@ echo ""
# Turn 2: Continue with more planning detail
echo ">>> Turn 2: Continuing planning..."
TURN2_LOG="$OUTPUT_DIR/turn2.json"
claude -p "Good analysis. I've already written the plan to docs/plans/auth-system.md. Now I'm ready to implement. What are my options for execution?" \
claude -p "Good analysis. I've already written the plan to docs/superpowers/plans/auth-system.md. Now I'm ready to implement. What are my options for execution?" \
--continue \
--plugin-dir "$PLUGIN_DIR" \
--dangerously-skip-permissions \

View File

@ -43,10 +43,10 @@ cp "$PROMPT_FILE" "$OUTPUT_DIR/prompt.txt"
# Create a minimal project directory for the test
PROJECT_DIR="$OUTPUT_DIR/project"
mkdir -p "$PROJECT_DIR/docs/plans"
mkdir -p "$PROJECT_DIR/docs/superpowers/plans"
# Create a dummy plan file for mid-conversation tests
cat > "$PROJECT_DIR/docs/plans/auth-system.md" << 'EOF'
cat > "$PROJECT_DIR/docs/superpowers/plans/auth-system.md" << 'EOF'
# Auth System Implementation Plan
## Task 1: Add User Model

View File

@ -1 +1 @@
I have a plan document at docs/plans/2024-01-15-auth-system.md that needs to be executed. Please implement it.
I have a plan document at docs/superpowers/plans/2024-01-15-auth-system.md that needs to be executed. Please implement it.