All skills
Skillintermediate

OpenCode Support Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Claude Code Knowledge Pack7/10/2026

Overview

OpenCode Support Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Add full superpowers support for OpenCode.ai with a native JavaScript plugin that shares core functionality with the existing Codex implementation.

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

#!/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('\
');

        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

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:

/**
 * 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:

module.exports = {
    extractFrontmatter,
    findSkillsInDir
};

Step 3: Verify syntax

Run: node -c lib/skills-core.js Expected: No output (success)

Step 4: Commit

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:

/**
 * 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

module.exports = {
    extractFrontmatter,
    findSkillsInDir,
    resolveSkillPath
};

Step 3: Verify syntax

Run: node -c lib/skills-core.js Expected: No output

Step 4: Commit

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:

const { execSync } = require('child_process');

Add before module.exports:

/**
 * 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('\
');
        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

module.exports = {
    extractFrontmatter,
    findSkillsInDir,
    resolveSkillPath,
    checkForUpdates
};

Step 3: Verify syntax

Run: node -c lib/skills-core.js Expected: No output

Step 4: Commit

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:

const skillsCore = require('../lib/skills-core');

Step 2: Verify syntax

Run: node -c .codex/superpowers-codex Expected: No output

Step 3: Commit

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

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

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

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

#!/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
 */

  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

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:


  // 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.\
\
Run 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('\
');
          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('\
').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

git add .opencode/plugin/superpowers.js
git commit -m "feat: implement use_skill tool for opencode"

Task 11: Implement find_skills Tool

Files:

  • Modif