Browse Source

docs: add implementation plan

Jesse Vincent 9 months ago
parent
commit
7db10cf540
1 changed files with 1095 additions and 0 deletions
  1. 1095 0
      docs/plans/2025-11-22-opencode-support-implementation.md

+ 1095 - 0
docs/plans/2025-11-22-opencode-support-implementation.md

@@ -0,0 +1,1095 @@
+# OpenCode Support Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
+
+**Goal:** Add full superpowers support for OpenCode.ai with a native JavaScript plugin that shares core functionality with the existing Codex implementation.
+
+**Architecture:** Extract common skill discovery/parsing logic into `lib/skills-core.js`, refactor Codex to use it, then build OpenCode plugin using their native plugin API with custom tools and session hooks.
+
+**Tech Stack:** Node.js, JavaScript, OpenCode Plugin API, Git worktrees
+
+---
+
+## Phase 1: Create Shared Core Module
+
+### Task 1: Extract Frontmatter Parsing
+
+**Files:**
+- Create: `lib/skills-core.js`
+- Reference: `.codex/superpowers-codex` (lines 40-74)
+
+**Step 1: Create lib/skills-core.js with extractFrontmatter function**
+
+```javascript
+#!/usr/bin/env node
+
+const fs = require('fs');
+const path = require('path');
+
+/**
+ * Extract YAML frontmatter from a skill file.
+ * Current format:
+ * ---
+ * name: skill-name
+ * description: Use when [condition] - [what it does]
+ * ---
+ *
+ * @param {string} filePath - Path to SKILL.md file
+ * @returns {{name: string, description: string}}
+ */
+function extractFrontmatter(filePath) {
+    try {
+        const content = fs.readFileSync(filePath, 'utf8');
+        const lines = content.split('\n');
+
+        let inFrontmatter = false;
+        let name = '';
+        let description = '';
+
+        for (const line of lines) {
+            if (line.trim() === '---') {
+                if (inFrontmatter) break;
+                inFrontmatter = true;
+                continue;
+            }
+
+            if (inFrontmatter) {
+                const match = line.match(/^(\w+):\s*(.*)$/);
+                if (match) {
+                    const [, key, value] = match;
+                    switch (key) {
+                        case 'name':
+                            name = value.trim();
+                            break;
+                        case 'description':
+                            description = value.trim();
+                            break;
+                    }
+                }
+            }
+        }
+
+        return { name, description };
+    } catch (error) {
+        return { name: '', description: '' };
+    }
+}
+
+module.exports = {
+    extractFrontmatter
+};
+```
+
+**Step 2: Verify file was created**
+
+Run: `ls -l lib/skills-core.js`
+Expected: File exists
+
+**Step 3: Commit**
+
+```bash
+git add lib/skills-core.js
+git commit -m "feat: create shared skills core module with frontmatter parser"
+```
+
+---
+
+### Task 2: Extract Skill Discovery Logic
+
+**Files:**
+- Modify: `lib/skills-core.js`
+- Reference: `.codex/superpowers-codex` (lines 97-136)
+
+**Step 1: Add findSkillsInDir function to skills-core.js**
+
+Add before `module.exports`:
+
+```javascript
+/**
+ * Find all SKILL.md files in a directory recursively.
+ *
+ * @param {string} dir - Directory to search
+ * @param {string} sourceType - 'personal' or 'superpowers' for namespacing
+ * @param {number} maxDepth - Maximum recursion depth (default: 3)
+ * @returns {Array<{path: string, name: string, description: string, sourceType: string}>}
+ */
+function findSkillsInDir(dir, sourceType, maxDepth = 3) {
+    const skills = [];
+
+    if (!fs.existsSync(dir)) return skills;
+
+    function recurse(currentDir, depth) {
+        if (depth > maxDepth) return;
+
+        const entries = fs.readdirSync(currentDir, { withFileTypes: true });
+
+        for (const entry of entries) {
+            const fullPath = path.join(currentDir, entry.name);
+
+            if (entry.isDirectory()) {
+                // Check for SKILL.md in this directory
+                const skillFile = path.join(fullPath, 'SKILL.md');
+                if (fs.existsSync(skillFile)) {
+                    const { name, description } = extractFrontmatter(skillFile);
+                    skills.push({
+                        path: fullPath,
+                        skillFile: skillFile,
+                        name: name || entry.name,
+                        description: description || '',
+                        sourceType: sourceType
+                    });
+                }
+
+                // Recurse into subdirectories
+                recurse(fullPath, depth + 1);
+            }
+        }
+    }
+
+    recurse(dir, 0);
+    return skills;
+}
+```
+
+**Step 2: Update module.exports**
+
+Replace the exports line with:
+
+```javascript
+module.exports = {
+    extractFrontmatter,
+    findSkillsInDir
+};
+```
+
+**Step 3: Verify syntax**
+
+Run: `node -c lib/skills-core.js`
+Expected: No output (success)
+
+**Step 4: Commit**
+
+```bash
+git add lib/skills-core.js
+git commit -m "feat: add skill discovery function to core module"
+```
+
+---
+
+### Task 3: Extract Skill Resolution Logic
+
+**Files:**
+- Modify: `lib/skills-core.js`
+- Reference: `.codex/superpowers-codex` (lines 212-280)
+
+**Step 1: Add resolveSkillPath function**
+
+Add before `module.exports`:
+
+```javascript
+/**
+ * Resolve a skill name to its file path, handling shadowing
+ * (personal skills override superpowers skills).
+ *
+ * @param {string} skillName - Name like "superpowers:brainstorming" or "my-skill"
+ * @param {string} superpowersDir - Path to superpowers skills directory
+ * @param {string} personalDir - Path to personal skills directory
+ * @returns {{skillFile: string, sourceType: string, skillPath: string} | null}
+ */
+function resolveSkillPath(skillName, superpowersDir, personalDir) {
+    // Strip superpowers: prefix if present
+    const forceSuperpowers = skillName.startsWith('superpowers:');
+    const actualSkillName = forceSuperpowers ? skillName.replace(/^superpowers:/, '') : skillName;
+
+    // Try personal skills first (unless explicitly superpowers:)
+    if (!forceSuperpowers && personalDir) {
+        const personalPath = path.join(personalDir, actualSkillName);
+        const personalSkillFile = path.join(personalPath, 'SKILL.md');
+        if (fs.existsSync(personalSkillFile)) {
+            return {
+                skillFile: personalSkillFile,
+                sourceType: 'personal',
+                skillPath: actualSkillName
+            };
+        }
+    }
+
+    // Try superpowers skills
+    if (superpowersDir) {
+        const superpowersPath = path.join(superpowersDir, actualSkillName);
+        const superpowersSkillFile = path.join(superpowersPath, 'SKILL.md');
+        if (fs.existsSync(superpowersSkillFile)) {
+            return {
+                skillFile: superpowersSkillFile,
+                sourceType: 'superpowers',
+                skillPath: actualSkillName
+            };
+        }
+    }
+
+    return null;
+}
+```
+
+**Step 2: Update module.exports**
+
+```javascript
+module.exports = {
+    extractFrontmatter,
+    findSkillsInDir,
+    resolveSkillPath
+};
+```
+
+**Step 3: Verify syntax**
+
+Run: `node -c lib/skills-core.js`
+Expected: No output
+
+**Step 4: Commit**
+
+```bash
+git add lib/skills-core.js
+git commit -m "feat: add skill path resolution with shadowing support"
+```
+
+---
+
+### Task 4: Extract Update Check Logic
+
+**Files:**
+- Modify: `lib/skills-core.js`
+- Reference: `.codex/superpowers-codex` (lines 16-38)
+
+**Step 1: Add checkForUpdates function**
+
+Add at top after requires:
+
+```javascript
+const { execSync } = require('child_process');
+```
+
+Add before `module.exports`:
+
+```javascript
+/**
+ * Check if a git repository has updates available.
+ *
+ * @param {string} repoDir - Path to git repository
+ * @returns {boolean} - True if updates are available
+ */
+function checkForUpdates(repoDir) {
+    try {
+        // Quick check with 3 second timeout to avoid delays if network is down
+        const output = execSync('git fetch origin && git status --porcelain=v1 --branch', {
+            cwd: repoDir,
+            timeout: 3000,
+            encoding: 'utf8',
+            stdio: 'pipe'
+        });
+
+        // Parse git status output to see if we're behind
+        const statusLines = output.split('\n');
+        for (const line of statusLines) {
+            if (line.startsWith('## ') && line.includes('[behind ')) {
+                return true; // We're behind remote
+            }
+        }
+        return false; // Up to date
+    } catch (error) {
+        // Network down, git error, timeout, etc. - don't block bootstrap
+        return false;
+    }
+}
+```
+
+**Step 2: Update module.exports**
+
+```javascript
+module.exports = {
+    extractFrontmatter,
+    findSkillsInDir,
+    resolveSkillPath,
+    checkForUpdates
+};
+```
+
+**Step 3: Verify syntax**
+
+Run: `node -c lib/skills-core.js`
+Expected: No output
+
+**Step 4: Commit**
+
+```bash
+git add lib/skills-core.js
+git commit -m "feat: add git update checking to core module"
+```
+
+---
+
+## Phase 2: Refactor Codex to Use Shared Core
+
+### Task 5: Update Codex to Import Shared Core
+
+**Files:**
+- Modify: `.codex/superpowers-codex` (add import at top)
+
+**Step 1: Add import statement**
+
+After the existing requires at top of file (around line 6), add:
+
+```javascript
+const skillsCore = require('../lib/skills-core');
+```
+
+**Step 2: Verify syntax**
+
+Run: `node -c .codex/superpowers-codex`
+Expected: No output
+
+**Step 3: Commit**
+
+```bash
+git add .codex/superpowers-codex
+git commit -m "refactor: import shared skills core in codex"
+```
+
+---
+
+### Task 6: Replace extractFrontmatter with Core Version
+
+**Files:**
+- Modify: `.codex/superpowers-codex` (lines 40-74)
+
+**Step 1: Remove local extractFrontmatter function**
+
+Delete lines 40-74 (the entire extractFrontmatter function definition).
+
+**Step 2: Update all extractFrontmatter calls**
+
+Find and replace all calls from `extractFrontmatter(` to `skillsCore.extractFrontmatter(`
+
+Affected lines approximately: 90, 310
+
+**Step 3: Verify script still works**
+
+Run: `.codex/superpowers-codex find-skills | head -20`
+Expected: Shows list of skills
+
+**Step 4: Commit**
+
+```bash
+git add .codex/superpowers-codex
+git commit -m "refactor: use shared extractFrontmatter in codex"
+```
+
+---
+
+### Task 7: Replace findSkillsInDir with Core Version
+
+**Files:**
+- Modify: `.codex/superpowers-codex` (lines 97-136, approximately)
+
+**Step 1: Remove local findSkillsInDir function**
+
+Delete the entire `findSkillsInDir` function definition (approximately lines 97-136).
+
+**Step 2: Update all findSkillsInDir calls**
+
+Replace calls from `findSkillsInDir(` to `skillsCore.findSkillsInDir(`
+
+**Step 3: Verify script still works**
+
+Run: `.codex/superpowers-codex find-skills | head -20`
+Expected: Shows list of skills
+
+**Step 4: Commit**
+
+```bash
+git add .codex/superpowers-codex
+git commit -m "refactor: use shared findSkillsInDir in codex"
+```
+
+---
+
+### Task 8: Replace checkForUpdates with Core Version
+
+**Files:**
+- Modify: `.codex/superpowers-codex` (lines 16-38, approximately)
+
+**Step 1: Remove local checkForUpdates function**
+
+Delete the entire `checkForUpdates` function definition.
+
+**Step 2: Update all checkForUpdates calls**
+
+Replace calls from `checkForUpdates(` to `skillsCore.checkForUpdates(`
+
+**Step 3: Verify script still works**
+
+Run: `.codex/superpowers-codex bootstrap | head -50`
+Expected: Shows bootstrap content
+
+**Step 4: Commit**
+
+```bash
+git add .codex/superpowers-codex
+git commit -m "refactor: use shared checkForUpdates in codex"
+```
+
+---
+
+## Phase 3: Build OpenCode Plugin
+
+### Task 9: Create OpenCode Plugin Directory Structure
+
+**Files:**
+- Create: `.opencode/plugin/superpowers.js`
+
+**Step 1: Create directory**
+
+Run: `mkdir -p .opencode/plugin`
+
+**Step 2: Create basic plugin file**
+
+```javascript
+#!/usr/bin/env node
+
+/**
+ * Superpowers plugin for OpenCode.ai
+ *
+ * Provides custom tools for loading and discovering skills,
+ * with automatic bootstrap on session start.
+ */
+
+const skillsCore = require('../../lib/skills-core');
+const path = require('path');
+const fs = require('fs');
+const os = require('os');
+
+const homeDir = os.homedir();
+const superpowersSkillsDir = path.join(homeDir, '.config/opencode/superpowers/skills');
+const personalSkillsDir = path.join(homeDir, '.config/opencode/skills');
+
+/**
+ * OpenCode plugin entry point
+ */
+export const SuperpowersPlugin = async ({ project, client, $, directory, worktree }) => {
+  return {
+    // Custom tools and hooks will go here
+  };
+};
+```
+
+**Step 3: Verify file was created**
+
+Run: `ls -l .opencode/plugin/superpowers.js`
+Expected: File exists
+
+**Step 4: Commit**
+
+```bash
+git add .opencode/plugin/superpowers.js
+git commit -m "feat: create opencode plugin scaffold"
+```
+
+---
+
+### Task 10: Implement use_skill Tool
+
+**Files:**
+- Modify: `.opencode/plugin/superpowers.js`
+
+**Step 1: Add use_skill tool implementation**
+
+Replace the plugin return statement with:
+
+```javascript
+export const SuperpowersPlugin = async ({ project, client, $, directory, worktree }) => {
+  // Import zod for schema validation
+  const { z } = await import('zod');
+
+  return {
+    tools: [
+      {
+        name: 'use_skill',
+        description: 'Load and read a specific skill to guide your work. Skills contain proven workflows, mandatory processes, and expert techniques.',
+        schema: z.object({
+          skill_name: z.string().describe('Name of the skill to load (e.g., "superpowers:brainstorming" or "my-custom-skill")')
+        }),
+        execute: async ({ skill_name }) => {
+          // Resolve skill path (handles shadowing: personal > superpowers)
+          const resolved = skillsCore.resolveSkillPath(
+            skill_name,
+            superpowersSkillsDir,
+            personalSkillsDir
+          );
+
+          if (!resolved) {
+            return `Error: Skill "${skill_name}" not found.\n\nRun find_skills to see available skills.`;
+          }
+
+          // Read skill content
+          const fullContent = fs.readFileSync(resolved.skillFile, 'utf8');
+          const { name, description } = skillsCore.extractFrontmatter(resolved.skillFile);
+
+          // Extract 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);
+            }
+          }
+
+          const content = contentLines.join('\n').trim();
+          const skillDirectory = path.dirname(resolved.skillFile);
+
+          // Format output similar to Claude Code's Skill tool
+          return `# ${name || skill_name}
+# ${description || ''}
+# Supporting tools and docs are in ${skillDirectory}
+# ============================================
+
+${content}`;
+        }
+      }
+    ]
+  };
+};
+```
+
+**Step 2: Verify syntax**
+
+Run: `node -c .opencode/plugin/superpowers.js`
+Expected: No output
+
+**Step 3: Commit**
+
+```bash
+git add .opencode/plugin/superpowers.js
+git commit -m "feat: implement use_skill tool for opencode"
+```
+
+---
+
+### Task 11: Implement find_skills Tool
+
+**Files:**
+- Modify: `.opencode/plugin/superpowers.js`
+
+**Step 1: Add find_skills tool to tools array**
+
+Add after the use_skill tool definition, before closing the tools array:
+
+```javascript
+      {
+        name: 'find_skills',
+        description: 'List all available skills in the superpowers and personal skill libraries.',
+        schema: z.object({}),
+        execute: async () => {
+          // Find skills in both directories
+          const superpowersSkills = skillsCore.findSkillsInDir(
+            superpowersSkillsDir,
+            'superpowers',
+            3
+          );
+          const personalSkills = skillsCore.findSkillsInDir(
+            personalSkillsDir,
+            'personal',
+            3
+          );
+
+          // Combine and format skills list
+          const allSkills = [...personalSkills, ...superpowersSkills];
+
+          if (allSkills.length === 0) {
+            return 'No skills found. Install superpowers skills to ~/.config/opencode/superpowers/skills/';
+          }
+
+          let output = 'Available skills:\n\n';
+
+          for (const skill of allSkills) {
+            const namespace = skill.sourceType === 'personal' ? '' : 'superpowers:';
+            const skillName = skill.name || path.basename(skill.path);
+
+            output += `${namespace}${skillName}\n`;
+            if (skill.description) {
+              output += `  ${skill.description}\n`;
+            }
+            output += `  Directory: ${skill.path}\n\n`;
+          }
+
+          return output;
+        }
+      }
+```
+
+**Step 2: Verify syntax**
+
+Run: `node -c .opencode/plugin/superpowers.js`
+Expected: No output
+
+**Step 3: Commit**
+
+```bash
+git add .opencode/plugin/superpowers.js
+git commit -m "feat: implement find_skills tool for opencode"
+```
+
+---
+
+### Task 12: Implement Session Start Hook
+
+**Files:**
+- Modify: `.opencode/plugin/superpowers.js`
+
+**Step 1: Add session.started hook**
+
+After the tools array, add:
+
+```javascript
+    'session.started': async () => {
+      // Read using-superpowers skill content
+      const usingSuperpowersPath = skillsCore.resolveSkillPath(
+        'using-superpowers',
+        superpowersSkillsDir,
+        personalSkillsDir
+      );
+
+      let usingSuperpowersContent = '';
+      if (usingSuperpowersPath) {
+        const fullContent = fs.readFileSync(usingSuperpowersPath.skillFile, 'utf8');
+        // Strip 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);
+          }
+        }
+
+        usingSuperpowersContent = contentLines.join('\n').trim();
+      }
+
+      // Tool mapping instructions
+      const toolMapping = `
+**Tool Mapping for OpenCode:**
+When skills reference tools you don't have, substitute OpenCode equivalents:
+- \`TodoWrite\` → \`update_plan\` (your planning/task tracking tool)
+- \`Task\` tool with subagents → Use OpenCode's subagent system (@mention syntax or automatic dispatch)
+- \`Skill\` tool → \`use_skill\` custom tool (already available)
+- \`Read\`, \`Write\`, \`Edit\`, \`Bash\` → Use your native tools
+
+**Skill directories contain supporting files:**
+- Scripts you can run with bash tool
+- Additional documentation you can read
+- Utilities and helpers specific to that skill
+
+**Skills naming:**
+- Superpowers skills: \`superpowers:skill-name\` (from ~/.config/opencode/superpowers/skills/)
+- Personal skills: \`skill-name\` (from ~/.config/opencode/skills/)
+- Personal skills override superpowers skills when names match
+`;
+
+      // Check for updates (non-blocking)
+      const hasUpdates = skillsCore.checkForUpdates(
+        path.join(homeDir, '.config/opencode/superpowers')
+      );
+
+      const updateNotice = hasUpdates ?
+        '\n\n⚠️ **Updates available!** Run `cd ~/.config/opencode/superpowers && git pull` to update superpowers.' :
+        '';
+
+      // Return context to inject into session
+      return {
+        context: `<EXTREMELY_IMPORTANT>
+You have superpowers.
+
+**Below is the full content of your 'superpowers:using-superpowers' skill - your introduction to using skills. For all other skills, use the 'use_skill' tool:**
+
+${usingSuperpowersContent}
+
+${toolMapping}${updateNotice}
+</EXTREMELY_IMPORTANT>`
+      };
+    }
+```
+
+**Step 2: Verify syntax**
+
+Run: `node -c .opencode/plugin/superpowers.js`
+Expected: No output
+
+**Step 3: Commit**
+
+```bash
+git add .opencode/plugin/superpowers.js
+git commit -m "feat: implement session.started hook for opencode"
+```
+
+---
+
+## Phase 4: Documentation
+
+### Task 13: Create OpenCode Installation Guide
+
+**Files:**
+- Create: `.opencode/INSTALL.md`
+
+**Step 1: Create installation guide**
+
+```markdown
+# Installing Superpowers for OpenCode
+
+## Prerequisites
+
+- [OpenCode.ai](https://opencode.ai) installed
+- Node.js installed
+- Git installed
+
+## Installation Steps
+
+### 1. Install Superpowers Skills
+
+```bash
+# Clone superpowers skills to OpenCode config directory
+mkdir -p ~/.config/opencode/superpowers
+git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
+```
+
+### 2. Install the Plugin
+
+The plugin is included in the superpowers repository you just cloned.
+
+OpenCode will automatically discover it from:
+- `~/.config/opencode/superpowers/.opencode/plugin/superpowers.js`
+
+Or you can link it to the project-local plugin directory:
+
+```bash
+# In your OpenCode project
+mkdir -p .opencode/plugin
+ln -s ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js .opencode/plugin/superpowers.js
+```
+
+### 3. Restart OpenCode
+
+Restart OpenCode to load the plugin. On the next session, you should see:
+
+```
+You have superpowers.
+```
+
+## Usage
+
+### Finding Skills
+
+Use the `find_skills` tool to list all available skills:
+
+```
+use find_skills tool
+```
+
+### Loading a Skill
+
+Use the `use_skill` tool to load a specific skill:
+
+```
+use use_skill tool with skill_name: "superpowers:brainstorming"
+```
+
+### Personal Skills
+
+Create your own skills in `~/.config/opencode/skills/`:
+
+```bash
+mkdir -p ~/.config/opencode/skills/my-skill
+```
+
+Create `~/.config/opencode/skills/my-skill/SKILL.md`:
+
+```markdown
+---
+name: my-skill
+description: Use when [condition] - [what it does]
+---
+
+# My Skill
+
+[Your skill content here]
+```
+
+Personal skills override superpowers skills with the same name.
+
+## Updating
+
+```bash
+cd ~/.config/opencode/superpowers
+git pull
+```
+
+## Troubleshooting
+
+### Plugin not loading
+
+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. 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 issues
+
+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
+- Documentation: https://github.com/obra/superpowers
+```
+
+**Step 2: Verify file created**
+
+Run: `ls -l .opencode/INSTALL.md`
+Expected: File exists
+
+**Step 3: Commit**
+
+```bash
+git add .opencode/INSTALL.md
+git commit -m "docs: add opencode installation guide"
+```
+
+---
+
+### Task 14: Update Main README
+
+**Files:**
+- Modify: `README.md`
+
+**Step 1: Add OpenCode section**
+
+Find the section about supported platforms (search for "Codex" in the file), and add after it:
+
+```markdown
+### OpenCode
+
+Superpowers works with [OpenCode.ai](https://opencode.ai) through a native JavaScript plugin.
+
+**Installation:** See [.opencode/INSTALL.md](.opencode/INSTALL.md)
+
+**Features:**
+- Custom tools: `use_skill` and `find_skills`
+- Automatic session bootstrap
+- Personal skills with shadowing
+- Supporting files and scripts access
+```
+
+**Step 2: Verify formatting**
+
+Run: `grep -A 10 "### OpenCode" README.md`
+Expected: Shows the section you added
+
+**Step 3: Commit**
+
+```bash
+git add README.md
+git commit -m "docs: add opencode support to readme"
+```
+
+---
+
+### Task 15: Update Release Notes
+
+**Files:**
+- Modify: `RELEASE-NOTES.md`
+
+**Step 1: Add entry for OpenCode support**
+
+At the top of the file (after the header), add:
+
+```markdown
+## [Unreleased]
+
+### Added
+
+- **OpenCode Support**: Native JavaScript plugin for OpenCode.ai
+  - Custom tools: `use_skill` and `find_skills`
+  - Automatic session bootstrap with tool mapping instructions
+  - Shared core module (`lib/skills-core.js`) for code reuse
+  - Installation guide in `.opencode/INSTALL.md`
+
+### Changed
+
+- **Refactored Codex Implementation**: Now uses shared `lib/skills-core.js` module
+  - Eliminates code duplication between Codex and OpenCode
+  - Single source of truth for skill discovery and parsing
+
+---
+
+```
+
+**Step 2: Verify formatting**
+
+Run: `head -30 RELEASE-NOTES.md`
+Expected: Shows your new section
+
+**Step 3: Commit**
+
+```bash
+git add RELEASE-NOTES.md
+git commit -m "docs: add opencode support to release notes"
+```
+
+---
+
+## Phase 5: Final Verification
+
+### Task 16: Test Codex Still Works
+
+**Files:**
+- Test: `.codex/superpowers-codex`
+
+**Step 1: Test find-skills command**
+
+Run: `.codex/superpowers-codex find-skills | head -20`
+Expected: Shows list of skills with names and descriptions
+
+**Step 2: Test use-skill command**
+
+Run: `.codex/superpowers-codex use-skill superpowers:brainstorming | head -20`
+Expected: Shows brainstorming skill content
+
+**Step 3: Test bootstrap command**
+
+Run: `.codex/superpowers-codex bootstrap | head -30`
+Expected: Shows bootstrap content with instructions
+
+**Step 4: If all tests pass, record success**
+
+No commit needed - this is verification only.
+
+---
+
+### Task 17: Verify File Structure
+
+**Files:**
+- Check: All new files exist
+
+**Step 1: Verify all files created**
+
+Run:
+```bash
+ls -l lib/skills-core.js
+ls -l .opencode/plugin/superpowers.js
+ls -l .opencode/INSTALL.md
+```
+
+Expected: All files exist
+
+**Step 2: Verify directory structure**
+
+Run: `tree -L 2 .opencode/` (or `find .opencode -type f` if tree not available)
+Expected:
+```
+.opencode/
+├── INSTALL.md
+└── plugin/
+    └── superpowers.js
+```
+
+**Step 3: If structure correct, proceed**
+
+No commit needed - this is verification only.
+
+---
+
+### Task 18: Final Commit and Summary
+
+**Files:**
+- Check: `git status`
+
+**Step 1: Check git status**
+
+Run: `git status`
+Expected: Working tree clean, all changes committed
+
+**Step 2: Review commit log**
+
+Run: `git log --oneline -20`
+Expected: Shows all commits from this implementation
+
+**Step 3: Create summary document**
+
+Create a completion summary showing:
+- Total commits made
+- Files created: `lib/skills-core.js`, `.opencode/plugin/superpowers.js`, `.opencode/INSTALL.md`
+- Files modified: `.codex/superpowers-codex`, `README.md`, `RELEASE-NOTES.md`
+- Testing performed: Codex commands verified
+- Ready for: Testing with actual OpenCode installation
+
+**Step 4: Report completion**
+
+Present summary to user and offer to:
+1. Push to remote
+2. Create pull request
+3. Test with real OpenCode installation (requires OpenCode installed)
+
+---
+
+## Testing Guide (Manual - Requires OpenCode)
+
+These steps require OpenCode to be installed and are not part of the automated implementation:
+
+1. **Install skills**: Follow `.opencode/INSTALL.md`
+2. **Start OpenCode session**: Verify bootstrap appears
+3. **Test find_skills**: Should list all available skills
+4. **Test use_skill**: Load a skill and verify content appears
+5. **Test supporting files**: Verify skill directory paths are accessible
+6. **Test personal skills**: Create a personal skill and verify it shadows core
+7. **Test tool mapping**: Verify TodoWrite → update_plan mapping works
+
+## Success Criteria
+
+- [ ] `lib/skills-core.js` created with all core functions
+- [ ] `.codex/superpowers-codex` refactored to use shared core
+- [ ] Codex commands still work (find-skills, use-skill, bootstrap)
+- [ ] `.opencode/plugin/superpowers.js` created with tools and hooks
+- [ ] Installation guide created
+- [ ] README and RELEASE-NOTES updated
+- [ ] All changes committed
+- [ ] Working tree clean