Browse Source

Add Codex superpowers integration

- Single unified script: superpowers-codex with bootstrap/use-skill/find-skills commands
- Cross-platform Node.js implementation (works on Windows, macOS, Linux)
- Namespaced skills: superpowers:skill-name for core, skill-name for personal
- Personal skills override superpowers skills when names match
- Clean skill display: shows name/description without raw frontmatter
- Helpful context: shows supporting files directory for each skill
- Tool mapping for Codex: TodoWrite→update_plan, Skill→superpowers-codex, etc.
- Subagent orchestration instructions for codex --yolo exec
- Updated terminology: "Superpowers skills" instead of "Core skills"
- Bootstrap integration with AGENTS.md for automatic startup
Jesse Vincent 10 tháng trước cách đây
mục cha
commit
113d18ec28
3 tập tin đã thay đổi với 617 bổ sung0 xóa
  1. 135 0
      codex/INSTALL.md
  2. 131 0
      codex/superpowers-bootstrap.md
  3. 351 0
      scripts/superpowers-codex

+ 135 - 0
codex/INSTALL.md

@@ -0,0 +1,135 @@
+# Installing Superpowers for Codex
+
+This guide will help you install and set up the Superpowers skill system for Codex.
+
+## Quick Installation
+
+1. **Clone Superpowers to ~/.codex/superpowers/**:
+   ```bash
+   mkdir -p ~/.codex/superpowers
+   cd ~/.codex/superpowers
+   git clone https://github.com/obra/superpowers.git .
+   ```
+
+2. **Create personal skills directory**:
+   ```bash
+   mkdir -p ~/.codex/skills
+   ```
+
+3. **Add script paths to your environment** (optional but recommended):
+   ```bash
+   echo 'export PATH="$HOME/.codex/superpowers/scripts:$PATH"' >> ~/.bashrc
+   source ~/.bashrc
+   ```
+
+## Directory Structure
+
+After installation, you'll have:
+
+```
+~/.codex/
+├── superpowers/           # Core superpowers repository
+│   ├── skills/           # Core skills (brainstorming, TDD, etc.)
+│   ├── scripts/          # find-skills and skill-run tools
+│   └── .codex/           # Codex-specific configuration
+└── skills/               # Your personal skills (override core)
+    └── category/
+        └── skill-name/
+            └── SKILL.md
+```
+
+## Tool Usage
+
+### Finding Skills
+```bash
+find-skills                    # List all available skills
+find-skills brainstorm        # Filter skills by pattern
+```
+
+### Running Skills
+```bash
+skill-run brainstorming              # Load a skill
+skill-run skills/brainstorming       # Same thing
+```
+
+## Skill Override System
+
+Personal skills in `~/.codex/skills/` take precedence over core skills:
+
+- **Core skill**: `~/.codex/superpowers/skills/brainstorming/SKILL.md`
+- **Personal override**: `~/.codex/skills/brainstorming/SKILL.md` ← This wins
+
+## Bootstrap Setup
+
+The bootstrap system ensures Codex automatically:
+
+1. Reads the superpowers-bootstrap.md on startup
+2. Runs find-skills to show available skills
+3. Knows how to use the skill tools
+
+See `~/.codex/AGENTS.md` for the bootstrap configuration.
+
+## Troubleshooting
+
+### Scripts not found
+```bash
+# Add to PATH or use full paths:
+~/.codex/superpowers/scripts/find-skills
+~/.codex/superpowers/scripts/skill-run
+```
+
+### No skills showing
+```bash
+# Check directory structure:
+ls ~/.codex/superpowers/skills/
+ls ~/.codex/skills/
+```
+
+### Permission errors
+```bash
+# Make scripts executable:
+chmod +x ~/.codex/superpowers/scripts/*
+```
+
+## Creating Personal Skills
+
+1. Create directory structure:
+   ```bash
+   mkdir -p ~/.codex/skills/my-category/my-skill
+   ```
+
+2. Create SKILL.md with frontmatter:
+   ```markdown
+   ---
+   name: My Skill Name
+   description: What this skill does
+   when_to_use: When to apply this skill
+   ---
+
+   # My Skill
+
+   Skill content here...
+   ```
+
+3. Test it:
+   ```bash
+   find-skills my-skill
+   skill-run my-skill
+   ```
+
+## Integration with Codex
+
+Once installed, Codex will automatically have access to:
+
+- **find-skills**: Discover available skills
+- **skill-run**: Load and apply skills
+- **Mandatory workflows**: Brainstorming before coding, systematic debugging, etc.
+- **TodoWrite integration**: Checklist tracking from skills
+
+The bootstrap ensures these tools are available from the first Codex session.
+
+## Compatibility Notes
+
+- Scripts are compatible with bash 3.2+ (works on macOS and Linux)
+- No external dependencies required
+- Works with existing Codex configuration

+ 131 - 0
codex/superpowers-bootstrap.md

@@ -0,0 +1,131 @@
+# Superpowers Bootstrap for Codex
+
+<EXTREMELY_IMPORTANT>
+You have superpowers.
+
+**Tool path for running skills:**
+- superpowers-codex: ~/.codex/superpowers/scripts/superpowers-codex
+
+**Important:** ALL AVAILABLE SKILLS ARE DISCLOSED ABOVE. You have complete visibility into every skill at session start.
+
+**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 → `codex --yolo exec "prompt"` (see subagent section below)
+- `Skill` tool → `superpowers-codex use-skill` command (already available)
+- `Read`, `Write`, `Edit`, `Bash` → Use your native tools with similar functions
+</EXTREMELY_IMPORTANT>
+
+## Getting Started with Skills
+
+Two skill libraries work together:
+- **Superpowers skills** at `~/.codex/superpowers/skills/` (from superpowers repository)
+- **Personal skills** at `~/.codex/skills/` (yours to create and share)
+
+Personal skills shadow superpowers skills when names match.
+
+## Critical Rules
+
+1. **Use skill-run before announcing skill usage.** The bootstrap does NOT read skills for you. Announcing without calling skill-run = lying.
+
+2. **Follow mandatory workflows.** Brainstorming before coding. Check for skills before ANY task.
+
+3. **Create TodoWrite todos for checklists.** Mental tracking = steps get skipped. Every time.
+
+## Mandatory Workflow: Before ANY Task
+
+**1. Review skills list** (completely disclosed above - no searching needed).
+
+**2. If relevant skill exists, YOU MUST use it:**
+
+- Use superpowers-codex: `~/.codex/superpowers/scripts/superpowers-codex use-skill superpowers:skill-name`
+- Read ENTIRE output, not just summary
+- Announce: "I've read the [Skill Name] skill and I'm using it to [purpose]"
+- Follow it exactly
+
+**Don't rationalize:**
+- "I remember this skill" - Skills evolve. Read the current version.
+- "Bootstrap showed it to me" - That was just the list. Read the actual skill.
+- "This doesn't count as a task" - It counts. Find and read skills.
+
+**Why:** Skills document proven techniques that save time and prevent mistakes. Not using available skills means repeating solved problems and making known errors.
+
+## Skills with Checklists
+
+If a skill has a checklist, YOU MUST create TodoWrite todos for EACH item.
+
+**Don't:**
+- Work through checklist mentally
+- Skip creating todos "to save time"
+- Batch multiple items into one todo
+- Mark complete without doing them
+
+**Why:** Checklists without TodoWrite tracking = steps get skipped. Every time.
+
+## How to Use skill-run
+
+Every skill has the same structure:
+
+1. **Frontmatter** - `when_to_use` tells you if this skill matches your situation
+2. **Overview** - Core principle in 1-2 sentences
+3. **Quick Reference** - Scan for your specific pattern
+4. **Implementation** - Full details and examples
+5. **Supporting files** - Load only when implementing
+
+**Many skills contain rigid rules (TDD, debugging, verification).** Follow them exactly. Don't adapt away the discipline.
+
+**Some skills are flexible patterns (architecture, naming).** Adapt core principles to your context.
+
+## Instructions ≠ Permission to Skip Workflows
+
+Your human partner's specific instructions describe WHAT to do, not HOW.
+
+"Add X", "Fix Y" = the goal, NOT permission to skip brainstorming, TDD, or RED-GREEN-REFACTOR.
+
+## Summary
+
+**Starting any task:**
+1. Run find-skills to check for relevant skills
+2. If relevant skill exists → Use skill-run with full path
+3. Announce you're using it
+4. Follow what it says
+
+**Skill has checklist?** TodoWrite for every item.
+
+**Finding a relevant skill = mandatory to read and use it. Not optional.**
+
+## Subagent Orchestration for Codex
+
+When skills reference dispatching subagents or parallel agents, use Codex's subagent capabilities:
+
+**Launch subagents with:**
+```bash
+codex --yolo exec "your detailed prompt here"
+```
+
+**Key guidelines:**
+1. **Always quote/escape prompts** - avoid unescaped backticks or `$()` that shell might interpolate
+2. **Set timeout for long tasks** - use `timeout_ms: 1800000` (30 minutes) in your bash calls
+3. **Parallel execution** - use background jobs (`& ... & wait`) but check individual logs for completion
+4. **Lightweight prompts** - subagents inherit CLI defaults, so keep prompts focused and clear
+
+**Example:**
+```bash
+# Single subagent
+codex --yolo exec "Debug the authentication bug in user.py and propose a fix"
+
+# Parallel subagents
+codex --yolo exec "Test the API endpoints" &
+codex --yolo exec "Review the database schema" &
+wait
+
+# Using superpowers skills in subagents
+codex --yolo exec "Use superpowers:systematic-debugging to find the root cause of the login failure"
+```
+
+**When to use subagents:**
+- Skills mention "dispatching parallel agents"
+- Tasks that can be broken into independent work
+- Code review, testing, or investigation that benefits from fresh perspective
+
+---

+ 351 - 0
scripts/superpowers-codex

@@ -0,0 +1,351 @@
+#!/usr/bin/env node
+
+const fs = require('fs');
+const path = require('path');
+const os = require('os');
+
+// 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');
+
+// Utility functions
+function extractFrontmatter(filePath) {
+    try {
+        const content = fs.readFileSync(filePath, 'utf8');
+        const lines = content.split('\n');
+
+        let inFrontmatter = false;
+        let name = '';
+        let description = '';
+        let whenToUse = '';
+
+        for (const line of lines) {
+            if (line.trim() === '---') {
+                if (inFrontmatter) break;
+                inFrontmatter = true;
+                continue;
+            }
+
+            if (inFrontmatter) {
+                const match = line.match(/^(\w+):\s*(.*)$/);
+                if (match) {
+                    const [, key, value] = match;
+                    switch (key) {
+                        case 'name': name = value.trim(); break;
+                        case 'description': description = value.trim(); break;
+                        case 'when_to_use': whenToUse = value.trim(); break;
+                    }
+                }
+            }
+        }
+
+        return { name, description, whenToUse };
+    } catch (error) {
+        return { name: '', description: '', whenToUse: '' };
+    }
+}
+
+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, whenToUse } = extractFrontmatter(skillFile);
+
+    if (description) console.log(`  ${description}`);
+    if (whenToUse) console.log(`  When to use: ${whenToUse}`);
+    console.log('');
+}
+
+function findSkillsInDir(dir, sourceType, maxDepth = 1) {
+    const skills = [];
+
+    if (!fs.existsSync(dir)) return skills;
+
+    function searchDir(currentDir, currentDepth) {
+        if (currentDepth > maxDepth) return;
+
+        try {
+            const entries = fs.readdirSync(currentDir, { withFileTypes: true });
+
+            for (const entry of entries) {
+                if (entry.isDirectory()) {
+                    const skillDir = path.join(currentDir, entry.name);
+                    const skillFile = path.join(skillDir, 'SKILL.md');
+
+                    if (fs.existsSync(skillFile)) {
+                        skills.push(skillDir);
+                    }
+
+                    // For personal skills, search deeper (category/skill structure)
+                    if (sourceType === 'personal' && currentDepth < maxDepth) {
+                        searchDir(skillDir, currentDepth + 1);
+                    }
+                }
+            }
+        } catch (error) {
+            // Ignore permission errors or other issues
+        }
+    }
+
+    searchDir(dir, 0);
+    return skills;
+}
+
+// Commands
+function runFindSkills() {
+    console.log('Available skills:');
+    console.log('==================');
+    console.log('');
+
+    const foundSkills = new Set();
+
+    // Find personal skills first (these take precedence)
+    const personalSkills = findSkillsInDir(personalSkillsDir, 'personal', 2);
+    for (const skillPath of personalSkills) {
+        const relPath = path.relative(personalSkillsDir, skillPath);
+        foundSkills.add(relPath);
+        printSkill(skillPath, 'personal');
+    }
+
+    // Find superpowers skills (only if not already found in personal)
+    const superpowersSkills = findSkillsInDir(superpowersSkillsDir, 'superpowers', 1);
+    for (const skillPath of superpowersSkills) {
+        const relPath = path.relative(superpowersSkillsDir, skillPath);
+        if (!foundSkills.has(relPath)) {
+            printSkill(skillPath, '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('');
+
+    // 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
+    let content, frontmatter;
+    try {
+        const fullContent = fs.readFileSync(skillFile, 'utf8');
+        const { name, description, whenToUse } = extractFrontmatter(skillFile);
+
+        // Extract just the content after frontmatter
+        const lines = fullContent.split('\n');
+        let inFrontmatter = false;
+        let frontmatterEnded = false;
+        const contentLines = [];
+
+        for (const line of lines) {
+            if (line.trim() === '---') {
+                if (inFrontmatter) {
+                    frontmatterEnded = true;
+                    continue;
+                }
+                inFrontmatter = true;
+                continue;
+            }
+
+            if (frontmatterEnded || !inFrontmatter) {
+                contentLines.push(line);
+            }
+        }
+
+        content = contentLines.join('\n').trim();
+        frontmatter = { name, description, whenToUse };
+    } 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}`);
+    }
+    if (frontmatter.whenToUse) {
+        console.log(`# When to use: ${frontmatter.whenToUse}`);
+    }
+    console.log(`# Supporting tools and docs are 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;
+}