Bladeren bron

feat(opencode): use native skills and fix agent reset bug (#226) (#330)

* fix use_skill agent context (#290)

* fix: respect OPENCODE_CONFIG_DIR for personal skills lookup (#297)

* fix: respect OPENCODE_CONFIG_DIR for personal skills lookup

The plugin was hardcoded to look for personal skills in ~/.config/opencode/skills,
ignoring users who set OPENCODE_CONFIG_DIR to a custom path (e.g., for dotfiles management).

Now uses OPENCODE_CONFIG_DIR if set, falling back to the default path.

* fix: update help text to use dynamic paths

Use configDir and personalSkillsDir variables in help text so paths
are accurate when OPENCODE_CONFIG_DIR is set.

* fix: normalize OPENCODE_CONFIG_DIR before use

Handle edge cases where the env var might be:
- Empty or whitespace-only
- Using ~ for home directory (common in .env files)
- A relative path

Now trims, expands ~, and resolves to absolute path.

* feat(opencode): use native skills and fix agent reset bug (#226)

- Replace custom use_skill/find_skills tools with OpenCode's native skill tool
- Use experimental.chat.system.transform hook instead of session.prompt
  (fixes #226 agent reset on first message)
- Symlink skills directory into ~/.config/opencode/skills/superpowers/
- Update installation docs with comprehensive Windows support:
  - Command Prompt, PowerShell, and Git Bash instructions
  - Proper symlink vs junction handling
  - Reinstall safety with cleanup steps
  - Verification commands for each shell

* Add OpenCode native skills changes to release notes

Documents:
- Breaking change: switch to native skill tool
- Fix for agent reset bug (#226)
- Fix for Windows installation (#232)

---------

Co-authored-by: Vinicius da Motta <viniciusmotta8@gmail.com>
Co-authored-by: oribi <oribarilan@gmail.com>
Jesse Vincent 7 maanden geleden
bovenliggende
commit
3964d18670
3 gewijzigde bestanden met toevoegingen van 235 en 258 verwijderingen
  1. 40 179
      .opencode/plugin/superpowers.js
  2. 24 0
      RELEASE-NOTES.md
  3. 171 79
      docs/README.opencode.md

+ 40 - 179
.opencode/plugin/superpowers.js

@@ -1,73 +1,81 @@
 /**
  * Superpowers plugin for OpenCode.ai
  *
- * Provides custom tools for loading and discovering skills,
- * with prompt generation for agent configuration.
+ * Injects superpowers bootstrap context via system prompt transform.
+ * Skills are discovered via OpenCode's native skill tool from symlinked directory.
  */
 
 import path from 'path';
 import fs from 'fs';
 import os from 'os';
 import { fileURLToPath } from 'url';
-import { tool } from '@opencode-ai/plugin/tool';
-import * as skillsCore from '../../lib/skills-core.js';
 
 const __dirname = path.dirname(fileURLToPath(import.meta.url));
 
+// Simple frontmatter extraction (avoid dependency on skills-core for bootstrap)
+const extractAndStripFrontmatter = (content) => {
+  const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
+  if (!match) return { frontmatter: {}, content };
+
+  const frontmatterStr = match[1];
+  const body = match[2];
+  const frontmatter = {};
+
+  for (const line of frontmatterStr.split('\n')) {
+    const colonIdx = line.indexOf(':');
+    if (colonIdx > 0) {
+      const key = line.slice(0, colonIdx).trim();
+      const value = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, '');
+      frontmatter[key] = value;
+    }
+  }
+
+  return { frontmatter, content: body };
+};
+
 // Normalize a path: trim whitespace, expand ~, resolve to absolute
 const normalizePath = (p, homeDir) => {
   if (!p || typeof p !== 'string') return null;
   let normalized = p.trim();
   if (!normalized) return null;
-  // Expand ~ to home directory
   if (normalized.startsWith('~/')) {
     normalized = path.join(homeDir, normalized.slice(2));
   } else if (normalized === '~') {
     normalized = homeDir;
   }
-  // Resolve to absolute path
   return path.resolve(normalized);
 };
 
 export const SuperpowersPlugin = async ({ client, directory }) => {
   const homeDir = os.homedir();
-  const projectSkillsDir = path.join(directory, '.opencode/skills');
-  // Derive superpowers skills dir from plugin location (works for both symlinked and local installs)
   const superpowersSkillsDir = path.resolve(__dirname, '../../skills');
-  // Respect OPENCODE_CONFIG_DIR if set, otherwise fall back to default
   const envConfigDir = normalizePath(process.env.OPENCODE_CONFIG_DIR, homeDir);
   const configDir = envConfigDir || path.join(homeDir, '.config/opencode');
-  const personalSkillsDir = path.join(configDir, 'skills');
 
   // Helper to generate bootstrap content
-  const getBootstrapContent = (compact = false) => {
-    const usingSuperpowersPath = skillsCore.resolveSkillPath('using-superpowers', superpowersSkillsDir, personalSkillsDir);
-    if (!usingSuperpowersPath) return null;
-
-    const fullContent = fs.readFileSync(usingSuperpowersPath.skillFile, 'utf8');
-    const content = skillsCore.stripFrontmatter(fullContent);
+  const getBootstrapContent = () => {
+    // Try to load using-superpowers skill
+    const skillPath = path.join(superpowersSkillsDir, 'using-superpowers', 'SKILL.md');
+    if (!fs.existsSync(skillPath)) return null;
 
-    const toolMapping = compact
-      ? `**Tool Mapping:** TodoWrite->update_plan, Task->@mention, Skill->use_skill
+    const fullContent = fs.readFileSync(skillPath, 'utf8');
+    const { content } = extractAndStripFrontmatter(fullContent);
 
-**Skills naming (priority order):** project: > personal > superpowers:`
-      : `**Tool Mapping for OpenCode:**
+    const toolMapping = `**Tool Mapping for OpenCode:**
 When skills reference tools you don't have, substitute OpenCode equivalents:
 - \`TodoWrite\` → \`update_plan\`
 - \`Task\` tool with subagents → Use OpenCode's subagent system (@mention)
-- \`Skill\` tool → \`use_skill\` custom tool
+- \`Skill\` tool → OpenCode's native \`skill\` tool
 - \`Read\`, \`Write\`, \`Edit\`, \`Bash\` → Your native tools
 
-**Skills naming (priority order):**
-- Project skills: \`project:skill-name\` (in .opencode/skills/)
-- Personal skills: \`skill-name\` (in ${configDir}/skills/)
-- Superpowers skills: \`superpowers:skill-name\`
-- Project skills override personal, which override superpowers when names match`;
+**Skills location:**
+Superpowers skills are in \`${configDir}/skills/superpowers/\`
+Use OpenCode's native \`skill\` tool to list and load skills.`;
 
     return `<EXTREMELY_IMPORTANT>
 You have superpowers.
 
-**IMPORTANT: The using-superpowers skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the use_skill tool to load "using-superpowers" - that would be redundant. Use use_skill only for OTHER skills.**
+**IMPORTANT: The using-superpowers skill content is included below. It is ALREADY LOADED - you are currently following it. Do NOT use the skill tool to load "using-superpowers" again - that would be redundant.**
 
 ${content}
 
@@ -75,159 +83,12 @@ ${toolMapping}
 </EXTREMELY_IMPORTANT>`;
   };
 
-  // Helper to inject bootstrap via session.prompt
-  const injectBootstrap = async (sessionID, compact = false) => {
-    const bootstrapContent = getBootstrapContent(compact);
-    if (!bootstrapContent) return false;
-
-    try {
-      await client.session.prompt({
-        path: { id: sessionID },
-        body: {
-          noReply: true,
-          parts: [{ type: "text", text: bootstrapContent, synthetic: true }]
-        }
-      });
-      return true;
-    } catch (err) {
-      return false;
-    }
-  };
-
   return {
-    tool: {
-      use_skill: tool({
-        description: 'Load and read a specific skill to guide your work. Skills contain proven workflows, mandatory processes, and expert techniques.',
-        args: {
-          skill_name: tool.schema.string().describe('Name of the skill to load (e.g., "superpowers:brainstorming", "my-custom-skill", or "project:my-skill")')
-        },
-        execute: async (args, context) => {
-          const { skill_name } = args;
-
-          // Resolve with priority: project > personal > superpowers
-          // Check for project: prefix first
-          const forceProject = skill_name.startsWith('project:');
-          const actualSkillName = forceProject ? skill_name.replace(/^project:/, '') : skill_name;
-
-          let resolved = null;
-
-          // Try project skills first (if project: prefix or no prefix)
-          if (forceProject || !skill_name.startsWith('superpowers:')) {
-            const projectPath = path.join(projectSkillsDir, actualSkillName);
-            const projectSkillFile = path.join(projectPath, 'SKILL.md');
-            if (fs.existsSync(projectSkillFile)) {
-              resolved = {
-                skillFile: projectSkillFile,
-                sourceType: 'project',
-                skillPath: actualSkillName
-              };
-            }
-          }
-
-          // Fall back to personal/superpowers resolution
-          if (!resolved && !forceProject) {
-            resolved = skillsCore.resolveSkillPath(skill_name, superpowersSkillsDir, personalSkillsDir);
-          }
-
-          if (!resolved) {
-            return `Error: Skill "${skill_name}" not found.\n\nRun find_skills to see available skills.`;
-          }
-
-          const fullContent = fs.readFileSync(resolved.skillFile, 'utf8');
-          const { name, description } = skillsCore.extractFrontmatter(resolved.skillFile);
-          const content = skillsCore.stripFrontmatter(fullContent);
-          const skillDirectory = path.dirname(resolved.skillFile);
-
-          const skillHeader = `# ${name || skill_name}
-# ${description || ''}
-# Supporting tools and docs are in ${skillDirectory}
-# ============================================`;
-
-          // Insert as user message with noReply for persistence across compaction
-          try {
-            await client.session.prompt({
-              path: { id: context.sessionID },
-              body: {
-                agent: context.agent,
-                noReply: true,
-                parts: [
-                  { type: "text", text: `Loading skill: ${name || skill_name}`, synthetic: true },
-                  { type: "text", text: `${skillHeader}\n\n${content}`, synthetic: true }
-                ]
-              }
-            });
-          } catch (err) {
-            // Fallback: return content directly if message insertion fails
-            return `${skillHeader}\n\n${content}`;
-          }
-
-          return `Launching skill: ${name || skill_name}`;
-        }
-      }),
-      find_skills: tool({
-        description: 'List all available skills in the project, personal, and superpowers skill libraries.',
-        args: {},
-        execute: async (args, context) => {
-          const projectSkills = skillsCore.findSkillsInDir(projectSkillsDir, 'project', 3);
-          const personalSkills = skillsCore.findSkillsInDir(personalSkillsDir, 'personal', 3);
-          const superpowersSkills = skillsCore.findSkillsInDir(superpowersSkillsDir, 'superpowers', 3);
-
-          // Priority: project > personal > superpowers
-          const allSkills = [...projectSkills, ...personalSkills, ...superpowersSkills];
-
-          if (allSkills.length === 0) {
-            return `No skills found. Install superpowers skills to ${superpowersSkillsDir}/ or add personal skills to ${personalSkillsDir}/`;
-          }
-
-          let output = 'Available skills:\n\n';
-
-          for (const skill of allSkills) {
-            let namespace;
-            switch (skill.sourceType) {
-              case 'project':
-                namespace = 'project:';
-                break;
-              case 'personal':
-                namespace = '';
-                break;
-              default:
-                namespace = '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;
-        }
-      })
-    },
-    event: async ({ event }) => {
-      // Extract sessionID from various event structures
-      const getSessionID = () => {
-        return event.properties?.info?.id ||
-               event.properties?.sessionID ||
-               event.session?.id;
-      };
-
-      // Inject bootstrap at session creation (before first user message)
-      if (event.type === 'session.created') {
-        const sessionID = getSessionID();
-        if (sessionID) {
-          await injectBootstrap(sessionID, false);
-        }
-      }
-
-      // Re-inject bootstrap after context compaction (compact version to save tokens)
-      if (event.type === 'session.compacted') {
-        const sessionID = getSessionID();
-        if (sessionID) {
-          await injectBootstrap(sessionID, true);
-        }
+    // Use system prompt transform to inject bootstrap (fixes #226 agent reset bug)
+    'experimental.chat.system.transform': async (_input, output) => {
+      const bootstrap = getBootstrapContent();
+      if (bootstrap) {
+        (output.system ||= []).push(bootstrap);
       }
     }
   };

+ 24 - 0
RELEASE-NOTES.md

@@ -1,5 +1,29 @@
 # Superpowers Release Notes
 
+## Unreleased
+
+### 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
+
+---
+
 ## v4.0.3 (2025-12-26)
 
 ### Improvements

+ 171 - 79
docs/README.opencode.md

@@ -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/plugin, then symlink ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js to ~/.config/opencode/plugin/superpowers.js, 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
@@ -15,59 +15,171 @@ Clone https://github.com/obra/superpowers to ~/.config/opencode/superpowers, the
 ### Prerequisites
 
 - [OpenCode.ai](https://opencode.ai) installed
-- Node.js installed
 - Git installed
 
-### Installation Steps
+### macOS / Linux
 
-#### 1. Install Superpowers
+```bash
+# 1. Install Superpowers (or update existing)
+if [ -d ~/.config/opencode/superpowers ]; then
+  cd ~/.config/opencode/superpowers && git pull
+else
+  git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
+fi
+
+# 2. Create directories
+mkdir -p ~/.config/opencode/plugin ~/.config/opencode/skills
+
+# 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. Restart OpenCode
+```
+
+#### Verify Installation
 
 ```bash
-mkdir -p ~/.config/opencode/superpowers
-git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
+ls -l ~/.config/opencode/plugin/superpowers.js
+ls -l ~/.config/opencode/skills/superpowers
 ```
 
-#### 2. Register the Plugin
+Both should show symlinks pointing to the superpowers directory.
 
-OpenCode discovers plugins from `~/.config/opencode/plugin/`. Create a symlink:
+### Windows
 
-```bash
-mkdir -p ~/.config/opencode/plugin
-ln -sf ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js ~/.config/opencode/plugin/superpowers.js
+**Prerequisites:**
+- Git installed
+- Either **Developer Mode** enabled OR **Administrator privileges**
+  - Windows 10: Settings → Update & Security → For developers
+  - Windows 11: Settings → System → For developers
+
+Pick your shell below: [Command Prompt](#command-prompt) | [PowerShell](#powershell) | [Git Bash](#git-bash)
+
+#### Command Prompt
+
+Run as Administrator, or with Developer Mode enabled:
+
+```cmd
+:: 1. Install Superpowers
+git clone https://github.com/obra/superpowers.git "%USERPROFILE%\.config\opencode\superpowers"
+
+:: 2. Create directories
+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\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\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"
+
+:: 6. Restart OpenCode
 ```
 
-Alternatively, for project-local installation:
+#### PowerShell
+
+Run as Administrator, or with Developer Mode enabled:
+
+```powershell
+# 1. Install Superpowers
+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\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\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\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"
+
+# 6. Restart OpenCode
+```
+
+#### Git Bash
+
+Note: Git Bash's native `ln` command copies files instead of creating symlinks. Use `cmd //c mklink` instead (the `//c` is Git Bash syntax for `/c`).
 
 ```bash
-# In your OpenCode project
-mkdir -p .opencode/plugin
-ln -sf ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js .opencode/plugin/superpowers.js
+# 1. Install Superpowers
+git clone https://github.com/obra/superpowers.git ~/.config/opencode/superpowers
+
+# 2. Create directories
+mkdir -p ~/.config/opencode/plugin ~/.config/opencode/skills
+
+# 3. Remove existing links (safe for reinstalls)
+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/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)\""
+
+# 6. Restart OpenCode
+```
+
+#### WSL Users
+
+If running OpenCode inside WSL, use the [macOS / Linux](#macos--linux) instructions instead.
+
+#### Verify Installation
+
+**Command Prompt:**
+```cmd
+dir /AL "%USERPROFILE%\.config\opencode\plugin"
+dir /AL "%USERPROFILE%\.config\opencode\skills"
+```
+
+**PowerShell:**
+```powershell
+Get-ChildItem "$env:USERPROFILE\.config\opencode\plugin" | Where-Object { $_.LinkType }
+Get-ChildItem "$env:USERPROFILE\.config\opencode\skills" | Where-Object { $_.LinkType }
 ```
 
-#### 3. Restart OpenCode
+Look for `<SYMLINK>` or `<JUNCTION>` in the output.
+
+#### Troubleshooting Windows
+
+**"You do not have sufficient privilege" error:**
+- Enable Developer Mode in Windows Settings, OR
+- Right-click your terminal → "Run as Administrator"
+
+**"Cannot create a file when that file already exists":**
+- Run the removal commands (step 3) first, then retry
 
-Restart OpenCode to load the plugin. Superpowers will automatically activate.
+**Symlinks not working after git clone:**
+- Run `git config --global core.symlinks true` and re-clone
 
 ## Usage
 
 ### Finding Skills
 
-Use the `find_skills` tool to list all available skills:
+Use OpenCode's native `skill` tool to list all available skills:
 
 ```
-use find_skills tool
+use skill tool to list skills
 ```
 
 ### Loading a Skill
 
-Use the `use_skill` tool to load a specific skill:
+Use OpenCode's native `skill` tool to load a specific skill:
 
 ```
-use use_skill tool with skill_name: "superpowers:brainstorming"
+use skill tool to load superpowers/brainstorming
 ```
 
-Skills are automatically inserted into the conversation and persist across context compaction.
-
 ### Personal Skills
 
 Create your own skills in `~/.config/opencode/skills/`:
@@ -111,40 +223,31 @@ description: Use when [condition] - [what it does]
 [Your skill content here]
 ```
 
-## Skill Priority
+## Skill Locations
 
-Skills are resolved with this priority order:
+OpenCode discovers skills from these locations:
 
 1. **Project skills** (`.opencode/skills/`) - Highest priority
 2. **Personal skills** (`~/.config/opencode/skills/`)
-3. **Superpowers skills** (`~/.config/opencode/superpowers/skills/`)
-
-You can force resolution to a specific level:
-- `project:skill-name` - Force project skill
-- `skill-name` - Search project → personal → superpowers
-- `superpowers:skill-name` - Force superpowers skill
+3. **Superpowers skills** (`~/.config/opencode/skills/superpowers/`) - via symlink
 
 ## Features
 
 ### Automatic Context Injection
 
-The plugin automatically injects superpowers context via the chat.message hook on every session. No manual configuration needed.
-
-### Message Insertion Pattern
+The plugin automatically injects superpowers context via the `experimental.chat.system.transform` hook. This adds the "using-superpowers" skill content to the system prompt on every request.
 
-When you load a skill with `use_skill`, it's inserted as a user message with `noReply: true`. This ensures skills persist throughout long conversations, even when OpenCode compacts context.
+### Native Skills Integration
 
-### Compaction Resilience
-
-The plugin listens for `session.compacted` events and automatically re-injects the core superpowers bootstrap to maintain functionality after context compaction.
+Superpowers uses OpenCode's native `skill` tool for skill discovery and loading. Skills are symlinked into `~/.config/opencode/skills/superpowers/` so they appear alongside your personal and project skills.
 
 ### Tool Mapping
 
-Skills written for Claude Code are automatically adapted for OpenCode. The plugin provides mapping instructions:
+Skills written for Claude Code are automatically adapted for OpenCode. The bootstrap provides mapping instructions:
 
 - `TodoWrite` → `update_plan`
 - `Task` with subagents → OpenCode's `@mention` system
-- `Skill` tool → `use_skill` custom tool
+- `Skill` tool → OpenCode's native `skill` tool
 - File operations → Native OpenCode tools
 
 ## Architecture
@@ -154,23 +257,14 @@ Skills written for Claude Code are automatically adapted for OpenCode. The plugi
 **Location:** `~/.config/opencode/superpowers/.opencode/plugin/superpowers.js`
 
 **Components:**
-- Two custom tools: `use_skill`, `find_skills`
-- chat.message hook for initial context injection
-- event handler for session.compacted re-injection
-- Uses shared `lib/skills-core.js` module (also used by Codex)
-
-### Shared Core Module
+- `experimental.chat.system.transform` hook for bootstrap injection
+- Reads and injects the "using-superpowers" skill content
 
-**Location:** `~/.config/opencode/superpowers/lib/skills-core.js`
+### Skills
 
-**Functions:**
-- `extractFrontmatter()` - Parse skill metadata
-- `stripFrontmatter()` - Remove metadata from content
-- `findSkillsInDir()` - Recursive skill discovery
-- `resolveSkillPath()` - Skill resolution with shadowing
-- `checkForUpdates()` - Git update detection
+**Location:** `~/.config/opencode/skills/superpowers/` (symlink to `~/.config/opencode/superpowers/skills/`)
 
-This module is shared between OpenCode and Codex implementations for code reuse.
+Skills are discovered by OpenCode's native skill system. Each skill has a `SKILL.md` file with YAML frontmatter.
 
 ## Updating
 
@@ -185,28 +279,28 @@ Restart OpenCode to load the updates.
 
 ### Plugin not loading
 
-1. Check plugin file exists: `ls ~/.config/opencode/superpowers/.opencode/plugin/superpowers.js`
-2. Check symlink: `ls -l ~/.config/opencode/plugin/superpowers.js`
+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: `service=plugin path=file:///.../superpowers.js loading plugin`
+4. Look for plugin loading message in logs
 
 ### Skills not found
 
-1. Verify skills directory: `ls ~/.config/opencode/superpowers/skills`
-2. Use `find_skills` tool to see what's discovered
-3. Check skill structure: each skill needs a `SKILL.md` file
+1. Verify skills symlink: `ls -l ~/.config/opencode/skills/superpowers` (should point to superpowers/skills/)
+2. Use OpenCode's `skill` tool to list available skills
+3. Check skill structure: each skill needs a `SKILL.md` file with valid frontmatter
 
-### Tools not working
+### Windows: Module not found error
 
-1. Verify plugin loaded: Check OpenCode logs for plugin loading message
-2. Check Node.js version: The plugin requires Node.js for ES modules
-3. Test plugin manually: `node --input-type=module -e "import('file://~/.config/opencode/plugin/superpowers.js').then(m => console.log(Object.keys(m)))"`
+If you see `Cannot find module` errors on Windows:
+- **Cause:** Git Bash `ln -sf` copies files instead of creating symlinks
+- **Fix:** Use `mklink /J` directory junctions instead (see Windows installation steps)
 
-### Context not injecting
+### Bootstrap not appearing
 
-1. Check if chat.message hook is working
-2. Verify using-superpowers skill exists
-3. Check OpenCode version (requires recent version with plugin support)
+1. Verify using-superpowers skill exists: `ls ~/.config/opencode/superpowers/skills/using-superpowers/SKILL.md`
+2. Check OpenCode version supports `experimental.chat.system.transform` hook
+3. Restart OpenCode after plugin changes
 
 ## Getting Help
 
@@ -216,19 +310,17 @@ Restart OpenCode to load the updates.
 
 ## Testing
 
-The implementation includes an automated test suite at `tests/opencode/`:
+Verify your installation:
 
 ```bash
-# Run all tests
-./tests/opencode/run-tests.sh --integration --verbose
+# Check plugin loads
+opencode run --print-logs "hello" 2>&1 | grep -i superpowers
+
+# Check skills are discoverable
+opencode run "use skill tool to list all skills" 2>&1 | grep -i superpowers
 
-# Run specific test
-./tests/opencode/run-tests.sh --test test-tools.sh
+# Check bootstrap injection
+opencode run "what superpowers do you have?"
 ```
 
-Tests verify:
-- Plugin loading
-- Skills-core library functionality
-- Tool execution (use_skill, find_skills)
-- Skill priority resolution
-- Proper isolation with temp HOME
+The agent should mention having superpowers and be able to list skills from `superpowers/`.