mirror of
https://github.com/obra/superpowers.git
synced 2026-04-21 00:49:06 +08:00
Compare commits
19 Commits
minor-adj-
...
fix/window
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c3d478dc47 | ||
|
|
e147c303c0 | ||
|
|
7a6b4c14d5 | ||
|
|
2b8814f7d9 | ||
|
|
b16369cae2 | ||
|
|
e9263c9754 | ||
|
|
de2e15242c | ||
|
|
70c2d06c4e | ||
|
|
b98afbd74f | ||
|
|
2a61167b02 | ||
|
|
94d5f4a817 | ||
|
|
209fcec3b9 | ||
|
|
fccb5b4b8f | ||
|
|
15d0f2a8f6 | ||
|
|
cc585ad4d5 | ||
|
|
7e86703081 | ||
|
|
c536926f03 | ||
|
|
333eaa3281 | ||
|
|
74a55c0bf4 |
@@ -9,7 +9,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "4.3.0",
|
||||
"version": "4.0.3",
|
||||
"source": "./",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"description": "Core skills library for Claude Code: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "4.3.0",
|
||||
"version": "4.0.3",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
|
||||
@@ -1,67 +1,35 @@
|
||||
# Installing Superpowers for Codex
|
||||
|
||||
Enable superpowers skills in Codex via native skill discovery. Just clone and symlink.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Git
|
||||
Quick setup to enable superpowers skills in Codex.
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone the superpowers repository:**
|
||||
1. **Clone superpowers repository**:
|
||||
```bash
|
||||
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
|
||||
mkdir -p ~/.codex/superpowers
|
||||
cd ~/.codex/superpowers
|
||||
git clone https://github.com/obra/superpowers.git .
|
||||
```
|
||||
|
||||
2. **Create the skills symlink:**
|
||||
2. **Create personal skills directory**:
|
||||
```bash
|
||||
mkdir -p ~/.agents/skills
|
||||
ln -s ~/.codex/superpowers/skills ~/.agents/skills/superpowers
|
||||
mkdir -p ~/.codex/skills
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills"
|
||||
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\superpowers" "$env:USERPROFILE\.codex\superpowers\skills"
|
||||
3. **Update ~/.codex/AGENTS.md** to include this superpowers section:
|
||||
```markdown
|
||||
## Superpowers System
|
||||
|
||||
<EXTREMELY_IMPORTANT>
|
||||
You have superpowers. Superpowers teach you new skills and capabilities. RIGHT NOW run: `~/.codex/superpowers/.codex/superpowers-codex bootstrap` and follow the instructions it returns.
|
||||
</EXTREMELY_IMPORTANT>
|
||||
```
|
||||
|
||||
3. **Restart Codex** (quit and relaunch the CLI) to discover the skills.
|
||||
|
||||
## Migrating from old bootstrap
|
||||
|
||||
If you installed superpowers before native skill discovery, you need to:
|
||||
|
||||
1. **Update the repo:**
|
||||
```bash
|
||||
cd ~/.codex/superpowers && git pull
|
||||
```
|
||||
|
||||
2. **Create the skills symlink** (step 2 above) — this is the new discovery mechanism.
|
||||
|
||||
3. **Remove the old bootstrap block** from `~/.codex/AGENTS.md` — any block referencing `superpowers-codex bootstrap` is no longer needed.
|
||||
|
||||
4. **Restart Codex.**
|
||||
|
||||
## Verify
|
||||
## Verification
|
||||
|
||||
Test the installation:
|
||||
```bash
|
||||
ls -la ~/.agents/skills/superpowers
|
||||
~/.codex/superpowers/.codex/superpowers-codex bootstrap
|
||||
```
|
||||
|
||||
You should see a symlink (or junction on Windows) pointing to your superpowers skills directory.
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.codex/superpowers && git pull
|
||||
```
|
||||
|
||||
Skills update instantly through the symlink.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
rm ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
Optionally delete the clone: `rm -rf ~/.codex/superpowers`.
|
||||
You should see skill listings and bootstrap instructions. The system is now ready for use.
|
||||
33
.codex/superpowers-bootstrap.md
Normal file
33
.codex/superpowers-bootstrap.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Superpowers Bootstrap for Codex
|
||||
|
||||
<EXTREMELY_IMPORTANT>
|
||||
You have superpowers.
|
||||
|
||||
**Tool for running skills:**
|
||||
- `~/.codex/superpowers/.codex/superpowers-codex use-skill <skill-name>`
|
||||
|
||||
**Tool Mapping for Codex:**
|
||||
When skills reference tools you don't have, substitute your equivalent tools:
|
||||
- `TodoWrite` → `update_plan` (your planning/task tracking tool)
|
||||
- `Task` tool with subagents → Tell the user that subagents aren't available in Codex yet and you'll do the work the subagent would do
|
||||
- `Skill` tool → `~/.codex/superpowers/.codex/superpowers-codex use-skill` command (already available)
|
||||
- `Read`, `Write`, `Edit`, `Bash` → Use your native tools with similar functions
|
||||
|
||||
**Skills naming:**
|
||||
- Superpowers skills: `superpowers:skill-name` (from ~/.codex/superpowers/skills/)
|
||||
- Personal skills: `skill-name` (from ~/.codex/skills/)
|
||||
- Personal skills override superpowers skills when names match
|
||||
|
||||
**Critical Rules:**
|
||||
- Before ANY task, review the skills list (shown below)
|
||||
- If a relevant skill exists, you MUST use `~/.codex/superpowers/.codex/superpowers-codex use-skill` to load it
|
||||
- Announce: "I've read the [Skill Name] skill and I'm using it to [purpose]"
|
||||
- Skills with checklists require `update_plan` todos for each item
|
||||
- NEVER skip mandatory workflows (brainstorming before coding, TDD, systematic debugging)
|
||||
|
||||
**Skills location:**
|
||||
- Superpowers skills: ~/.codex/superpowers/skills/
|
||||
- Personal skills: ~/.codex/skills/ (override superpowers when names match)
|
||||
|
||||
IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
|
||||
</EXTREMELY_IMPORTANT>
|
||||
267
.codex/superpowers-codex
Executable file
267
.codex/superpowers-codex
Executable file
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const skillsCore = require('../lib/skills-core');
|
||||
|
||||
// Paths
|
||||
const homeDir = os.homedir();
|
||||
const superpowersSkillsDir = path.join(homeDir, '.codex', 'superpowers', 'skills');
|
||||
const personalSkillsDir = path.join(homeDir, '.codex', 'skills');
|
||||
const bootstrapFile = path.join(homeDir, '.codex', 'superpowers', '.codex', 'superpowers-bootstrap.md');
|
||||
const superpowersRepoDir = path.join(homeDir, '.codex', 'superpowers');
|
||||
|
||||
// Utility functions
|
||||
function printSkill(skillPath, sourceType) {
|
||||
const skillFile = path.join(skillPath, 'SKILL.md');
|
||||
const relPath = sourceType === 'personal'
|
||||
? path.relative(personalSkillsDir, skillPath)
|
||||
: path.relative(superpowersSkillsDir, skillPath);
|
||||
|
||||
// Print skill name with namespace
|
||||
if (sourceType === 'personal') {
|
||||
console.log(relPath.replace(/\\/g, '/')); // Personal skills are not namespaced
|
||||
} else {
|
||||
console.log(`superpowers:${relPath.replace(/\\/g, '/')}`); // Superpowers skills get superpowers namespace
|
||||
}
|
||||
|
||||
// Extract and print metadata
|
||||
const { name, description } = skillsCore.extractFrontmatter(skillFile);
|
||||
|
||||
if (description) console.log(` ${description}`);
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Commands
|
||||
function runFindSkills() {
|
||||
console.log('Available skills:');
|
||||
console.log('==================');
|
||||
console.log('');
|
||||
|
||||
const foundSkills = new Set();
|
||||
|
||||
// Find personal skills first (these take precedence)
|
||||
const personalSkills = skillsCore.findSkillsInDir(personalSkillsDir, 'personal', 2);
|
||||
for (const skill of personalSkills) {
|
||||
const relPath = path.relative(personalSkillsDir, skill.path);
|
||||
foundSkills.add(relPath);
|
||||
printSkill(skill.path, 'personal');
|
||||
}
|
||||
|
||||
// Find superpowers skills (only if not already found in personal)
|
||||
const superpowersSkills = skillsCore.findSkillsInDir(superpowersSkillsDir, 'superpowers', 1);
|
||||
for (const skill of superpowersSkills) {
|
||||
const relPath = path.relative(superpowersSkillsDir, skill.path);
|
||||
if (!foundSkills.has(relPath)) {
|
||||
printSkill(skill.path, 'superpowers');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Usage:');
|
||||
console.log(' superpowers-codex use-skill <skill-name> # Load a specific skill');
|
||||
console.log('');
|
||||
console.log('Skill naming:');
|
||||
console.log(' Superpowers skills: superpowers:skill-name (from ~/.codex/superpowers/skills/)');
|
||||
console.log(' Personal skills: skill-name (from ~/.codex/skills/)');
|
||||
console.log(' Personal skills override superpowers skills when names match.');
|
||||
console.log('');
|
||||
console.log('Note: All skills are disclosed at session start via bootstrap.');
|
||||
}
|
||||
|
||||
function runBootstrap() {
|
||||
console.log('# Superpowers Bootstrap for Codex');
|
||||
console.log('# ================================');
|
||||
console.log('');
|
||||
|
||||
// Check for updates (with timeout protection)
|
||||
if (skillsCore.checkForUpdates(superpowersRepoDir)) {
|
||||
console.log('## Update Available');
|
||||
console.log('');
|
||||
console.log('⚠️ Your superpowers installation is behind the latest version.');
|
||||
console.log('To update, run: `cd ~/.codex/superpowers && git pull`');
|
||||
console.log('');
|
||||
console.log('---');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Show the bootstrap instructions
|
||||
if (fs.existsSync(bootstrapFile)) {
|
||||
console.log('## Bootstrap Instructions:');
|
||||
console.log('');
|
||||
try {
|
||||
const content = fs.readFileSync(bootstrapFile, 'utf8');
|
||||
console.log(content);
|
||||
} catch (error) {
|
||||
console.log(`Error reading bootstrap file: ${error.message}`);
|
||||
}
|
||||
console.log('');
|
||||
console.log('---');
|
||||
console.log('');
|
||||
}
|
||||
|
||||
// Run find-skills to show available skills
|
||||
console.log('## Available Skills:');
|
||||
console.log('');
|
||||
runFindSkills();
|
||||
|
||||
console.log('');
|
||||
console.log('---');
|
||||
console.log('');
|
||||
|
||||
// Load the using-superpowers skill automatically
|
||||
console.log('## Auto-loading superpowers:using-superpowers skill:');
|
||||
console.log('');
|
||||
runUseSkill('superpowers:using-superpowers');
|
||||
|
||||
console.log('');
|
||||
console.log('---');
|
||||
console.log('');
|
||||
console.log('# Bootstrap Complete!');
|
||||
console.log('# You now have access to all superpowers skills.');
|
||||
console.log('# Use "superpowers-codex use-skill <skill>" to load and apply skills.');
|
||||
console.log('# Remember: If a skill applies to your task, you MUST use it!');
|
||||
}
|
||||
|
||||
function runUseSkill(skillName) {
|
||||
if (!skillName) {
|
||||
console.log('Usage: superpowers-codex use-skill <skill-name>');
|
||||
console.log('Examples:');
|
||||
console.log(' superpowers-codex use-skill superpowers:brainstorming # Load superpowers skill');
|
||||
console.log(' superpowers-codex use-skill brainstorming # Load personal skill (or superpowers if not found)');
|
||||
console.log(' superpowers-codex use-skill my-custom-skill # Load personal skill');
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle namespaced skill names
|
||||
let actualSkillPath;
|
||||
let forceSuperpowers = false;
|
||||
|
||||
if (skillName.startsWith('superpowers:')) {
|
||||
// Remove the superpowers: namespace prefix
|
||||
actualSkillPath = skillName.substring('superpowers:'.length);
|
||||
forceSuperpowers = true;
|
||||
} else {
|
||||
actualSkillPath = skillName;
|
||||
}
|
||||
|
||||
// Remove "skills/" prefix if present
|
||||
if (actualSkillPath.startsWith('skills/')) {
|
||||
actualSkillPath = actualSkillPath.substring('skills/'.length);
|
||||
}
|
||||
|
||||
// Function to find skill file
|
||||
function findSkillFile(searchPath) {
|
||||
// Check for exact match with SKILL.md
|
||||
const skillMdPath = path.join(searchPath, 'SKILL.md');
|
||||
if (fs.existsSync(skillMdPath)) {
|
||||
return skillMdPath;
|
||||
}
|
||||
|
||||
// Check for direct SKILL.md file
|
||||
if (searchPath.endsWith('SKILL.md') && fs.existsSync(searchPath)) {
|
||||
return searchPath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
let skillFile = null;
|
||||
|
||||
// If superpowers: namespace was used, only check superpowers skills
|
||||
if (forceSuperpowers) {
|
||||
if (fs.existsSync(superpowersSkillsDir)) {
|
||||
const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath);
|
||||
skillFile = findSkillFile(superpowersPath);
|
||||
}
|
||||
} else {
|
||||
// First check personal skills directory (takes precedence)
|
||||
if (fs.existsSync(personalSkillsDir)) {
|
||||
const personalPath = path.join(personalSkillsDir, actualSkillPath);
|
||||
skillFile = findSkillFile(personalPath);
|
||||
if (skillFile) {
|
||||
console.log(`# Loading personal skill: ${actualSkillPath}`);
|
||||
console.log(`# Source: ${skillFile}`);
|
||||
console.log('');
|
||||
}
|
||||
}
|
||||
|
||||
// If not found in personal, check superpowers skills
|
||||
if (!skillFile && fs.existsSync(superpowersSkillsDir)) {
|
||||
const superpowersPath = path.join(superpowersSkillsDir, actualSkillPath);
|
||||
skillFile = findSkillFile(superpowersPath);
|
||||
if (skillFile) {
|
||||
console.log(`# Loading superpowers skill: superpowers:${actualSkillPath}`);
|
||||
console.log(`# Source: ${skillFile}`);
|
||||
console.log('');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If still not found, error
|
||||
if (!skillFile) {
|
||||
console.log(`Error: Skill not found: ${actualSkillPath}`);
|
||||
console.log('');
|
||||
console.log('Available skills:');
|
||||
runFindSkills();
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract frontmatter and content using shared core functions
|
||||
let content, frontmatter;
|
||||
try {
|
||||
const fullContent = fs.readFileSync(skillFile, 'utf8');
|
||||
const { name, description } = skillsCore.extractFrontmatter(skillFile);
|
||||
content = skillsCore.stripFrontmatter(fullContent);
|
||||
frontmatter = { name, description };
|
||||
} catch (error) {
|
||||
console.log(`Error reading skill file: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Display skill header with clean info
|
||||
const displayName = forceSuperpowers ? `superpowers:${actualSkillPath}` :
|
||||
(skillFile.includes(personalSkillsDir) ? actualSkillPath : `superpowers:${actualSkillPath}`);
|
||||
|
||||
const skillDirectory = path.dirname(skillFile);
|
||||
|
||||
console.log(`# ${frontmatter.name || displayName}`);
|
||||
if (frontmatter.description) {
|
||||
console.log(`# ${frontmatter.description}`);
|
||||
}
|
||||
console.log(`# Skill-specific tools and reference files live in ${skillDirectory}`);
|
||||
console.log('# ============================================');
|
||||
console.log('');
|
||||
|
||||
// Display the skill content (without frontmatter)
|
||||
console.log(content);
|
||||
|
||||
}
|
||||
|
||||
// Main CLI
|
||||
const command = process.argv[2];
|
||||
const arg = process.argv[3];
|
||||
|
||||
switch (command) {
|
||||
case 'bootstrap':
|
||||
runBootstrap();
|
||||
break;
|
||||
case 'use-skill':
|
||||
runUseSkill(arg);
|
||||
break;
|
||||
case 'find-skills':
|
||||
runFindSkills();
|
||||
break;
|
||||
default:
|
||||
console.log('Superpowers for Codex');
|
||||
console.log('Usage:');
|
||||
console.log(' superpowers-codex bootstrap # Run complete bootstrap with all skills');
|
||||
console.log(' superpowers-codex use-skill <skill-name> # Load a specific skill');
|
||||
console.log(' superpowers-codex find-skills # List all available skills');
|
||||
console.log('');
|
||||
console.log('Examples:');
|
||||
console.log(' superpowers-codex bootstrap');
|
||||
console.log(' superpowers-codex use-skill superpowers:brainstorming');
|
||||
console.log(' superpowers-codex use-skill my-custom-skill');
|
||||
break;
|
||||
}
|
||||
14
.codex/superpowers-codex.cmd
Normal file
14
.codex/superpowers-codex.cmd
Normal file
@@ -0,0 +1,14 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
REM Windows shim for the extensionless Node.js launcher (superpowers-codex).
|
||||
REM
|
||||
REM Windows cannot execute extensionless scripts with shebangs, so this wrapper
|
||||
REM invokes Node.js directly.
|
||||
REM
|
||||
REM Usage:
|
||||
REM superpowers-codex.cmd bootstrap
|
||||
REM superpowers-codex.cmd use-skill superpowers:brainstorming
|
||||
REM superpowers-codex.cmd find-skills
|
||||
|
||||
node "%~dp0superpowers-codex" %*
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "superpowers",
|
||||
"displayName": "Superpowers",
|
||||
"description": "Core skills library: TDD, debugging, collaboration patterns, and proven techniques",
|
||||
"version": "4.3.0",
|
||||
"author": {
|
||||
"name": "Jesse Vincent",
|
||||
"email": "jesse@fsck.com"
|
||||
},
|
||||
"homepage": "https://github.com/obra/superpowers",
|
||||
"repository": "https://github.com/obra/superpowers",
|
||||
"license": "MIT",
|
||||
"keywords": ["skills", "tdd", "debugging", "collaboration", "best-practices", "workflows"],
|
||||
"skills": "./skills/",
|
||||
"agents": "./agents/",
|
||||
"commands": "./commands/",
|
||||
"hooks": "./hooks/hooks.json"
|
||||
}
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1,6 +1,5 @@
|
||||
# Ensure shell scripts always have LF line endings
|
||||
*.sh text eol=lf
|
||||
hooks/session-start text eol=lf
|
||||
|
||||
# Ensure the polyglot wrapper keeps LF (it's parsed by both cmd and bash)
|
||||
*.cmd text eol=lf
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,5 +2,3 @@
|
||||
.private-journal/
|
||||
.claude/
|
||||
node_modules/
|
||||
inspo
|
||||
triage/
|
||||
|
||||
@@ -3,13 +3,15 @@
|
||||
## Prerequisites
|
||||
|
||||
- [OpenCode.ai](https://opencode.ai) installed
|
||||
- Node.js installed
|
||||
- Git installed
|
||||
|
||||
## Installation Steps
|
||||
|
||||
### 1. Clone Superpowers
|
||||
### 1. Install Superpowers
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/superpowers
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
```
|
||||
|
||||
@@ -18,43 +20,32 @@ git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
Create a symlink so OpenCode discovers the plugin:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/plugins
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js
|
||||
ln -s ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js ~/.config/opencode/plugins/superpowers.js
|
||||
mkdir -p ~/.config/opencode/plugin
|
||||
ln -sf ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js ~/.config/opencode/plugin/superpowers.js
|
||||
```
|
||||
|
||||
### 3. Symlink Skills
|
||||
### 3. Restart OpenCode
|
||||
|
||||
Create a symlink so OpenCode's native skill tool discovers superpowers skills:
|
||||
Restart OpenCode. The plugin will automatically inject superpowers context via the chat.message hook.
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.config/opencode/skills
|
||||
rm -rf ~/.config/opencode/skills/superpowers
|
||||
ln -s ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
```
|
||||
|
||||
### 4. Restart OpenCode
|
||||
|
||||
Restart OpenCode. The plugin will automatically inject superpowers context.
|
||||
|
||||
Verify by asking: "do you have superpowers?"
|
||||
You should see superpowers is active when you ask "do you have superpowers?"
|
||||
|
||||
## Usage
|
||||
|
||||
### Finding Skills
|
||||
|
||||
Use OpenCode's native `skill` tool to list available skills:
|
||||
Use the `find_skills` tool to list all available skills:
|
||||
|
||||
```
|
||||
use skill tool to list skills
|
||||
use find_skills tool
|
||||
```
|
||||
|
||||
### Loading a Skill
|
||||
|
||||
Use OpenCode's native `skill` tool to load a specific skill:
|
||||
Use the `use_skill` tool to load a specific skill:
|
||||
|
||||
```
|
||||
use skill tool to load superpowers/brainstorming
|
||||
use use_skill tool with skill_name: "superpowers:brainstorming"
|
||||
```
|
||||
|
||||
### Personal Skills
|
||||
@@ -78,11 +69,36 @@ description: Use when [condition] - [what it does]
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
Personal skills override superpowers skills with the same name.
|
||||
|
||||
### Project Skills
|
||||
|
||||
Create project-specific skills in `.opencode/skills/` within your project.
|
||||
Create project-specific skills in your OpenCode project:
|
||||
|
||||
**Skill Priority:** Project skills > Personal skills > Superpowers skills
|
||||
```bash
|
||||
# In your OpenCode project
|
||||
mkdir -p .opencode/skills/my-project-skill
|
||||
```
|
||||
|
||||
Create `.opencode/skills/my-project-skill/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: my-project-skill
|
||||
description: Use when [condition] - [what it does]
|
||||
---
|
||||
|
||||
# My Project Skill
|
||||
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
**Skill Priority:** Project skills override personal skills, which override superpowers skills.
|
||||
|
||||
**Skill Naming:**
|
||||
- `project:skill-name` - Force project skill lookup
|
||||
- `skill-name` - Searches project → personal → superpowers
|
||||
- `superpowers:skill-name` - Force superpowers skill lookup
|
||||
|
||||
## Updating
|
||||
|
||||
@@ -95,25 +111,25 @@ git pull
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
1. Check plugin symlink: `ls -l ~/.config/opencode/plugins/superpowers.js`
|
||||
2. Check source exists: `ls ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
3. Check OpenCode logs for errors
|
||||
1. Check plugin file exists: `ls ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js`
|
||||
2. Check OpenCode logs for errors
|
||||
3. Verify Node.js is installed: `node --version`
|
||||
|
||||
### Skills not found
|
||||
|
||||
1. Check skills symlink: `ls -l ~/.config/opencode/skills/superpowers`
|
||||
2. Verify it points to: `~/.config/opencode/superpowers/skills`
|
||||
3. Use `skill` tool to list what's discovered
|
||||
1. Verify skills directory exists: `ls ~/.config/opencode/superpowers/skills`
|
||||
2. Use `find_skills` tool to see what's discovered
|
||||
3. Check file structure: each skill should have a `SKILL.md` file
|
||||
|
||||
### Tool mapping
|
||||
### Tool mapping issues
|
||||
|
||||
When skills reference Claude Code tools:
|
||||
- `TodoWrite` → `update_plan`
|
||||
- `Task` with subagents → `@mention` syntax
|
||||
- `Skill` tool → OpenCode's native `skill` tool
|
||||
- File operations → your native tools
|
||||
When a skill references a Claude Code tool you don't have:
|
||||
- `TodoWrite` → use `update_plan`
|
||||
- `Task` with subagents → use `@mention` syntax to invoke OpenCode subagents
|
||||
- `Skill` → use `use_skill` tool
|
||||
- File operations → use your native tools
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Report issues: https://github.com/obra/superpowers/issues
|
||||
- Full documentation: https://github.com/obra/superpowers/blob/main/docs/README.opencode.md
|
||||
- Documentation: https://github.com/obra/superpowers
|
||||
|
||||
22
README.md
22
README.md
@@ -26,8 +26,7 @@ Thanks!
|
||||
|
||||
## Installation
|
||||
|
||||
**Note:** Installation differs by platform. Claude Code or Cursor have built-in plugin marketplaces. Codex and OpenCode require manual setup.
|
||||
|
||||
**Note:** Installation differs by platform. Claude Code has a built-in plugin system. Codex and OpenCode require manual setup.
|
||||
|
||||
### Claude Code (via Plugin Marketplace)
|
||||
|
||||
@@ -43,12 +42,19 @@ Then install the plugin from this marketplace:
|
||||
/plugin install superpowers@superpowers-marketplace
|
||||
```
|
||||
|
||||
### Cursor (via Plugin Marketplace)
|
||||
### Verify Installation
|
||||
|
||||
In Cursor Agent chat, install from marketplace:
|
||||
Check that commands appear:
|
||||
|
||||
```text
|
||||
/plugin-add superpowers
|
||||
```bash
|
||||
/help
|
||||
```
|
||||
|
||||
```
|
||||
# Should see:
|
||||
# /superpowers:brainstorm - Interactive design refinement
|
||||
# /superpowers:write-plan - Create implementation plan
|
||||
# /superpowers:execute-plan - Execute plan in batches
|
||||
```
|
||||
|
||||
### Codex
|
||||
@@ -71,10 +77,6 @@ Fetch and follow instructions from https://raw.githubusercontent.com/obra/superp
|
||||
|
||||
**Detailed docs:** [docs/README.opencode.md](docs/README.opencode.md)
|
||||
|
||||
### Verify Installation
|
||||
|
||||
Start a new session in your chosen platform and ask for something that should trigger a skill (for example, "help me plan this feature" or "let's debug this issue"). The agent should automatically invoke the relevant superpowers skill.
|
||||
|
||||
## The Basic Workflow
|
||||
|
||||
1. **brainstorming** - Activates before writing code. Refines rough ideas through questions, explores alternatives, presents design in sections for validation. Saves design document.
|
||||
|
||||
173
RELEASE-NOTES.md
173
RELEASE-NOTES.md
@@ -4,25 +4,6 @@
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
**Specs and plans directory restructured**
|
||||
|
||||
- Specs (brainstorming output) now go to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`
|
||||
- Plans (writing-plans output) now go to `docs/superpowers/plans/YYYY-MM-DD-<feature-name>.md`
|
||||
- User preferences for spec/plan locations override these defaults
|
||||
- Migration: move existing files from `docs/plans/` to new locations if desired
|
||||
|
||||
**Brainstorming → writing-plans transition enforced**
|
||||
|
||||
- After design approval, brainstorming now requires using writing-plans skill
|
||||
- Platform planning features (e.g., EnterPlanMode) should not be used
|
||||
- Direct implementation without writing-plans is not allowed
|
||||
|
||||
**Subagent-driven development now mandatory on capable harnesses**
|
||||
|
||||
- On harnesses with subagent support (Claude Code), subagent-driven-development is now required after plan approval
|
||||
- No longer offers a choice between subagent-driven and executing-plans
|
||||
- Executing-plans is only used on harnesses without subagent capability
|
||||
|
||||
**OpenCode: Switched to native skills system**
|
||||
|
||||
Superpowers for OpenCode now uses OpenCode's native `skill` tool instead of custom `use_skill`/`find_skills` tools. This is a cleaner integration that works with OpenCode's built-in skill discovery.
|
||||
@@ -63,19 +44,11 @@ Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh
|
||||
|
||||
Fix: hooks.json now calls session-start.sh directly. Claude Code 2.1.x handles the bash invocation automatically. Also added .gitattributes to enforce LF line endings for shell scripts (fixes CRLF issues on Windows checkout).
|
||||
|
||||
**Brainstorming visual companion: reduced token cost and improved persistence**
|
||||
**Fixed Windows Codex launcher (#243, #285)**
|
||||
|
||||
The visual companion now generates much smaller HTML per screen. The server automatically wraps bare content fragments in the frame template (header, CSS theme, feedback footer, interactive JS), so Claude writes only the content portion (~30 lines instead of ~260). Full HTML documents are still served as-is when Claude needs complete control.
|
||||
Windows cannot execute extensionless scripts with shebangs, so the `superpowers-codex` script would either open an "Open with" dialog or produce no output in PowerShell.
|
||||
|
||||
Other improvements:
|
||||
- `toggleSelect`/`send`/`selectedChoice` moved from inline template script to `helper.js` (auto-injected)
|
||||
- `start-server.sh --project-dir` persists mockups under `.superpowers/brainstorm/` instead of `/tmp`
|
||||
- `stop-server.sh` only deletes ephemeral `/tmp` sessions, preserving persistent ones
|
||||
- Dark mode fix: `sendToClaude` confirmation page now uses CSS variables instead of hardcoded colors
|
||||
- Skill restructured: SKILL.md is minimal (prompt + pointer); all visual companion details in progressive disclosure doc (`visual-companion.md`)
|
||||
- Prompt to user now notes the feature is new, token-intensive, and can be slow
|
||||
- Deleted redundant `CLAUDE-INSTRUCTIONS.md` (content folded into `visual-companion.md`)
|
||||
- Test fixes: correct env var (`BRAINSTORM_DIR`), polling-based startup wait, new tests for frame wrapping
|
||||
Fix: Added `.codex/superpowers-codex.cmd` wrapper that invokes Node.js directly. Updated docs with Windows-specific installation and usage instructions.
|
||||
|
||||
### Improvements
|
||||
|
||||
@@ -89,146 +62,6 @@ Added explicit instruction priority hierarchy to prevent conflicts with user pre
|
||||
|
||||
This ensures users remain in control. If CLAUDE.md says "don't use TDD" and a skill says "always use TDD," CLAUDE.md wins.
|
||||
|
||||
## v4.3.0 (2026-02-12)
|
||||
|
||||
This fix should dramatically improve superpowers skills compliance and should reduce the chances of Claude entering its native plan mode unintentionally.
|
||||
|
||||
### Changed
|
||||
|
||||
**Brainstorming skill now enforces its workflow instead of describing it**
|
||||
|
||||
Models were skipping the design phase and jumping straight to implementation skills like frontend-design, or collapsing the entire brainstorming process into a single text block. The skill now uses hard gates, a mandatory checklist, and a graphviz process flow to enforce compliance:
|
||||
|
||||
- `<HARD-GATE>`: no implementation skills, code, or scaffolding until design is presented and user approves
|
||||
- Explicit checklist (6 items) that must be created as tasks and completed in order
|
||||
- Graphviz process flow with `writing-plans` as the only valid terminal state
|
||||
- Anti-pattern callout for "this is too simple to need a design" — the exact rationalization models use to skip the process
|
||||
- Design section sizing based on section complexity, not project complexity
|
||||
|
||||
**Using-superpowers workflow graph intercepts EnterPlanMode**
|
||||
|
||||
Added an `EnterPlanMode` intercept to the skill flow graph. When the model is about to enter Claude's native plan mode, it checks whether brainstorming has happened and routes through the brainstorming skill instead. Plan mode is never entered.
|
||||
|
||||
### Fixed
|
||||
|
||||
**SessionStart hook now runs synchronously**
|
||||
|
||||
Changed `async: true` to `async: false` in hooks.json. When async, the hook could fail to complete before the model's first turn, meaning using-superpowers instructions weren't in context for the first message.
|
||||
|
||||
## v4.2.0 (2026-02-05)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
**Codex: Replaced bootstrap CLI with native skill discovery**
|
||||
|
||||
The `superpowers-codex` bootstrap CLI, Windows `.cmd` wrapper, and related bootstrap content file have been removed. Codex now uses native skill discovery via `~/.agents/skills/superpowers/` symlink, so the old `use_skill`/`find_skills` CLI tools are no longer needed.
|
||||
|
||||
Installation is now just clone + symlink (documented in INSTALL.md). No Node.js dependency required. The old `~/.codex/skills/` path is deprecated.
|
||||
|
||||
### Fixes
|
||||
|
||||
**Windows: Fixed Claude Code 2.1.x hook execution (#331)**
|
||||
|
||||
Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh` files in commands and prepends `bash`. This broke the polyglot wrapper pattern because `bash "run-hook.cmd" session-start.sh` tries to execute the `.cmd` file as a bash script.
|
||||
|
||||
Fix: hooks.json now calls session-start.sh directly. Claude Code 2.1.x handles the bash invocation automatically. Also added .gitattributes to enforce LF line endings for shell scripts (fixes CRLF issues on Windows checkout).
|
||||
|
||||
**Windows: SessionStart hook runs async to prevent terminal freeze (#404, #413, #414, #419)**
|
||||
|
||||
The synchronous SessionStart hook blocked the TUI from entering raw mode on Windows, freezing all keyboard input. Running the hook async prevents the freeze while still injecting superpowers context.
|
||||
|
||||
**Windows: Fixed O(n^2) `escape_for_json` performance**
|
||||
|
||||
The character-by-character loop using `${input:$i:1}` was O(n^2) in bash due to substring copy overhead. On Windows Git Bash this took 60+ seconds. Replaced with bash parameter substitution (`${s//old/new}`) which runs each pattern as a single C-level pass — 7x faster on macOS, dramatically faster on Windows.
|
||||
|
||||
**Codex: Fixed Windows/PowerShell invocation (#285, #243)**
|
||||
|
||||
- Windows doesn't respect shebangs, so directly invoking the extensionless `superpowers-codex` script triggered an "Open with" dialog. All invocations now prefixed with `node`.
|
||||
- Fixed `~/` path expansion on Windows — PowerShell doesn't expand `~` when passed as an argument to `node`. Changed to `$HOME` which expands correctly in both bash and PowerShell.
|
||||
|
||||
**Codex: Fixed path resolution in installer**
|
||||
|
||||
Used `fileURLToPath()` instead of manual URL pathname parsing to correctly handle paths with spaces and special characters on all platforms.
|
||||
|
||||
**Codex: Fixed stale skills path in writing-skills**
|
||||
|
||||
Updated `~/.codex/skills/` reference (deprecated) to `~/.agents/skills/` for native discovery.
|
||||
|
||||
### Improvements
|
||||
|
||||
**Worktree isolation now required before implementation**
|
||||
|
||||
Added `using-git-worktrees` as a required skill for both `subagent-driven-development` and `executing-plans`. Implementation workflows now explicitly require setting up an isolated worktree before starting work, preventing accidental work directly on main.
|
||||
|
||||
**Main branch protection softened to require explicit consent**
|
||||
|
||||
Instead of prohibiting main branch work entirely, the skills now allow it with explicit user consent. More flexible while still ensuring users are aware of the implications.
|
||||
|
||||
**Simplified installation verification**
|
||||
|
||||
Removed `/help` command check and specific slash command list from verification steps. Skills are primarily invoked by describing what you want to do, not by running specific commands.
|
||||
|
||||
**Codex: Clarified subagent tool mapping in bootstrap**
|
||||
|
||||
Improved documentation of how Codex tools map to Claude Code equivalents for subagent workflows.
|
||||
|
||||
### Tests
|
||||
|
||||
- Added worktree requirement test for subagent-driven-development
|
||||
- Added main branch red flag warning test
|
||||
- Fixed case sensitivity in skill recognition test assertions
|
||||
|
||||
---
|
||||
|
||||
## v4.1.1 (2026-01-23)
|
||||
|
||||
### Fixes
|
||||
|
||||
**OpenCode: Standardized on `plugins/` directory per official docs (#343)**
|
||||
|
||||
OpenCode's official documentation uses `~/.config/opencode/plugins/` (plural). Our docs previously used `plugin/` (singular). While OpenCode accepts both forms, we've standardized on the official convention to avoid confusion.
|
||||
|
||||
Changes:
|
||||
- Renamed `.opencode/plugin/` to `.opencode/plugins/` in repo structure
|
||||
- Updated all installation docs (INSTALL.md, README.opencode.md) across all platforms
|
||||
- Updated test scripts to match
|
||||
|
||||
**OpenCode: Fixed symlink instructions (#339, #342)**
|
||||
|
||||
- Added explicit `rm` before `ln -s` (fixes "file already exists" errors on reinstall)
|
||||
- Added missing skills symlink step that was absent from INSTALL.md
|
||||
- Updated from deprecated `use_skill`/`find_skills` to native `skill` tool references
|
||||
|
||||
---
|
||||
|
||||
## v4.1.0 (2026-01-23)
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
**OpenCode: Switched to native skills system**
|
||||
|
||||
Superpowers for OpenCode now uses OpenCode's native `skill` tool instead of custom `use_skill`/`find_skills` tools. This is a cleaner integration that works with OpenCode's built-in skill discovery.
|
||||
|
||||
**Migration required:** Skills must be symlinked to `~/.config/opencode/skills/superpowers/` (see updated installation docs).
|
||||
|
||||
### Fixes
|
||||
|
||||
**OpenCode: Fixed agent reset on session start (#226)**
|
||||
|
||||
The previous bootstrap injection method using `session.prompt({ noReply: true })` caused OpenCode to reset the selected agent to "build" on first message. Now uses `experimental.chat.system.transform` hook which modifies the system prompt directly without side effects.
|
||||
|
||||
**OpenCode: Fixed Windows installation (#232)**
|
||||
|
||||
- Removed dependency on `skills-core.js` (eliminates broken relative imports when file is copied instead of symlinked)
|
||||
- Added comprehensive Windows installation docs for cmd.exe, PowerShell, and Git Bash
|
||||
- Documented proper symlink vs junction usage for each platform
|
||||
|
||||
**Claude Code: Fixed Windows hook execution for Claude Code 2.1.x**
|
||||
|
||||
Claude Code 2.1.x changed how hooks execute on Windows: it now auto-detects `.sh` files in commands and prepends `bash `. This broke the polyglot wrapper pattern because `bash "run-hook.cmd" session-start.sh` tries to execute the .cmd file as a bash script.
|
||||
|
||||
Fix: hooks.json now calls session-start.sh directly. Claude Code 2.1.x handles the bash invocation automatically. Also added .gitattributes to enforce LF line endings for shell scripts (fixes CRLF issues on Windows checkout).
|
||||
|
||||
---
|
||||
|
||||
## v4.0.3 (2025-12-26)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Superpowers for Codex
|
||||
|
||||
Guide for using Superpowers with OpenAI Codex via native skill discovery.
|
||||
Complete guide for using Superpowers with OpenAI Codex.
|
||||
|
||||
## Quick Install
|
||||
|
||||
@@ -14,65 +14,85 @@ Fetch and follow instructions from https://raw.githubusercontent.com/obra/superp
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- OpenAI Codex CLI
|
||||
- Git
|
||||
- OpenAI Codex access
|
||||
- Shell access to install files
|
||||
|
||||
### Steps
|
||||
### Installation Steps
|
||||
|
||||
1. Clone the repo:
|
||||
```bash
|
||||
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
|
||||
```
|
||||
#### macOS / Linux
|
||||
|
||||
2. Create the skills symlink:
|
||||
```bash
|
||||
mkdir -p ~/.agents/skills
|
||||
ln -s ~/.codex/superpowers/skills ~/.agents/skills/superpowers
|
||||
```
|
||||
```bash
|
||||
mkdir -p ~/.codex/superpowers
|
||||
git clone https://github.com/obra/superpowers.git ~/.codex/superpowers
|
||||
```
|
||||
|
||||
3. Restart Codex.
|
||||
#### Windows
|
||||
|
||||
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):
|
||||
**Command Prompt:**
|
||||
```cmd
|
||||
mkdir "%USERPROFILE%\.codex\superpowers"
|
||||
git clone https://github.com/obra/superpowers.git "%USERPROFILE%\.codex\superpowers"
|
||||
```
|
||||
|
||||
**PowerShell:**
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.agents\skills"
|
||||
cmd /c mklink /J "$env:USERPROFILE\.agents\skills\superpowers" "$env:USERPROFILE\.codex\superpowers\skills"
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.codex\superpowers"
|
||||
git clone https://github.com/obra/superpowers.git "$env:USERPROFILE\.codex\superpowers"
|
||||
```
|
||||
|
||||
## How It Works
|
||||
#### 2. Install Bootstrap
|
||||
|
||||
Codex has native skill discovery — it scans `~/.agents/skills/` at startup, parses SKILL.md frontmatter, and loads skills on demand. Superpowers skills are made visible through a single symlink:
|
||||
The bootstrap file is included in the repository at `.codex/superpowers-bootstrap.md`. Codex will automatically use it from the cloned location.
|
||||
|
||||
#### 3. Verify Installation
|
||||
|
||||
Tell Codex:
|
||||
|
||||
**macOS / Linux:**
|
||||
```
|
||||
~/.agents/skills/superpowers/ → ~/.codex/superpowers/skills/
|
||||
Run ~/.codex/superpowers/.codex/superpowers-codex find-skills to show available skills
|
||||
```
|
||||
|
||||
The `using-superpowers` skill is discovered automatically and enforces skill usage discipline — no additional configuration needed.
|
||||
**Windows:**
|
||||
```
|
||||
Run ~/.codex/superpowers/.codex/superpowers-codex.cmd find-skills to show available skills
|
||||
```
|
||||
|
||||
You should see a list of available skills with descriptions.
|
||||
|
||||
> **Note:** On Windows, always use the `.cmd` extension when running superpowers-codex commands.
|
||||
|
||||
## Usage
|
||||
|
||||
Skills are discovered automatically. Codex activates them when:
|
||||
- You mention a skill by name (e.g., "use brainstorming")
|
||||
- The task matches a skill's description
|
||||
- The `using-superpowers` skill directs Codex to use one
|
||||
### Finding Skills
|
||||
|
||||
```
|
||||
Run ~/.codex/superpowers/.codex/superpowers-codex find-skills
|
||||
```
|
||||
|
||||
### Loading a Skill
|
||||
|
||||
```
|
||||
Run ~/.codex/superpowers/.codex/superpowers-codex use-skill superpowers:brainstorming
|
||||
```
|
||||
|
||||
### Bootstrap All Skills
|
||||
|
||||
```
|
||||
Run ~/.codex/superpowers/.codex/superpowers-codex bootstrap
|
||||
```
|
||||
|
||||
This loads the complete bootstrap with all skill information.
|
||||
|
||||
### Personal Skills
|
||||
|
||||
Create your own skills in `~/.agents/skills/`:
|
||||
Create your own skills in `~/.codex/skills/`:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.agents/skills/my-skill
|
||||
mkdir -p ~/.codex/skills/my-skill
|
||||
```
|
||||
|
||||
Create `~/.agents/skills/my-skill/SKILL.md`:
|
||||
Create `~/.codex/skills/my-skill/SKILL.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
@@ -85,42 +105,85 @@ description: Use when [condition] - [what it does]
|
||||
[Your skill content here]
|
||||
```
|
||||
|
||||
The `description` field is how Codex decides when to activate a skill automatically — write it as a clear trigger condition.
|
||||
Personal skills override superpowers skills with the same name.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Codex CLI Tool
|
||||
|
||||
**Location:** `~/.codex/superpowers/.codex/superpowers-codex`
|
||||
|
||||
A Node.js CLI script that provides three commands:
|
||||
- `bootstrap` - Load complete bootstrap with all skills
|
||||
- `use-skill <name>` - Load a specific skill
|
||||
- `find-skills` - List all available skills
|
||||
|
||||
### Shared Core Module
|
||||
|
||||
**Location:** `~/.codex/superpowers/lib/skills-core.js`
|
||||
|
||||
The Codex implementation uses the shared `skills-core` module (ES module format) for skill discovery and parsing. This is the same module used by the OpenCode plugin, ensuring consistent behavior across platforms.
|
||||
|
||||
### Tool Mapping
|
||||
|
||||
Skills written for Claude Code are adapted for Codex with these mappings:
|
||||
|
||||
- `TodoWrite` → `update_plan`
|
||||
- `Task` with subagents → Tell user subagents aren't available, do work directly
|
||||
- `Skill` tool → `~/.codex/superpowers/.codex/superpowers-codex use-skill`
|
||||
- File operations → Native Codex tools
|
||||
|
||||
## Updating
|
||||
|
||||
```bash
|
||||
cd ~/.codex/superpowers && git pull
|
||||
cd ~/.codex/superpowers
|
||||
git pull
|
||||
```
|
||||
|
||||
Skills update instantly through the symlink.
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
rm ~/.agents/skills/superpowers
|
||||
```
|
||||
|
||||
**Windows (PowerShell):**
|
||||
```powershell
|
||||
Remove-Item "$env:USERPROFILE\.agents\skills\superpowers"
|
||||
```
|
||||
|
||||
Optionally delete the clone: `rm -rf ~/.codex/superpowers` (Windows: `Remove-Item -Recurse -Force "$env:USERPROFILE\.codex\superpowers"`).
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skills not showing up
|
||||
### Skills not found
|
||||
|
||||
1. Verify the symlink: `ls -la ~/.agents/skills/superpowers`
|
||||
2. Check skills exist: `ls ~/.codex/superpowers/skills`
|
||||
3. Restart Codex — skills are discovered at startup
|
||||
1. Verify installation: `ls ~/.codex/superpowers/skills`
|
||||
2. Check CLI works: `~/.codex/superpowers/.codex/superpowers-codex find-skills`
|
||||
3. Verify skills have SKILL.md files
|
||||
|
||||
### Windows junction issues
|
||||
### CLI script not executable (macOS/Linux)
|
||||
|
||||
Junctions normally work without special permissions. If creation fails, try running PowerShell as administrator.
|
||||
```bash
|
||||
chmod +x ~/.codex/superpowers/.codex/superpowers-codex
|
||||
```
|
||||
|
||||
### Windows: "Open with" dialog or no output
|
||||
|
||||
On Windows, you must use the `.cmd` wrapper:
|
||||
|
||||
```cmd
|
||||
~/.codex/superpowers/.codex/superpowers-codex.cmd find-skills
|
||||
```
|
||||
|
||||
Or invoke with Node directly:
|
||||
|
||||
```cmd
|
||||
node "%USERPROFILE%\.codex\superpowers\.codex\superpowers-codex" find-skills
|
||||
```
|
||||
|
||||
### Node.js errors
|
||||
|
||||
The CLI script requires Node.js. Verify:
|
||||
|
||||
```bash
|
||||
node --version
|
||||
```
|
||||
|
||||
Should show v14 or higher (v18+ recommended).
|
||||
|
||||
## Getting Help
|
||||
|
||||
- Report issues: https://github.com/obra/superpowers/issues
|
||||
- Main documentation: https://github.com/obra/superpowers
|
||||
- Blog post: https://blog.fsck.com/2025/10/27/skills-for-openai-codex/
|
||||
|
||||
## Note
|
||||
|
||||
Codex support is experimental and may require refinement based on user feedback. If you encounter issues, please report them on GitHub.
|
||||
|
||||
@@ -7,7 +7,7 @@ Complete guide for using Superpowers with [OpenCode.ai](https://opencode.ai).
|
||||
Tell OpenCode:
|
||||
|
||||
```
|
||||
Clone https://github.com/obra/superpowers to ~/.config/opencode/superpowers, then create directory ~/.config/opencode/plugins, then symlink ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js to ~/.config/opencode/plugins/superpowers.js, then symlink ~/.config/opencode/superpowers/skills to ~/.config/opencode/skills/superpowers, then restart opencode.
|
||||
Clone https://github.com/obra/superpowers to ~/.config/opencode/superpowers, then create directory ~/.config/opencode/plugin, then symlink ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js to ~/.config/opencode/plugin/superpowers.js, then symlink ~/.config/opencode/superpowers/skills to ~/.config/opencode/skills/superpowers, then restart opencode.
|
||||
```
|
||||
|
||||
## Manual Installation
|
||||
@@ -28,23 +28,19 @@ else
|
||||
fi
|
||||
|
||||
# 2. Create directories
|
||||
mkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills
|
||||
mkdir -p ~/.config/opencode/plugin ~/.config/opencode/skills
|
||||
|
||||
# 3. Remove old symlinks/directories if they exist
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js
|
||||
rm -rf ~/.config/opencode/skills/superpowers
|
||||
# 3. Create symlinks (safe for reinstalls - ln -sf overwrites)
|
||||
ln -sf ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js ~/.config/opencode/plugin/superpowers.js
|
||||
ln -sf ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
|
||||
# 4. Create symlinks
|
||||
ln -s ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js ~/.config/opencode/plugins/superpowers.js
|
||||
ln -s ~/.config/opencode/superpowers/skills ~/.config/opencode/skills/superpowers
|
||||
|
||||
# 5. Restart OpenCode
|
||||
# 4. Restart OpenCode
|
||||
```
|
||||
|
||||
#### Verify Installation
|
||||
|
||||
```bash
|
||||
ls -l ~/.config/opencode/plugins/superpowers.js
|
||||
ls -l ~/.config/opencode/plugin/superpowers.js
|
||||
ls -l ~/.config/opencode/skills/superpowers
|
||||
```
|
||||
|
||||
@@ -69,15 +65,15 @@ Run as Administrator, or with Developer Mode enabled:
|
||||
git clone https://github.com/obra/superpowers.git "%USERPROFILE%\.config\opencode\superpowers"
|
||||
|
||||
:: 2. Create directories
|
||||
mkdir "%USERPROFILE%\.config\opencode\plugins" 2>nul
|
||||
mkdir "%USERPROFILE%\.config\opencode\plugin" 2>nul
|
||||
mkdir "%USERPROFILE%\.config\opencode\skills" 2>nul
|
||||
|
||||
:: 3. Remove existing links (safe for reinstalls)
|
||||
del "%USERPROFILE%\.config\opencode\plugins\superpowers.js" 2>nul
|
||||
del "%USERPROFILE%\.config\opencode\plugin\superpowers.js" 2>nul
|
||||
rmdir "%USERPROFILE%\.config\opencode\skills\superpowers" 2>nul
|
||||
|
||||
:: 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
mklink "%USERPROFILE%\.config\opencode\plugins\superpowers.js" "%USERPROFILE%\.config\opencode\superpowers\.opencode\plugins\superpowers.js"
|
||||
mklink "%USERPROFILE%\.config\opencode\plugin\superpowers.js" "%USERPROFILE%\.config\opencode\superpowers\.opencode\plugin\superpowers.js"
|
||||
|
||||
:: 5. Create skills junction (works without special privileges)
|
||||
mklink /J "%USERPROFILE%\.config\opencode\skills\superpowers" "%USERPROFILE%\.config\opencode\superpowers\skills"
|
||||
@@ -94,15 +90,15 @@ Run as Administrator, or with Developer Mode enabled:
|
||||
git clone https://github.com/obra/superpowers.git "$env:USERPROFILE\.config\opencode\superpowers"
|
||||
|
||||
# 2. Create directories
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\plugins"
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\plugin"
|
||||
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.config\opencode\skills"
|
||||
|
||||
# 3. Remove existing links (safe for reinstalls)
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\plugins\superpowers.js" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\plugin\superpowers.js" -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item "$env:USERPROFILE\.config\opencode\skills\superpowers" -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.config\opencode\plugins\superpowers.js" -Target "$env:USERPROFILE\.config\opencode\superpowers\.opencode\plugins\superpowers.js"
|
||||
New-Item -ItemType SymbolicLink -Path "$env:USERPROFILE\.config\opencode\plugin\superpowers.js" -Target "$env:USERPROFILE\.config\opencode\superpowers\.opencode\plugin\superpowers.js"
|
||||
|
||||
# 5. Create skills junction (works without special privileges)
|
||||
New-Item -ItemType Junction -Path "$env:USERPROFILE\.config\opencode\skills\superpowers" -Target "$env:USERPROFILE\.config\opencode\superpowers\skills"
|
||||
@@ -119,14 +115,14 @@ Note: Git Bash's native `ln` command copies files instead of creating symlinks.
|
||||
git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
|
||||
|
||||
# 2. Create directories
|
||||
mkdir -p ~/.config/opencode/plugins ~/.config/opencode/skills
|
||||
mkdir -p ~/.config/opencode/plugin ~/.config/opencode/skills
|
||||
|
||||
# 3. Remove existing links (safe for reinstalls)
|
||||
rm -f ~/.config/opencode/plugins/superpowers.js 2>/dev/null
|
||||
rm -f ~/.config/opencode/plugin/superpowers.js 2>/dev/null
|
||||
rm -rf ~/.config/opencode/skills/superpowers 2>/dev/null
|
||||
|
||||
# 4. Create plugin symlink (requires Developer Mode or Admin)
|
||||
cmd //c "mklink \"$(cygpath -w ~/.config/opencode/plugins/superpowers.js)\" \"$(cygpath -w ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js)\""
|
||||
cmd //c "mklink \"$(cygpath -w ~/.config/opencode/plugin/superpowers.js)\" \"$(cygpath -w ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js)\""
|
||||
|
||||
# 5. Create skills junction (works without special privileges)
|
||||
cmd //c "mklink /J \"$(cygpath -w ~/.config/opencode/skills/superpowers)\" \"$(cygpath -w ~/.config/opencode/superpowers/skills)\""
|
||||
@@ -142,13 +138,13 @@ If running OpenCode inside WSL, use the [macOS / Linux](#macos--linux) instructi
|
||||
|
||||
**Command Prompt:**
|
||||
```cmd
|
||||
dir /AL "%USERPROFILE%\.config\opencode\plugins"
|
||||
dir /AL "%USERPROFILE%\.config\opencode\plugin"
|
||||
dir /AL "%USERPROFILE%\.config\opencode\skills"
|
||||
```
|
||||
|
||||
**PowerShell:**
|
||||
```powershell
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\plugins" | Where-Object { $_.LinkType }
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\plugin" | Where-Object { $_.LinkType }
|
||||
Get-ChildItem "$env:USERPROFILE\.config\opencode\skills" | Where-Object { $_.LinkType }
|
||||
```
|
||||
|
||||
@@ -258,7 +254,7 @@ Skills written for Claude Code are automatically adapted for OpenCode. The boots
|
||||
|
||||
### Plugin Structure
|
||||
|
||||
**Location:** `~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
**Location:** `~/.config/opencode/superpowers/.opencode/plugin/superpowers.js`
|
||||
|
||||
**Components:**
|
||||
- `experimental.chat.system.transform` hook for bootstrap injection
|
||||
@@ -283,8 +279,8 @@ Restart OpenCode to load the updates.
|
||||
|
||||
### Plugin not loading
|
||||
|
||||
1. Check plugin exists: `ls ~/.config/opencode/superpowers/.opencode/plugins/superpowers.js`
|
||||
2. Check symlink/junction: `ls -l ~/.config/opencode/plugins/` (macOS/Linux) or `dir /AL %USERPROFILE%\.config\opencode\plugins` (Windows)
|
||||
1. Check plugin exists: `ls ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js`
|
||||
2. Check symlink/junction: `ls -l ~/.config/opencode/plugin/` (macOS/Linux) or `dir /AL %USERPROFILE%\.config\opencode\plugin` (Windows)
|
||||
3. Check OpenCode logs: `opencode run "test" --print-logs --log-level DEBUG`
|
||||
4. Look for plugin loading message in logs
|
||||
|
||||
|
||||
@@ -1,301 +0,0 @@
|
||||
# Document Review System Implementation Plan
|
||||
|
||||
> **For Claude:** 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 Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Tasks and steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
```
|
||||
|
||||
- [ ] **Step 3:** Verify the change
|
||||
|
||||
Run: `grep -A 5 "For Claude:" 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"
|
||||
```
|
||||
@@ -1,523 +0,0 @@
|
||||
# Visual Brainstorming Refactor Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**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
|
||||
```
|
||||
@@ -1,136 +0,0 @@
|
||||
# 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
|
||||
@@ -1,162 +0,0 @@
|
||||
# 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.
|
||||
@@ -6,8 +6,7 @@
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/run-hook.cmd session-start",
|
||||
"async": false
|
||||
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/session-start.sh"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,46 +1,43 @@
|
||||
: << 'CMDBLOCK'
|
||||
@echo off
|
||||
REM Cross-platform polyglot wrapper for hook scripts.
|
||||
REM On Windows: cmd.exe runs the batch portion, which finds and calls bash.
|
||||
REM On Unix: the shell interprets this as a script (: is a no-op in bash).
|
||||
REM ============================================================================
|
||||
REM DEPRECATED: This polyglot wrapper is no longer used as of Claude Code 2.1.x
|
||||
REM ============================================================================
|
||||
REM
|
||||
REM Hook scripts use extensionless filenames (e.g. "session-start" not
|
||||
REM "session-start.sh") so Claude Code's Windows auto-detection -- which
|
||||
REM prepends "bash" to any command containing .sh -- doesn't interfere.
|
||||
REM Claude Code 2.1.x changed the Windows execution model for hooks:
|
||||
REM
|
||||
REM Before (2.0.x): Hooks ran with shell:true, using the system default shell.
|
||||
REM This wrapper provided cross-platform compatibility by
|
||||
REM being both a valid .cmd file (Windows) and bash script.
|
||||
REM
|
||||
REM After (2.1.x): Claude Code now auto-detects .sh files in hook commands
|
||||
REM and prepends "bash " on Windows. This broke the wrapper
|
||||
REM because the command:
|
||||
REM "run-hook.cmd" session-start.sh
|
||||
REM became:
|
||||
REM bash "run-hook.cmd" session-start.sh
|
||||
REM ...and bash cannot execute a .cmd file.
|
||||
REM
|
||||
REM The fix: hooks.json now calls session-start.sh directly. Claude Code 2.1.x
|
||||
REM handles the bash invocation automatically on Windows.
|
||||
REM
|
||||
REM This file is kept for reference and potential backward compatibility.
|
||||
REM ============================================================================
|
||||
REM
|
||||
REM Original purpose: Polyglot wrapper to run .sh scripts cross-platform
|
||||
REM Usage: run-hook.cmd <script-name> [args...]
|
||||
REM The script should be in the same directory as this wrapper
|
||||
|
||||
if "%~1"=="" (
|
||||
echo run-hook.cmd: missing script name >&2
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "HOOK_DIR=%~dp0"
|
||||
|
||||
REM Try Git for Windows bash in standard locations
|
||||
if exist "C:\Program Files\Git\bin\bash.exe" (
|
||||
"C:\Program Files\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
if exist "C:\Program Files (x86)\Git\bin\bash.exe" (
|
||||
"C:\Program Files (x86)\Git\bin\bash.exe" "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
REM Try bash on PATH (e.g. user-installed Git Bash, MSYS2, Cygwin)
|
||||
where bash >nul 2>nul
|
||||
if %ERRORLEVEL% equ 0 (
|
||||
bash "%HOOK_DIR%%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
||||
exit /b %ERRORLEVEL%
|
||||
)
|
||||
|
||||
REM No bash found - exit silently rather than error
|
||||
REM (plugin still works, just without SessionStart context injection)
|
||||
exit /b 0
|
||||
"C:\Program Files\Git\bin\bash.exe" -l "%~dp0%~1" %2 %3 %4 %5 %6 %7 %8 %9
|
||||
exit /b
|
||||
CMDBLOCK
|
||||
|
||||
# Unix: run the named script directly
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
|
||||
# Unix shell runs from here
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT_NAME="$1"
|
||||
shift
|
||||
exec bash "${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
||||
"${SCRIPT_DIR}/${SCRIPT_NAME}" "$@"
|
||||
|
||||
@@ -17,33 +17,34 @@ fi
|
||||
# Read using-superpowers content
|
||||
using_superpowers_content=$(cat "${PLUGIN_ROOT}/skills/using-superpowers/SKILL.md" 2>&1 || echo "Error reading using-superpowers skill")
|
||||
|
||||
# Escape string for JSON embedding using bash parameter substitution.
|
||||
# Each ${s//old/new} is a single C-level pass - orders of magnitude
|
||||
# faster than the character-by-character loop this replaces.
|
||||
# Escape outputs for JSON using pure bash
|
||||
escape_for_json() {
|
||||
local s="$1"
|
||||
s="${s//\\/\\\\}"
|
||||
s="${s//\"/\\\"}"
|
||||
s="${s//$'\n'/\\n}"
|
||||
s="${s//$'\r'/\\r}"
|
||||
s="${s//$'\t'/\\t}"
|
||||
printf '%s' "$s"
|
||||
local input="$1"
|
||||
local output=""
|
||||
local i char
|
||||
for (( i=0; i<${#input}; i++ )); do
|
||||
char="${input:$i:1}"
|
||||
case "$char" in
|
||||
$'\\') output+='\\' ;;
|
||||
'"') output+='\"' ;;
|
||||
$'\n') output+='\n' ;;
|
||||
$'\r') output+='\r' ;;
|
||||
$'\t') output+='\t' ;;
|
||||
*) output+="$char" ;;
|
||||
esac
|
||||
done
|
||||
printf '%s' "$output"
|
||||
}
|
||||
|
||||
using_superpowers_escaped=$(escape_for_json "$using_superpowers_content")
|
||||
warning_escaped=$(escape_for_json "$warning_message")
|
||||
session_context="<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
|
||||
|
||||
# Output context injection as JSON.
|
||||
# Keep both shapes for compatibility:
|
||||
# - Cursor hooks expect additional_context.
|
||||
# - Claude hooks expect hookSpecificOutput.additionalContext.
|
||||
# Output context injection as JSON
|
||||
cat <<EOF
|
||||
{
|
||||
"additional_context": "${session_context}",
|
||||
"hookSpecificOutput": {
|
||||
"hookEventName": "SessionStart",
|
||||
"additionalContext": "${session_context}"
|
||||
"additionalContext": "<EXTREMELY_IMPORTANT>\nYou have superpowers.\n\n**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'Skill' tool:**\n\n${using_superpowers_escaped}\n\n${warning_escaped}\n</EXTREMELY_IMPORTANT>"
|
||||
}
|
||||
}
|
||||
EOF
|
||||
212
lib/brainstorm-server/CLAUDE-INSTRUCTIONS.md
Normal file
212
lib/brainstorm-server/CLAUDE-INSTRUCTIONS.md
Normal file
@@ -0,0 +1,212 @@
|
||||
# Visual Companion Instructions for Claude
|
||||
|
||||
This document explains how to use the brainstorm visual companion to show mockups, designs, and options to users without resorting to ASCII art.
|
||||
|
||||
## When to Use
|
||||
|
||||
Use the visual companion when you need to show:
|
||||
- **UI mockups** - layouts, navigation patterns, component designs
|
||||
- **Design comparisons** - "Which of these 3 approaches works better?"
|
||||
- **Interactive prototypes** - clickable wireframes
|
||||
- **Visual choices** - anything where seeing beats describing
|
||||
|
||||
**Don't use it for:** simple text questions, code review, or when the user prefers terminal-only interaction.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
```bash
|
||||
# Start server (returns JSON with URL and session directory)
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh
|
||||
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
|
||||
# "screen_dir":"/tmp/brainstorm-12345-1234567890"}
|
||||
|
||||
# Save screen_dir from response!
|
||||
|
||||
# Tell user to open the URL in their browser
|
||||
|
||||
# For each screen:
|
||||
# 1. Start watcher in background FIRST (avoids race condition)
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/wait-for-feedback.sh $SCREEN_DIR
|
||||
# 2. Write HTML to a NEW file in screen_dir (e.g., platform.html, style.html)
|
||||
# Server automatically serves the newest file by modification time
|
||||
# 3. Call TaskOutput(task_id, block=true, timeout=600000) to wait for feedback
|
||||
|
||||
# When done, stop server (pass screen_dir)
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/stop-server.sh $SCREEN_DIR
|
||||
```
|
||||
|
||||
## File Naming
|
||||
|
||||
- **Use semantic names**: `platform.html`, `visual-style.html`, `layout.html`, `controls.html`
|
||||
- **Never reuse filenames** - each screen must be a new file
|
||||
- **For iterations**: append version suffix like `layout-v2.html`, `layout-v3.html`
|
||||
- Server automatically serves the newest `.html` file by modification time
|
||||
|
||||
## Writing Screens
|
||||
|
||||
Copy the frame template structure but replace `#claude-content` with your content:
|
||||
|
||||
```html
|
||||
<div id="claude-content">
|
||||
<h2>Your Question</h2>
|
||||
<p class="subtitle">Brief context</p>
|
||||
|
||||
<!-- Your content here -->
|
||||
</div>
|
||||
```
|
||||
|
||||
The frame template (`frame-template.html`) includes CSS for:
|
||||
- OS-aware light/dark theming
|
||||
- Fixed header and feedback footer
|
||||
- Common UI patterns (see below)
|
||||
|
||||
## CSS Helper Classes
|
||||
|
||||
### 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>Option Title</h3>
|
||||
<p>Description of this option</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- More options... -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Cards (visual designs)
|
||||
|
||||
```html
|
||||
<div class="cards">
|
||||
<div class="card" data-choice="design1" onclick="toggleSelect(this)">
|
||||
<div class="card-image">
|
||||
<!-- Put mockup content here -->
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Design Name</h3>
|
||||
<p>Brief 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 side --></div>
|
||||
<div class="mockup"><!-- Right side --></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Pros/Cons
|
||||
|
||||
```html
|
||||
<div class="pros-cons">
|
||||
<div class="pros">
|
||||
<h4>Pros</h4>
|
||||
<ul>
|
||||
<li>Benefit one</li>
|
||||
<li>Benefit two</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="cons">
|
||||
<h4>Cons</h4>
|
||||
<ul>
|
||||
<li>Drawback one</li>
|
||||
<li>Drawback two</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Inline Mockup Elements
|
||||
|
||||
```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">
|
||||
```
|
||||
|
||||
## User Feedback
|
||||
|
||||
When the user clicks Send, you receive JSON like:
|
||||
|
||||
```json
|
||||
{"choice": "a", "feedback": "I like this but make the header smaller"}
|
||||
```
|
||||
|
||||
- `choice` - which option/card they selected (from `data-choice` attribute)
|
||||
- `feedback` - any notes they typed
|
||||
|
||||
## Example: Design Comparison
|
||||
|
||||
```html
|
||||
<div id="claude-content">
|
||||
<h2>Which blog layout works better?</h2>
|
||||
<p class="subtitle">Consider readability and visual hierarchy</p>
|
||||
|
||||
<div class="cards">
|
||||
<div class="card" data-choice="classic" onclick="toggleSelect(this)">
|
||||
<div class="card-image">
|
||||
<div style="padding: 1rem;">
|
||||
<div class="mock-nav">Blog Title</div>
|
||||
<div style="padding: 1rem;">
|
||||
<h3 style="margin-bottom: 0.5rem;">Post Title</h3>
|
||||
<p style="color: var(--text-secondary); font-size: 0.9rem;">
|
||||
Content preview text goes here...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Classic Layout</h3>
|
||||
<p>Traditional blog with posts in a single column</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card" data-choice="magazine" onclick="toggleSelect(this)">
|
||||
<div class="card-image">
|
||||
<div style="padding: 1rem;">
|
||||
<div class="mock-nav">Blog Title</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; padding: 0.5rem;">
|
||||
<div class="placeholder" style="padding: 1rem;">Featured</div>
|
||||
<div class="placeholder" style="padding: 0.5rem;">Post</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h3>Magazine Layout</h3>
|
||||
<p>Grid-based with featured posts</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
1. **Keep mockups simple** - Focus on layout and structure, not pixel-perfect design
|
||||
2. **Use placeholders** - The `.placeholder` class works great for content areas
|
||||
3. **Label clearly** - Use `.mockup-header` to explain what each mockup shows
|
||||
4. **Limit choices** - 2-4 options is ideal; more gets overwhelming
|
||||
5. **Provide context** - Use `.subtitle` to explain what you're asking
|
||||
6. **Regenerate fully** - Write the complete HTML each turn; don't try to patch
|
||||
@@ -8,11 +8,12 @@
|
||||
*
|
||||
* This template provides a consistent frame with:
|
||||
* - OS-aware light/dark theming
|
||||
* - Fixed header and selection indicator bar
|
||||
* - Fixed header and feedback footer
|
||||
* - Scrollable main content area
|
||||
* - CSS helpers for common UI patterns
|
||||
*
|
||||
* Content is injected via placeholder comment in #claude-content.
|
||||
* CLAUDE: Replace the contents of #claude-content with your content.
|
||||
* Keep the header, main wrapper, and feedback-footer intact.
|
||||
*/
|
||||
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
@@ -78,21 +79,37 @@
|
||||
.main { flex: 1; overflow-y: auto; }
|
||||
#claude-content { padding: 2rem; min-height: 100%; }
|
||||
|
||||
.indicator-bar {
|
||||
.feedback-footer {
|
||||
background: var(--bg-secondary);
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 0.5rem 1.5rem;
|
||||
padding: 0.75rem 1.5rem;
|
||||
flex-shrink: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.indicator-bar span {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-secondary);
|
||||
.feedback-footer label { display: block; font-size: 0.65rem; color: var(--text-secondary); margin-bottom: 0.4rem; text-transform: uppercase; letter-spacing: 0.05em; }
|
||||
.feedback-row { display: flex; gap: 0.5rem; }
|
||||
.feedback-footer textarea {
|
||||
flex: 1;
|
||||
background: var(--bg-primary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
padding: 0.5rem 0.75rem;
|
||||
color: var(--text-primary);
|
||||
font-family: inherit;
|
||||
font-size: 0.85rem;
|
||||
resize: none;
|
||||
height: 36px;
|
||||
}
|
||||
.indicator-bar .selected-text {
|
||||
color: var(--accent);
|
||||
font-weight: 500;
|
||||
.feedback-footer textarea:focus { outline: none; border-color: var(--accent); }
|
||||
.feedback-footer button {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0 1rem;
|
||||
border-radius: 6px;
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
.feedback-footer button:hover { background: var(--accent-hover); }
|
||||
|
||||
/* ===== TYPOGRAPHY ===== */
|
||||
h2 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.5rem; }
|
||||
@@ -201,13 +218,42 @@
|
||||
|
||||
<div class="main">
|
||||
<div id="claude-content">
|
||||
<!-- CONTENT -->
|
||||
<!-- CLAUDE: Replace this content -->
|
||||
<h2>Visual Brainstorming</h2>
|
||||
<p class="subtitle">Claude will show mockups and options here.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="indicator-bar">
|
||||
<span id="indicator-text">Click an option above, then return to the terminal</span>
|
||||
<div class="feedback-footer">
|
||||
<label>Feedback for Claude</label>
|
||||
<div class="feedback-row">
|
||||
<textarea id="feedback" placeholder="Add notes (optional)..." onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();send()}"></textarea>
|
||||
<button onclick="send()">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let selectedChoice = null;
|
||||
|
||||
function toggleSelect(el) {
|
||||
const container = el.closest('.options') || el.closest('.cards');
|
||||
if (container) {
|
||||
container.querySelectorAll('.option, .card').forEach(o => o.classList.remove('selected'));
|
||||
}
|
||||
el.classList.add('selected');
|
||||
selectedChoice = el.dataset.choice;
|
||||
}
|
||||
|
||||
function send() {
|
||||
const feedbackEl = document.getElementById('feedback');
|
||||
const feedback = feedbackEl.value.trim();
|
||||
const payload = {};
|
||||
if (selectedChoice) payload.choice = selectedChoice;
|
||||
if (feedback) payload.feedback = feedback;
|
||||
if (Object.keys(payload).length === 0) return;
|
||||
brainstorm.sendToClaude(payload);
|
||||
feedbackEl.value = '';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
ws = new WebSocket(WS_URL);
|
||||
|
||||
ws.onopen = () => {
|
||||
// Send any queued events
|
||||
eventQueue.forEach(e => ws.send(JSON.stringify(e)));
|
||||
eventQueue = [];
|
||||
};
|
||||
@@ -19,11 +20,12 @@
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
// Reconnect after 1 second
|
||||
setTimeout(connect, 1000);
|
||||
};
|
||||
}
|
||||
|
||||
function sendEvent(event) {
|
||||
function send(event) {
|
||||
event.timestamp = Date.now();
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify(event));
|
||||
@@ -32,56 +34,81 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Capture clicks on choice elements
|
||||
// Auto-capture clicks on interactive elements
|
||||
document.addEventListener('click', (e) => {
|
||||
const target = e.target.closest('[data-choice]');
|
||||
const target = e.target.closest('button, a, [data-choice], [role="button"], input[type="submit"]');
|
||||
if (!target) return;
|
||||
|
||||
sendEvent({
|
||||
// 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,
|
||||
id: target.id || null
|
||||
choice: target.dataset.choice || null,
|
||||
id: target.id || null,
|
||||
className: target.className || 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;
|
||||
// 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; });
|
||||
|
||||
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;
|
||||
};
|
||||
send({
|
||||
type: 'submit',
|
||||
formId: form.id || null,
|
||||
formName: form.name || null,
|
||||
data: data
|
||||
});
|
||||
});
|
||||
|
||||
// Expose API for explicit use
|
||||
// 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
|
||||
});
|
||||
|
||||
// Send to Claude - triggers server to exit and return all events
|
||||
function sendToClaude(feedback) {
|
||||
send({
|
||||
type: 'send-to-claude',
|
||||
feedback: feedback || null
|
||||
});
|
||||
// Show confirmation to user
|
||||
document.body.innerHTML = `
|
||||
<div style="display: flex; align-items: center; justify-content: center; height: 100vh; font-family: system-ui, sans-serif;">
|
||||
<div style="text-align: center; color: #666;">
|
||||
<h2 style="color: #333;">✓ Sent to Claude</h2>
|
||||
<p>Return to the terminal to see Claude's response.</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Expose for explicit use if needed
|
||||
window.brainstorm = {
|
||||
send: sendEvent,
|
||||
choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata })
|
||||
send: send,
|
||||
choice: (value, metadata = {}) => send({ type: 'choice', value, ...metadata }),
|
||||
sendToClaude: sendToClaude
|
||||
};
|
||||
|
||||
connect();
|
||||
|
||||
@@ -5,31 +5,15 @@ const chokidar = require('chokidar');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Use provided port or pick a random high port (49152-65535)
|
||||
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';
|
||||
|
||||
// Ensure screen directory exists
|
||||
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)
|
||||
@@ -44,6 +28,7 @@ function getNewestScreen() {
|
||||
return files.length > 0 ? files[0].path : null;
|
||||
}
|
||||
|
||||
// Default waiting page (served when no screens exist yet)
|
||||
const WAITING_PAGE = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
@@ -64,6 +49,7 @@ 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) => {
|
||||
@@ -71,46 +57,36 @@ wss.on('connection', (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({ 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;
|
||||
let html = screenFile ? fs.readFileSync(screenFile, 'utf-8') : WAITING_PAGE;
|
||||
|
||||
if (!screenFile) {
|
||||
html = WAITING_PAGE;
|
||||
} else {
|
||||
const raw = fs.readFileSync(screenFile, 'utf-8');
|
||||
html = isFullDocument(raw) ? raw : wrapInFrame(raw);
|
||||
}
|
||||
// Inject helper script before </body>
|
||||
const helperScript = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf-8');
|
||||
const injection = `<script>\n${helperScript}\n</script>`;
|
||||
|
||||
// Inject helper script
|
||||
if (html.includes('</body>')) {
|
||||
html = html.replace('</body>', `${helperInjection}\n</body>`);
|
||||
html = html.replace('</body>', `${injection}\n</body>`);
|
||||
} else {
|
||||
html += helperInjection;
|
||||
html += injection;
|
||||
}
|
||||
|
||||
res.type('html').send(html);
|
||||
});
|
||||
|
||||
// Watch for new or changed .html files
|
||||
// Watch for new or changed .html files in the directory
|
||||
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 }));
|
||||
// Notify all browsers to reload
|
||||
clients.forEach(ws => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify({ type: 'reload' }));
|
||||
@@ -129,13 +105,11 @@ chokidar.watch(SCREEN_DIR, { ignoreInitial: true })
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
server.listen(PORT, '127.0.0.1', () => {
|
||||
console.log(JSON.stringify({
|
||||
type: 'server-started',
|
||||
port: PORT,
|
||||
host: HOST,
|
||||
url_host: URL_HOST,
|
||||
url: `http://${URL_HOST}:${PORT}`,
|
||||
url: `http://localhost:${PORT}`,
|
||||
screen_dir: SCREEN_DIR
|
||||
}));
|
||||
});
|
||||
|
||||
@@ -1,78 +1,16 @@
|
||||
#!/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]
|
||||
# Usage: start-server.sh
|
||||
#
|
||||
# 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).
|
||||
# Starts server on a random high port, outputs JSON with URL
|
||||
# Each session gets its own temp directory to avoid conflicts
|
||||
# Server runs in background, PID saved for cleanup
|
||||
|
||||
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
|
||||
|
||||
SCREEN_DIR="/tmp/brainstorm-${SESSION_ID}"
|
||||
PID_FILE="${SCREEN_DIR}/.server.pid"
|
||||
LOG_FILE="${SCREEN_DIR}/.server.log"
|
||||
|
||||
@@ -86,38 +24,16 @@ if [[ -f "$PID_FILE" ]]; then
|
||||
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 &
|
||||
cd "$SCRIPT_DIR"
|
||||
BRAINSTORM_DIR="$SCREEN_DIR" 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
|
||||
# Extract and output the server-started line
|
||||
grep "server-started" "$LOG_FILE" | head -1
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Stop the brainstorm server and clean up
|
||||
# Stop the brainstorm server and clean up session directory
|
||||
# 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"
|
||||
|
||||
@@ -18,13 +14,8 @@ 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
|
||||
|
||||
# Clean up session directory
|
||||
rm -rf "$SCREEN_DIR"
|
||||
echo '{"status": "stopped"}'
|
||||
else
|
||||
echo '{"status": "not_running"}'
|
||||
|
||||
27
lib/brainstorm-server/wait-for-feedback.sh
Executable file
27
lib/brainstorm-server/wait-for-feedback.sh
Executable file
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Wait for user feedback from the brainstorm browser
|
||||
# Usage: wait-for-feedback.sh <screen_dir>
|
||||
#
|
||||
# Blocks until user sends feedback, then outputs the JSON.
|
||||
# Write HTML to screen_file BEFORE calling this.
|
||||
|
||||
SCREEN_DIR="${1:?Usage: wait-for-feedback.sh <screen_dir>}"
|
||||
LOG_FILE="${SCREEN_DIR}/.server.log"
|
||||
|
||||
if [[ ! -d "$SCREEN_DIR" ]]; then
|
||||
echo '{"error": "Screen directory not found"}' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Record current position in log file
|
||||
LOG_POS=$(wc -l < "$LOG_FILE" 2>/dev/null || echo 0)
|
||||
|
||||
# Poll for new lines containing the event
|
||||
while true; do
|
||||
RESULT=$(tail -n +$((LOG_POS + 1)) "$LOG_FILE" 2>/dev/null | grep -m 1 "send-to-claude")
|
||||
if [[ -n "$RESULT" ]]; then
|
||||
echo "$RESULT"
|
||||
exit 0
|
||||
fi
|
||||
sleep 0.2
|
||||
done
|
||||
@@ -5,118 +5,44 @@ 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.
|
||||
|
||||
<HARD-GATE>
|
||||
Do NOT invoke any implementation skill, write any code, scaffold any project, or take any implementation action until you have presented a design and the user has approved it. This applies to EVERY project regardless of perceived simplicity.
|
||||
</HARD-GATE>
|
||||
|
||||
## Anti-Pattern: "This Is Too Simple To Need A Design"
|
||||
|
||||
Every project goes through this process. A todo list, a single-function utility, a config change — all of them. "Simple" projects are where unexamined assumptions cause the most wasted work. The design can be short (a few sentences for truly simple projects), but you MUST present it and get approval.
|
||||
|
||||
## Checklist
|
||||
|
||||
You MUST create a task for each of these items and complete them in order:
|
||||
|
||||
1. **Explore project context** — check files, docs, recent commits
|
||||
2. **Offer visual companion** (if topic will involve visual questions) — this is its own message, not combined with a clarifying question. See the Visual Companion section below.
|
||||
3. **Ask clarifying questions** — one at a time, understand purpose/constraints/success criteria
|
||||
4. **Propose 2-3 approaches** — with trade-offs and your recommendation
|
||||
5. **Present design** — in sections scaled to their complexity, get user approval after each section
|
||||
6. **Write design doc** — save to `docs/plans/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];
|
||||
"User approves design?" [shape=diamond];
|
||||
"Write design doc" [shape=box];
|
||||
"Invoke writing-plans skill" [shape=doublecircle];
|
||||
|
||||
"Explore project context" -> "Visual questions ahead?";
|
||||
"Visual questions ahead?" -> "Offer Visual Companion\n(own message, no other content)" [label="yes"];
|
||||
"Visual questions ahead?" -> "Ask clarifying questions" [label="no"];
|
||||
"Offer Visual Companion\n(own message, no other content)" -> "Ask clarifying questions";
|
||||
"Ask clarifying questions" -> "Propose 2-3 approaches";
|
||||
"Propose 2-3 approaches" -> "Present design sections";
|
||||
"Present design sections" -> "User approves design?";
|
||||
"User approves design?" -> "Present design sections" [label="no, revise"];
|
||||
"User approves design?" -> "Write design doc" [label="yes"];
|
||||
"Write design doc" -> "Invoke writing-plans skill";
|
||||
}
|
||||
```
|
||||
|
||||
**The terminal state is invoking writing-plans.** Do NOT invoke frontend-design, mcp-builder, or any other implementation skill. The ONLY skill you invoke after brainstorming is writing-plans.
|
||||
Start by understanding the current project context, then ask questions one at a time to refine the idea. Once you understand what you're building, present the design in small sections (200-300 words), checking after each section whether it looks right so far.
|
||||
|
||||
## The Process
|
||||
|
||||
**Understanding the idea:**
|
||||
|
||||
- Check out the current project state first (files, docs, recent commits)
|
||||
- Before asking detailed questions, assess scope: if the request describes multiple independent subsystems (e.g., "build a platform with chat, file storage, billing, and analytics"), flag this immediately. Don't spend questions refining details of a project that needs to be decomposed first.
|
||||
- If the project is too large for a single spec, help the user decompose into sub-projects: what are the independent pieces, how do they relate, what order should they be built? Then brainstorm the first sub-project through the normal design flow. Each sub-project gets its own spec → plan → implementation cycle.
|
||||
- For appropriately-scoped projects, ask questions one at a time to refine the idea
|
||||
- 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
|
||||
- Break it into sections of 200-300 words
|
||||
- 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 (spec) to `docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md`
|
||||
- (User preferences for spec location override this default)
|
||||
- Write the validated design to `docs/plans/YYYY-MM-DD-<topic>-design.md`
|
||||
- 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.
|
||||
**Implementation (if continuing):**
|
||||
- Ask: "Ready to set up for implementation?"
|
||||
- Use superpowers:using-git-worktrees to create isolated workspace
|
||||
- Use superpowers:writing-plans to create detailed implementation plan
|
||||
|
||||
## Key Principles
|
||||
|
||||
@@ -124,24 +50,88 @@ After writing the spec document:
|
||||
- **Multiple choice preferred** - Easier to answer than open-ended when possible
|
||||
- **YAGNI ruthlessly** - Remove unnecessary features from all designs
|
||||
- **Explore alternatives** - Always propose 2-3 approaches before settling
|
||||
- **Incremental validation** - Present design, get approval before moving on
|
||||
- **Incremental validation** - Present design in sections, validate each
|
||||
- **Be flexible** - Go back and clarify when something doesn't make sense
|
||||
|
||||
## Visual Companion
|
||||
## Visual Companion (Claude Code Only)
|
||||
|
||||
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.
|
||||
A browser-based visual companion for showing mockups, diagrams, and options. Use it whenever visual representation makes feedback easier. **Only works in Claude Code.**
|
||||
|
||||
**Offering the companion:** When you anticipate that upcoming questions will involve visual content (mockups, layouts, diagrams), offer it once for consent:
|
||||
> "Some of the upcoming design questions would benefit from visual mockups. I can show those in a browser window so you can see and compare options visually. This feature is still new — it can be token-intensive and a bit slow, but it works well for layout and design questions. Want to try it? (Requires opening a local URL)"
|
||||
### When to Use
|
||||
|
||||
**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.
|
||||
Use the visual companion when seeing beats describing:
|
||||
- **UI mockups** - layouts, navigation, component designs
|
||||
- **Architecture diagrams** - system components, data flow, relationships
|
||||
- **Complex choices** - multi-option decisions with visual trade-offs
|
||||
- **Design polish** - when the question is about look and feel
|
||||
- **Spatial relationships** - file structures, database schemas, state machines
|
||||
|
||||
**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?**
|
||||
**Always ask first:**
|
||||
> "This involves some visual decisions. Would you like me to show mockups in a browser window? (Requires opening a local URL)"
|
||||
|
||||
- **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
|
||||
Only proceed if they agree. Otherwise, describe options in text.
|
||||
|
||||
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.
|
||||
### How to Use Effectively
|
||||
|
||||
If they agree to the companion, read the detailed guide before proceeding:
|
||||
`skills/brainstorming/visual-companion.md`
|
||||
**Scale fidelity to the question.** If you're asking about layout structure, simple wireframes suffice. If you're asking about visual polish, show polish. Match the mockup's detail level to what you're trying to learn.
|
||||
|
||||
**Explain the question on each page.** Don't just show options—state what decision you're seeking. "Which layout feels more professional?" not just "Pick one."
|
||||
|
||||
**Iterate before moving on.** If feedback changes the current screen, update it and show again. Validate that your changes address their feedback before proceeding to the next question.
|
||||
|
||||
**Limit choices to 2-4 options.** More gets overwhelming. If you have more alternatives, narrow them down first or group them.
|
||||
|
||||
**Use real content when it matters.** For a photography portfolio, use actual images (Unsplash). For a blog, use realistic text. Placeholder content obscures design issues.
|
||||
|
||||
### Starting a Session
|
||||
|
||||
```bash
|
||||
# Start server (creates unique session directory)
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh
|
||||
|
||||
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
|
||||
# "screen_dir":"/tmp/brainstorm-12345"}
|
||||
```
|
||||
|
||||
Save `screen_dir` from the response. Tell user to open the URL.
|
||||
|
||||
### The Loop
|
||||
|
||||
1. **Start watcher first** (background bash) - avoids race condition:
|
||||
```bash
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/wait-for-feedback.sh $SCREEN_DIR
|
||||
```
|
||||
|
||||
2. **Write HTML** to a new file in `screen_dir`:
|
||||
- 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
|
||||
|
||||
3. **Tell user what to expect:**
|
||||
- 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")
|
||||
- This lets them know what to look for before switching to browser
|
||||
|
||||
4. **Wait for feedback** - call `TaskOutput(task_id, block=true, timeout=600000)`
|
||||
- If timeout, call TaskOutput again (watcher still running)
|
||||
- After 3 timeouts (30 min), say "Let me know when you want to continue"
|
||||
|
||||
5. **Process feedback** - returns JSON like `{"choice": "a", "feedback": "make header smaller"}`
|
||||
|
||||
6. **Iterate or advance** - if feedback changes current screen, write a new file (e.g., `layout-v2.html`). Only move to next question when current step is validated.
|
||||
|
||||
7. Repeat until done.
|
||||
|
||||
### Cleaning Up
|
||||
|
||||
```bash
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/stop-server.sh $SCREEN_DIR
|
||||
```
|
||||
|
||||
### Resources
|
||||
|
||||
- Frame template: `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/frame-template.html`
|
||||
- CSS classes: `.options`, `.cards`, `.mockup`, `.split`, `.pros-cons`
|
||||
- Detailed examples: `${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/CLAUDE-INSTRUCTIONS.md`
|
||||
- Quick reference: `${CLAUDE_PLUGIN_ROOT}/skills/brainstorming/visual-companion.md`
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# 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
|
||||
@@ -1,139 +1,64 @@
|
||||
# Visual Companion Guide
|
||||
# Visual Companion Reference
|
||||
|
||||
Browser-based visual brainstorming companion for showing mockups, diagrams, and options.
|
||||
Quick reference for the browser-based visual brainstorming companion.
|
||||
|
||||
## When to Use
|
||||
## Files
|
||||
|
||||
Decide per-question, not per-session. The test: **would the user understand this better by seeing it than reading it?**
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `lib/brainstorm-server/start-server.sh` | Start server, outputs JSON with URL and session paths |
|
||||
| `lib/brainstorm-server/stop-server.sh` | Stop server and clean up session directory |
|
||||
| `lib/brainstorm-server/wait-for-feedback.sh` | Wait for user feedback (polling-based) |
|
||||
| `lib/brainstorm-server/frame-template.html` | Base HTML template with CSS |
|
||||
| `lib/brainstorm-server/CLAUDE-INSTRUCTIONS.md` | Detailed usage guide |
|
||||
|
||||
**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
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Start server with persistence (mockups saved to project)
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh --project-dir /path/to/project
|
||||
# 1. Start server
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh
|
||||
# Returns: {"screen_dir":"/tmp/brainstorm-xxx","url":"http://localhost:PORT"}
|
||||
|
||||
# Returns: {"type":"server-started","port":52341,"url":"http://localhost:52341",
|
||||
# "screen_dir":"/path/to/project/.superpowers/brainstorm/12345-1706000000"}
|
||||
# 2. Start watcher FIRST (background bash) - avoids race condition
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/wait-for-feedback.sh $SCREEN_DIR
|
||||
|
||||
# 3. Write HTML to a NEW file in screen_dir (e.g., platform.html, style.html)
|
||||
# Never reuse filenames - server serves newest file automatically
|
||||
|
||||
# 4. Call TaskOutput(task_id, block=true, timeout=600000)
|
||||
# If timeout, call again. After 3 timeouts (30 min), prompt user.
|
||||
# Returns: {"choice":"a","feedback":"user notes"}
|
||||
|
||||
# 5. Iterate or advance - write new file if feedback changes it (e.g., style-v2.html)
|
||||
|
||||
# 6. Clean up when done
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/stop-server.sh $SCREEN_DIR
|
||||
```
|
||||
|
||||
Save `screen_dir` from the response. Tell user to open the URL.
|
||||
## Key Principles
|
||||
|
||||
**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.
|
||||
- **Always ask first** before starting visual companion
|
||||
- **Scale fidelity to the question** - wireframes for layout, polish for polish questions
|
||||
- **Explain the question** on each page - what decision are you seeking?
|
||||
- **Iterate before advancing** - if feedback changes current screen, write new version
|
||||
- **2-4 options max** per screen
|
||||
|
||||
**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.
|
||||
## File Naming
|
||||
|
||||
**If background processes are reaped in your environment:** run in foreground from a persistent terminal session:
|
||||
- **Use semantic names**: `platform.html`, `visual-style.html`, `layout.html`, `controls.html`
|
||||
- **Never reuse filenames** - each screen is a new file
|
||||
- **For iterations**: append version suffix like `layout-v2.html`, `layout-v3.html`
|
||||
- Server automatically serves the newest file by modification time
|
||||
|
||||
```bash
|
||||
${CLAUDE_PLUGIN_ROOT}/lib/brainstorm-server/start-server.sh --project-dir /path/to/project --foreground
|
||||
```
|
||||
## Terminal UX
|
||||
|
||||
In `--foreground` mode, the command stays attached and serves until interrupted.
|
||||
- **Never use cat/heredoc for HTML** - dumps noise into terminal. Use Write tool instead.
|
||||
- **Remind user of URL** on every step, not just the first
|
||||
- **Give text summary** of what's on screen before they look (e.g., "Showing 3 API structure options")
|
||||
|
||||
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:
|
||||
## CSS Classes
|
||||
|
||||
### Options (A/B/C choices)
|
||||
|
||||
```html
|
||||
<div class="options">
|
||||
<div class="option" data-choice="a" onclick="toggleSelect(this)">
|
||||
@@ -146,20 +71,11 @@ The frame template provides these CSS classes for your content:
|
||||
</div>
|
||||
```
|
||||
|
||||
**Multi-select:** Add `data-multiselect` to the container to let users select multiple options. Each click toggles the item. The indicator bar shows the count.
|
||||
|
||||
```html
|
||||
<div class="options" data-multiselect>
|
||||
<!-- same option markup — users can select/deselect multiple -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Cards (visual designs)
|
||||
|
||||
```html
|
||||
<div class="cards">
|
||||
<div class="card" data-choice="design1" onclick="toggleSelect(this)">
|
||||
<div class="card-image"><!-- mockup content --></div>
|
||||
<div class="card" data-choice="x" onclick="toggleSelect(this)">
|
||||
<div class="card-image"><!-- mockup --></div>
|
||||
<div class="card-body">
|
||||
<h3>Name</h3>
|
||||
<p>Description</p>
|
||||
@@ -169,92 +85,46 @@ The frame template provides these CSS classes for your content:
|
||||
```
|
||||
|
||||
### Mockup container
|
||||
|
||||
```html
|
||||
<div class="mockup">
|
||||
<div class="mockup-header">Preview: Dashboard Layout</div>
|
||||
<div class="mockup-body"><!-- your mockup HTML --></div>
|
||||
<div class="mockup-header">Label</div>
|
||||
<div class="mockup-body"><!-- content --></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Split view (side-by-side)
|
||||
|
||||
### Split view
|
||||
```html
|
||||
<div class="split">
|
||||
<div class="mockup"><!-- left --></div>
|
||||
<div class="mockup"><!-- right --></div>
|
||||
<div><!-- left --></div>
|
||||
<div><!-- 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 class="pros"><h4>Pros</h4><ul><li>...</li></ul></div>
|
||||
<div class="cons"><h4>Cons</h4><ul><li>...</li></ul></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Mock elements (wireframe building blocks)
|
||||
|
||||
### Mock elements
|
||||
```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="mock-nav">Nav items</div>
|
||||
<div class="mock-sidebar">Sidebar</div>
|
||||
<div class="mock-content">Content</div>
|
||||
<button class="mock-button">Button</button>
|
||||
<input class="mock-input" placeholder="Input">
|
||||
<div class="placeholder">Placeholder area</div>
|
||||
```
|
||||
|
||||
### Typography and sections
|
||||
## User Feedback Format
|
||||
|
||||
- `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}
|
||||
```json
|
||||
{
|
||||
"choice": "option-id", // from data-choice attribute
|
||||
"feedback": "user notes" // from feedback textarea
|
||||
}
|
||||
```
|
||||
|
||||
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`
|
||||
Both fields are optional - user may select without notes, or send notes without selection.
|
||||
|
||||
@@ -74,11 +74,3 @@ After all tasks complete and verified:
|
||||
- Reference skills when plan says to
|
||||
- Between batches: just report and wait
|
||||
- Stop when blocked, don't guess
|
||||
- Never start implementation on main/master branch without explicit user consent
|
||||
|
||||
## Integration
|
||||
|
||||
**Required workflow skills:**
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
- **superpowers:writing-plans** - Creates the plan this skill executes
|
||||
- **superpowers:finishing-a-development-branch** - Complete development after all tasks
|
||||
|
||||
@@ -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/superpowers/plans/deployment-plan.md
|
||||
PLAN_OR_REQUIREMENTS: Task 2 from docs/plans/deployment-plan.md
|
||||
BASE_SHA: a7981ec
|
||||
HEAD_SHA: 3df7661
|
||||
DESCRIPTION: Added verifyIndex() and repairIndex() with 4 issue types
|
||||
|
||||
@@ -82,39 +82,6 @@ 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
|
||||
@@ -126,7 +93,7 @@ Implementer subagents report one of four statuses. Handle each appropriately:
|
||||
```
|
||||
You: I'm using Subagent-Driven Development to execute this plan.
|
||||
|
||||
[Read plan file once: docs/superpowers/plans/feature-plan.md]
|
||||
[Read plan file once: docs/plans/feature-plan.md]
|
||||
[Extract all 5 tasks with full text and context]
|
||||
[Create TodoWrite with all tasks]
|
||||
|
||||
@@ -232,7 +199,6 @@ Done!
|
||||
## Red Flags
|
||||
|
||||
**Never:**
|
||||
- Start implementation on main/master branch without explicit user consent
|
||||
- Skip reviews (spec compliance OR code quality)
|
||||
- Proceed with unfixed issues
|
||||
- Dispatch multiple implementation subagents in parallel (conflicts)
|
||||
@@ -263,7 +229,6 @@ Done!
|
||||
## Integration
|
||||
|
||||
**Required workflow skills:**
|
||||
- **superpowers:using-git-worktrees** - REQUIRED: Set up isolated workspace before starting
|
||||
- **superpowers:writing-plans** - Creates the plan this skill executes
|
||||
- **superpowers:requesting-code-review** - Code review template for reviewer subagents
|
||||
- **superpowers:finishing-a-development-branch** - Complete development after all tasks
|
||||
|
||||
@@ -17,10 +17,4 @@ 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
|
||||
|
||||
@@ -41,36 +41,6 @@ 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:
|
||||
@@ -100,14 +70,9 @@ Task tool (general-purpose):
|
||||
## Report Format
|
||||
|
||||
When done, report:
|
||||
- **Status:** DONE | DONE_WITH_CONCERNS | BLOCKED | NEEDS_CONTEXT
|
||||
- What you implemented (or what you attempted, if blocked)
|
||||
- What you implemented
|
||||
- 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.
|
||||
```
|
||||
|
||||
@@ -210,9 +210,8 @@ Ready to implement auth feature
|
||||
|
||||
**Called by:**
|
||||
- **brainstorming** (Phase 4) - REQUIRED when design is approved and implementation follows
|
||||
- **subagent-driven-development** - REQUIRED before executing any tasks
|
||||
- **executing-plans** - REQUIRED before executing any tasks
|
||||
- Any skill needing isolated workspace
|
||||
|
||||
**Pairs with:**
|
||||
- **finishing-a-development-branch** - REQUIRED for cleanup after work complete
|
||||
- **executing-plans** or **subagent-driven-development** - Work happens in this worktree
|
||||
|
||||
@@ -3,10 +3,6 @@ name: using-superpowers
|
||||
description: Use when starting any conversation - establishes how to find and use skills, requiring Skill tool invocation before ANY response including clarifying questions
|
||||
---
|
||||
|
||||
<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.
|
||||
|
||||
@@ -31,10 +27,6 @@ If CLAUDE.md says "don't use TDD" and a skill says "always use TDD," follow CLAU
|
||||
|
||||
**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
|
||||
@@ -44,9 +36,6 @@ Skills use Claude Code tool names. Non-CC platforms: see `references/codex-tools
|
||||
```dot
|
||||
digraph skill_flow {
|
||||
"User message received" [shape=doublecircle];
|
||||
"About to EnterPlanMode?" [shape=doublecircle];
|
||||
"Already brainstormed?" [shape=diamond];
|
||||
"Invoke brainstorming skill" [shape=box];
|
||||
"Might any skill apply?" [shape=diamond];
|
||||
"Invoke Skill tool" [shape=box];
|
||||
"Announce: 'Using [skill] to [purpose]'" [shape=box];
|
||||
@@ -55,11 +44,6 @@ digraph skill_flow {
|
||||
"Follow skill exactly" [shape=box];
|
||||
"Respond (including clarifications)" [shape=doublecircle];
|
||||
|
||||
"About to EnterPlanMode?" -> "Already brainstormed?";
|
||||
"Already brainstormed?" -> "Invoke brainstorming skill" [label="no"];
|
||||
"Already brainstormed?" -> "Might any skill apply?" [label="yes"];
|
||||
"Invoke brainstorming skill" -> "Might any skill apply?";
|
||||
|
||||
"User message received" -> "Might any skill apply?";
|
||||
"Might any skill apply?" -> "Invoke Skill tool" [label="yes, even 1%"];
|
||||
"Might any skill apply?" -> "Respond (including clarifications)" [label="definitely not"];
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
# 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`.
|
||||
@@ -15,23 +15,7 @@ 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/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.
|
||||
**Save plans to:** `docs/plans/YYYY-MM-DD-<feature-name>.md`
|
||||
|
||||
## Bite-Sized Task Granularity
|
||||
|
||||
@@ -49,7 +33,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
||||
```markdown
|
||||
# [Feature Name] Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** [One sentence describing what this builds]
|
||||
|
||||
@@ -62,7 +46,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
||||
|
||||
## Task Structure
|
||||
|
||||
````markdown
|
||||
```markdown
|
||||
### Task N: [Component Name]
|
||||
|
||||
**Files:**
|
||||
@@ -70,7 +54,7 @@ This structure informs the task decomposition. Each task should produce self-con
|
||||
- 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():
|
||||
@@ -78,30 +62,30 @@ 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
|
||||
git commit -m "feat: add specific feature"
|
||||
```
|
||||
````
|
||||
```
|
||||
|
||||
## Remember
|
||||
- Exact file paths always
|
||||
@@ -110,38 +94,23 @@ 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:
|
||||
After saving the plan, offer execution choice:
|
||||
|
||||
**"Plan complete and saved to `docs/superpowers/plans/<filename>.md`. Ready to execute?"**
|
||||
**"Plan complete and saved to `docs/plans/<filename>.md`. Two execution options:**
|
||||
|
||||
**Execution path depends on harness capabilities:**
|
||||
**1. Subagent-Driven (this session)** - I dispatch fresh subagent per task, review between tasks, fast iteration
|
||||
|
||||
**If harness has subagents (Claude Code, etc.):**
|
||||
- **REQUIRED:** Use superpowers:subagent-driven-development
|
||||
- Do NOT offer a choice - subagent-driven is the standard approach
|
||||
- Fresh subagent per task + two-stage review
|
||||
**2. Parallel Session (separate)** - Open new session with executing-plans, batch execution with checkpoints
|
||||
|
||||
**If harness does NOT have subagents:**
|
||||
- Execute plan in current session using superpowers:executing-plans
|
||||
- Batch execution with checkpoints for 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
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
# 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
|
||||
@@ -9,7 +9,7 @@ description: Use when creating new skills, editing existing skills, or verifying
|
||||
|
||||
**Writing skills IS Test-Driven Development applied to process documentation.**
|
||||
|
||||
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.agents/skills/` for Codex)**
|
||||
**Personal skills live in agent-specific directories (`~/.claude/skills` for Claude Code, `~/.codex/skills` for Codex)**
|
||||
|
||||
You write test cases (pressure scenarios with subagents), watch them fail (baseline behavior), write the skill (documentation), watch tests pass (agents comply), and refactor (close loopholes).
|
||||
|
||||
|
||||
@@ -7,11 +7,12 @@ 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';
|
||||
const TEST_SCREEN = '/tmp/brainstorm-test/screen.html';
|
||||
|
||||
// Clean up test directory
|
||||
function cleanup() {
|
||||
if (fs.existsSync(TEST_DIR)) {
|
||||
fs.rmSync(TEST_DIR, { recursive: true });
|
||||
if (fs.existsSync(path.dirname(TEST_SCREEN))) {
|
||||
fs.rmSync(path.dirname(TEST_SCREEN), { recursive: true });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,29 +30,19 @@ async function fetch(url) {
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
// Start server
|
||||
const server = spawn('node', [SERVER_PATH], {
|
||||
env: { ...process.env, BRAINSTORM_PORT: TEST_PORT, BRAINSTORM_SCREEN: TEST_SCREEN }
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
server.stdout.on('data', (data) => { stdout += data.toString(); });
|
||||
server.stderr.on('data', (data) => { stderr += data.toString(); });
|
||||
server.stderr.on('data', (data) => { console.error('Server 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);
|
||||
await sleep(1000); // Wait for server to start
|
||||
|
||||
try {
|
||||
// Test 1: Server starts and outputs JSON
|
||||
@@ -60,17 +51,17 @@ async function runTests() {
|
||||
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');
|
||||
// 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('Waiting for Claude'), 'Should show waiting message');
|
||||
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 = '';
|
||||
stdout = ''; // Reset stdout capture
|
||||
const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
||||
await new Promise(resolve => ws.on('open', resolve));
|
||||
|
||||
@@ -93,91 +84,14 @@ async function runTests() {
|
||||
if (msg.type === 'reload') gotReload = true;
|
||||
});
|
||||
|
||||
fs.writeFileSync(path.join(TEST_DIR, 'test-screen.html'), '<html><body>Full doc</body></html>');
|
||||
// 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');
|
||||
|
||||
// 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 {
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Integration Test: Document Review System
|
||||
# Actually runs spec/plan review and verifies reviewers catch issues
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
source "$SCRIPT_DIR/test-helpers.sh"
|
||||
|
||||
echo "========================================"
|
||||
echo " Integration Test: Document Review System"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
echo "This test verifies the document review system by:"
|
||||
echo " 1. Creating a spec with intentional errors"
|
||||
echo " 2. Running the spec document reviewer"
|
||||
echo " 3. Verifying the reviewer catches the errors"
|
||||
echo ""
|
||||
|
||||
# Create test project
|
||||
TEST_PROJECT=$(create_test_project)
|
||||
echo "Test project: $TEST_PROJECT"
|
||||
|
||||
# Trap to cleanup
|
||||
trap "cleanup_test_project $TEST_PROJECT" EXIT
|
||||
|
||||
cd "$TEST_PROJECT"
|
||||
|
||||
# Create directory structure
|
||||
mkdir -p docs/superpowers/specs
|
||||
|
||||
# Create a spec document WITH INTENTIONAL ERRORS for the reviewer to catch
|
||||
cat > docs/superpowers/specs/test-feature-design.md <<'EOF'
|
||||
# Test Feature Design
|
||||
|
||||
## Overview
|
||||
|
||||
This is a test feature that does something useful.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. The feature should work correctly
|
||||
2. It should be fast
|
||||
3. TODO: Add more requirements here
|
||||
|
||||
## Architecture
|
||||
|
||||
The feature will use a simple architecture with:
|
||||
- A frontend component
|
||||
- A backend service
|
||||
- Error handling will be specified later once we understand the failure modes better
|
||||
|
||||
## Data Flow
|
||||
|
||||
Data flows from the frontend to the backend.
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
Tests will be written to cover the main functionality.
|
||||
EOF
|
||||
|
||||
# Initialize git repo
|
||||
git init --quiet
|
||||
git config user.email "test@test.com"
|
||||
git config user.name "Test User"
|
||||
git add .
|
||||
git commit -m "Initial commit with test spec" --quiet
|
||||
|
||||
echo ""
|
||||
echo "Created test spec with intentional errors:"
|
||||
echo " - TODO placeholder in Requirements section"
|
||||
echo " - 'specified later' deferral in Architecture section"
|
||||
echo ""
|
||||
echo "Running spec document reviewer..."
|
||||
echo ""
|
||||
|
||||
# Run Claude to review the spec
|
||||
OUTPUT_FILE="$TEST_PROJECT/claude-output.txt"
|
||||
|
||||
PROMPT="You are testing the spec document reviewer.
|
||||
|
||||
Read the spec-document-reviewer-prompt.md template in skills/brainstorming/ to understand the review format.
|
||||
|
||||
Then review the spec at $TEST_PROJECT/docs/superpowers/specs/test-feature-design.md using the criteria from that template.
|
||||
|
||||
Look for:
|
||||
- TODOs, placeholders, 'TBD', incomplete sections
|
||||
- Sections saying 'to be defined later' or 'will spec when X is done'
|
||||
- Sections noticeably less detailed than others
|
||||
|
||||
Output your review in the format specified in the template."
|
||||
|
||||
echo "================================================================================"
|
||||
cd "$SCRIPT_DIR/../.." && timeout 120 claude -p "$PROMPT" --permission-mode bypassPermissions 2>&1 | tee "$OUTPUT_FILE" || {
|
||||
echo ""
|
||||
echo "================================================================================"
|
||||
echo "EXECUTION FAILED (exit code: $?)"
|
||||
exit 1
|
||||
}
|
||||
echo "================================================================================"
|
||||
|
||||
echo ""
|
||||
echo "Analyzing reviewer output..."
|
||||
echo ""
|
||||
|
||||
# Verification tests
|
||||
FAILED=0
|
||||
|
||||
echo "=== Verification Tests ==="
|
||||
echo ""
|
||||
|
||||
# Test 1: Reviewer found the TODO
|
||||
echo "Test 1: Reviewer found TODO..."
|
||||
if grep -qi "TODO" "$OUTPUT_FILE" && grep -qi "requirements\|Requirements" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Reviewer identified TODO in Requirements section"
|
||||
else
|
||||
echo " [FAIL] Reviewer did not identify TODO"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 2: Reviewer found the "specified later" deferral
|
||||
echo "Test 2: Reviewer found 'specified later' deferral..."
|
||||
if grep -qi "specified later\|later\|defer\|incomplete\|error handling" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Reviewer identified deferred content"
|
||||
else
|
||||
echo " [FAIL] Reviewer did not identify deferred content"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 3: Reviewer output includes Issues section
|
||||
echo "Test 3: Review output format..."
|
||||
if grep -qi "issues\|Issues" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Review includes Issues section"
|
||||
else
|
||||
echo " [FAIL] Review missing Issues section"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Test 4: Reviewer did NOT approve (found issues)
|
||||
echo "Test 4: Reviewer verdict..."
|
||||
if grep -qi "Issues Found\|❌\|not approved\|issues found" "$OUTPUT_FILE"; then
|
||||
echo " [PASS] Reviewer correctly found issues (not approved)"
|
||||
elif grep -qi "Approved\|✅" "$OUTPUT_FILE" && ! grep -qi "Issues Found\|❌" "$OUTPUT_FILE"; then
|
||||
echo " [FAIL] Reviewer incorrectly approved spec with errors"
|
||||
FAILED=$((FAILED + 1))
|
||||
else
|
||||
echo " [PASS] Reviewer identified problems (ambiguous format but found issues)"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
# Summary
|
||||
echo "========================================"
|
||||
echo " Test Summary"
|
||||
echo "========================================"
|
||||
echo ""
|
||||
|
||||
if [ $FAILED -eq 0 ]; then
|
||||
echo "STATUS: PASSED"
|
||||
echo "All verification tests passed!"
|
||||
echo ""
|
||||
echo "The spec document reviewer correctly:"
|
||||
echo " ✓ Found TODO placeholder"
|
||||
echo " ✓ Found 'specified later' deferral"
|
||||
echo " ✓ Produced properly formatted review"
|
||||
echo " ✓ Did not approve spec with errors"
|
||||
exit 0
|
||||
else
|
||||
echo "STATUS: FAILED"
|
||||
echo "Failed $FAILED verification tests"
|
||||
echo ""
|
||||
echo "Output saved to: $OUTPUT_FILE"
|
||||
echo ""
|
||||
echo "Review the output to see what went wrong."
|
||||
exit 1
|
||||
fi
|
||||
@@ -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/superpowers/plans/$plan_name.md"
|
||||
local plan_file="$project_dir/docs/plans/$plan_name.md"
|
||||
|
||||
mkdir -p "$(dirname "$plan_file")"
|
||||
|
||||
|
||||
@@ -42,10 +42,10 @@ cat > package.json <<'EOF'
|
||||
}
|
||||
EOF
|
||||
|
||||
mkdir -p src test docs/superpowers/plans
|
||||
mkdir -p src test docs/plans
|
||||
|
||||
# Create a simple implementation plan
|
||||
cat > docs/superpowers/plans/implementation-plan.md <<'EOF'
|
||||
cat > docs/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/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
|
||||
I want you to execute the implementation plan at docs/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/superpowers/plans/implementation-plan.md using the subagent-driven-development skill.
|
||||
PROMPT="Change to directory $TEST_PROJECT and then execute the implementation plan at docs/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
|
||||
|
||||
@@ -14,7 +14,7 @@ echo "Test 1: Skill loading..."
|
||||
|
||||
output=$(run_claude "What is the subagent-driven-development skill? Describe its key steps briefly." 30)
|
||||
|
||||
if assert_contains "$output" "subagent-driven-development\|Subagent-Driven Development\|Subagent Driven" "Skill is recognized"; then
|
||||
if assert_contains "$output" "subagent-driven-development" "Skill is recognized"; then
|
||||
: # pass
|
||||
else
|
||||
exit 1
|
||||
@@ -136,30 +136,4 @@ fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Test 8: Verify worktree requirement
|
||||
echo "Test 8: Worktree requirement..."
|
||||
|
||||
output=$(run_claude "What workflow skills are required before using subagent-driven-development? List any prerequisites or required skills." 30)
|
||||
|
||||
if assert_contains "$output" "using-git-worktrees\|worktree" "Mentions worktree requirement"; then
|
||||
: # pass
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Test 9: Verify main branch warning
|
||||
echo "Test 9: Main branch red flag..."
|
||||
|
||||
output=$(run_claude "In subagent-driven-development, is it okay to start implementation directly on the main branch?" 30)
|
||||
|
||||
if assert_contains "$output" "worktree\|feature.*branch\|not.*main\|never.*main\|avoid.*main\|don't.*main\|consent\|permission" "Warns against main branch"; then
|
||||
: # pass
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
echo "=== All subagent-driven-development skill tests passed ==="
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
The plan is done. docs/superpowers/plans/auth-system.md has everything.
|
||||
The plan is done. docs/plans/auth-system.md has everything.
|
||||
|
||||
Do subagent-driven development on this - start with Task 1, dispatch a subagent, then we'll review.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Great, the plan is complete. I've saved it to docs/superpowers/plans/auth-system.md.
|
||||
Great, the plan is complete. I've saved it to docs/plans/auth-system.md.
|
||||
|
||||
Here's a summary of what we designed:
|
||||
- Task 1: Add User Model with email/password fields
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[Previous assistant message]:
|
||||
Plan complete and saved to docs/superpowers/plans/auth-system.md.
|
||||
Plan complete and saved to docs/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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
I have my implementation plan ready at docs/superpowers/plans/auth-system.md.
|
||||
I have my implementation plan ready at docs/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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
I have a plan at docs/superpowers/plans/auth-system.md that's ready to implement.
|
||||
I have a plan at docs/plans/auth-system.md that's ready to implement.
|
||||
|
||||
subagent-driven-development, please
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Plan is at docs/superpowers/plans/auth-system.md.
|
||||
Plan is at docs/plans/auth-system.md.
|
||||
|
||||
subagent-driven-development, please. Don't waste time - just read the plan and start dispatching subagents immediately.
|
||||
|
||||
@@ -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/superpowers/plans"
|
||||
mkdir -p "$PROJECT_DIR/docs/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/superpowers/plans/auth-system.md" << 'EOF'
|
||||
cat > "$PROJECT_DIR/docs/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/superpowers/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/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 \
|
||||
|
||||
@@ -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/superpowers/plans"
|
||||
mkdir -p "$PROJECT_DIR/docs/plans"
|
||||
|
||||
echo "=== Extended Multi-Turn Test ==="
|
||||
echo "Output dir: $OUTPUT_DIR"
|
||||
|
||||
@@ -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/superpowers/plans"
|
||||
mkdir -p "$PROJECT_DIR/docs/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/superpowers/plans/auth-system.md" << 'EOF'
|
||||
cat > "$PROJECT_DIR/docs/plans/auth-system.md" << 'EOF'
|
||||
# Auth System Implementation Plan
|
||||
|
||||
## Task 1: Add User Model
|
||||
|
||||
@@ -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/superpowers/plans"
|
||||
mkdir -p "$PROJECT_DIR/docs/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/superpowers/plans/auth-system.md" << 'EOF'
|
||||
cat > "$PROJECT_DIR/docs/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/superpowers/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/plans/auth-system.md. Now I'm ready to implement. What are my options for execution?" \
|
||||
--continue \
|
||||
--plugin-dir "$PLUGIN_DIR" \
|
||||
--dangerously-skip-permissions \
|
||||
|
||||
@@ -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/superpowers/plans"
|
||||
mkdir -p "$PROJECT_DIR/docs/plans"
|
||||
|
||||
# Create a dummy plan file for mid-conversation tests
|
||||
cat > "$PROJECT_DIR/docs/superpowers/plans/auth-system.md" << 'EOF'
|
||||
cat > "$PROJECT_DIR/docs/plans/auth-system.md" << 'EOF'
|
||||
# Auth System Implementation Plan
|
||||
|
||||
## Task 1: Add User Model
|
||||
|
||||
@@ -18,13 +18,13 @@ cp -r "$REPO_ROOT/lib" "$HOME/.config/opencode/superpowers/"
|
||||
cp -r "$REPO_ROOT/skills" "$HOME/.config/opencode/superpowers/"
|
||||
|
||||
# Copy plugin directory
|
||||
mkdir -p "$HOME/.config/opencode/superpowers/.opencode/plugins"
|
||||
cp "$REPO_ROOT/.opencode/plugins/superpowers.js" "$HOME/.config/opencode/superpowers/.opencode/plugins/"
|
||||
mkdir -p "$HOME/.config/opencode/superpowers/.opencode/plugin"
|
||||
cp "$REPO_ROOT/.opencode/plugin/superpowers.js" "$HOME/.config/opencode/superpowers/.opencode/plugin/"
|
||||
|
||||
# Register plugin via symlink
|
||||
mkdir -p "$HOME/.config/opencode/plugins"
|
||||
ln -sf "$HOME/.config/opencode/superpowers/.opencode/plugins/superpowers.js" \
|
||||
"$HOME/.config/opencode/plugins/superpowers.js"
|
||||
mkdir -p "$HOME/.config/opencode/plugin"
|
||||
ln -sf "$HOME/.config/opencode/superpowers/.opencode/plugin/superpowers.js" \
|
||||
"$HOME/.config/opencode/plugin/superpowers.js"
|
||||
|
||||
# Create test skills in different locations for testing
|
||||
|
||||
@@ -57,8 +57,8 @@ PROJECT_SKILL_MARKER_67890
|
||||
EOF
|
||||
|
||||
echo "Setup complete: $TEST_HOME"
|
||||
echo "Plugin installed to: $HOME/.config/opencode/superpowers/.opencode/plugins/superpowers.js"
|
||||
echo "Plugin registered at: $HOME/.config/opencode/plugins/superpowers.js"
|
||||
echo "Plugin installed to: $HOME/.config/opencode/superpowers/.opencode/plugin/superpowers.js"
|
||||
echo "Plugin registered at: $HOME/.config/opencode/plugin/superpowers.js"
|
||||
echo "Test project at: $TEST_HOME/test-project"
|
||||
|
||||
# Helper function for cleanup (call from tests or trap)
|
||||
|
||||
@@ -15,15 +15,15 @@ trap cleanup_test_env EXIT
|
||||
|
||||
# Test 1: Verify plugin file exists and is registered
|
||||
echo "Test 1: Checking plugin registration..."
|
||||
if [ -L "$HOME/.config/opencode/plugins/superpowers.js" ]; then
|
||||
if [ -L "$HOME/.config/opencode/plugin/superpowers.js" ]; then
|
||||
echo " [PASS] Plugin symlink exists"
|
||||
else
|
||||
echo " [FAIL] Plugin symlink not found at $HOME/.config/opencode/plugins/superpowers.js"
|
||||
echo " [FAIL] Plugin symlink not found at $HOME/.config/opencode/plugin/superpowers.js"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify symlink target exists
|
||||
if [ -f "$(readlink -f "$HOME/.config/opencode/plugins/superpowers.js")" ]; then
|
||||
if [ -f "$(readlink -f "$HOME/.config/opencode/plugin/superpowers.js")" ]; then
|
||||
echo " [PASS] Plugin symlink target exists"
|
||||
else
|
||||
echo " [FAIL] Plugin symlink target does not exist"
|
||||
@@ -60,7 +60,7 @@ fi
|
||||
|
||||
# Test 5: Verify plugin JavaScript syntax (basic check)
|
||||
echo "Test 5: Checking plugin JavaScript syntax..."
|
||||
plugin_file="$HOME/.config/opencode/superpowers/.opencode/plugins/superpowers.js"
|
||||
plugin_file="$HOME/.config/opencode/superpowers/.opencode/plugin/superpowers.js"
|
||||
if node --check "$plugin_file" 2>/dev/null; then
|
||||
echo " [PASS] Plugin JavaScript syntax is valid"
|
||||
else
|
||||
|
||||
@@ -1 +1 @@
|
||||
I have a plan document at docs/superpowers/plans/2024-01-15-auth-system.md that needs to be executed. Please implement it.
|
||||
I have a plan document at docs/plans/2024-01-15-auth-system.md that needs to be executed. Please implement it.
|
||||
@@ -77,7 +77,6 @@ claude -p "$PROMPT" \
|
||||
--plugin-dir "$PLUGIN_DIR" \
|
||||
--dangerously-skip-permissions \
|
||||
--output-format stream-json \
|
||||
--verbose \
|
||||
> "$LOG_FILE" 2>&1 || true
|
||||
|
||||
# Extract final stats
|
||||
|
||||
Reference in New Issue
Block a user