Remove all local directory loaders from Matrixx. Built-in skills/commands/agents/MCPs will be registered directly via OpenCode's config hook. This eliminates ~7,169 LOC across 42 files and removes Claude Code compatibility layers.
What we're removing:
src/features/opencode-skill-loader/(17 files, ~2850 LOC) — loads skills from.opencode/skills/,.claude/skills/,.agents/skills/, and config sourcessrc/features/command-loader/(3 files, ~300 LOC) — loads commands from.opencode/command/src/features/agent-loader/(3 files, ~200 LOC) — loads agents from.opencode/agents/src/features/mcp-oauth/(7 files, ~2050 LOC) — OAuth 2.0 for MCP serverssrc/features/skill-mcp-manager/(12 files, ~1769 LOC) — MCP client lifecycle per session
What we're keeping:
src/features/builtin-skills/— 45 built-in skills (code, not loaded from disk)src/features/builtin-commands/— built-in commands (code, not loaded from disk)src/agents/— 14 built-in agents (code, not loaded from disk)src/mcp/— 4 built-in MCPs (code, not loaded from disk)
createSkillContext() [src/plugin/skill-context.ts]
├─ discoverConfigSourceSkills() ← matrixx.jsonc skills.sources paths
├─ discoverOpencodeGlobalSkills() ← ~/.config/opencode/skills/
├─ discoverOpencodeProjectSkills() ← .opencode/skills/
├─ discoverProjectAgentsSkills() ← .agents/skills/ (project)
├─ discoverGlobalAgentsSkills() ← ~/.agents/skills/ (global)
├─ createBuiltinSkills() ← 45 built-in skills (KEEP)
└─ mergeSkills() ← priority-based merging
↓
mergedSkills: LoadedSkill[]
↓
├─ createToolRegistry() ← skill tool, slashcommand tool
├─ command-config-handler.ts ← registered as commands
├─ agent-config-handler.ts ← agent configs with skill awareness
└─ auto-slash-command hook ← auto-detection
applyCommandConfig() [src/plugin-handlers/command-config-handler.ts]
├─ loadBuiltinCommands() ← Matrixx built-in commands (KEEP)
├─ loadOpencodeGlobalCommands() ← ~/.config/opencode/command/
├─ loadOpencodeProjectCommands() ← .opencode/command/
├─ skillsToCommandDefinitionRecord() ← skills converted to commands
└─ pluginComponents.commands/skills ← (currently empty)
↓
params.config.command = { ...merged }
applyAgentConfig() [src/plugin-handlers/agent-config-handler.ts]
├─ createBuiltinAgents() ← 14 built-in agents (KEEP)
├─ createMouseAgentWithOverrides() ← Mouse agent (KEEP)
├─ loadUserAgents() ← ~/.config/opencode/agents/
├─ loadProjectAgents() ← .opencode/agents/
└─ pluginComponents.agents ← (currently empty)
↓
params.config.agent = { ...merged }
applyMcpConfig() [src/plugin-handlers/mcp-config-handler.ts]
├─ createBuiltinMcps() ← 4 built-in MCPs (KEEP)
├─ userMcp ← user config
└─ pluginComponents.mcpServers ← (currently empty)
↓
params.config.mcp = { ...merged }
SkillMcpManager [src/features/skill-mcp-manager/]
└─ Manages MCP lifecycle for skills with embedded MCPs
createSkillContext() [src/plugin/skill-context.ts]
├─ createBuiltinSkills() ← 45 built-in skills
└─ filterDisabledSkills() ← remove disabled_skills
↓
builtinSkills: BuiltinSkill[]
↓
├─ createToolRegistry() ← skill tool, slashcommand tool
├─ command-config-handler.ts ← registered as commands
├─ agent-config-handler.ts ← agent configs with skill awareness
└─ auto-slash-command hook ← auto-detection
applyCommandConfig() [src/plugin-handlers/command-config-handler.ts]
├─ loadBuiltinCommands() ← Matrixx built-in commands
└─ builtinSkillsToCommands() ← built-in skills as commands
↓
params.config.command = { ...merged }
applyAgentConfig() [src/plugin-handlers/agent-config-handler.ts]
├─ createBuiltinAgents() ← 14 built-in agents
└─ createMouseAgentWithOverrides() ← Mouse agent
↓
params.config.agent = { ...merged }
applyMcpConfig() [src/plugin-handlers/mcp-config-handler.ts]
├─ createBuiltinMcps() ← 4 built-in MCPs
└─ userMcp ← user config
↓
params.config.mcp = { ...merged }
[SkillMcpManager removed — OpenCode handles MCP lifecycle]
- Remove all discovery functions from
opencode-skill-loader createSkillContext()should only usecreateBuiltinSkills()- Remove
mergeSkills()— no longer needed
-
Refactor
src/plugin/skill-context.ts- Remove imports:
discoverConfigSourceSkills,discoverGlobalAgentsSkills,discoverOpencodeGlobalSkills,discoverOpencodeProjectSkills,discoverProjectAgentsSkills,mergeSkills - Remove
SkillScopetype (no longer needed) - Simplify
createSkillContext():export async function createSkillContext(args: { directory: string pluginConfig: MatrixxConfig }): Promise<SkillContext> { const { pluginConfig } = args const browserProvider = pluginConfig.browser_automation_engine?.provider ?? "playwright" const disabledSkills = new Set<string>(pluginConfig.disabled_skills ?? []) if (!pluginConfig.tdd_enforcer?.enabled) { disabledSkills.add("tdd-enforcer") } const builtinSkills = createBuiltinSkills({ browserProvider, disabledSkills, }) const availableSkills: AvailableSkill[] = builtinSkills.map((skill) => ({ name: skill.name, description: skill.description, location: "plugin", })) return { builtinSkills, availableSkills, browserProvider, disabledSkills, } }
- Update
SkillContexttype:export type SkillContext = { builtinSkills: BuiltinSkill[] // was: mergedSkills: LoadedSkill[] availableSkills: AvailableSkill[] browserProvider: BrowserAutomationProvider disabledSkills: Set<string> }
- Remove imports:
-
Update
src/create-tools.ts- Change
mergedSkills: LoadedSkill[]tobuiltinSkills: BuiltinSkill[] - Update return type
- Change
-
Update
src/create-hooks.ts- Change
mergedSkills: LoadedSkill[]tobuiltinSkills: BuiltinSkill[]
- Change
-
Update
src/plugin/hooks/create-skill-hooks.ts- Change
LoadedSkilltoBuiltinSkill
- Change
src/plugin/skill-context.tssimplified to ~40 LOC- All references to
LoadedSkillreplaced withBuiltinSkill - No more skill discovery from disk
- Verify
createSkillContext()returns only built-in skills - Verify
disabled_skillsconfig still works - Verify
browserProviderselection still works
- Medium: Many files import
LoadedSkill— need to update all of them - Mitigation: Use grep to find all imports, update systematically
- Remove
loadOpencodeGlobalCommands(),loadOpencodeProjectCommands() applyCommandConfig()should only useloadBuiltinCommands()- Remove skill-to-command conversion (skills are registered separately)
-
Refactor
src/plugin-handlers/command-config-handler.ts- Remove imports:
loadOpencodeGlobalCommands,loadOpencodeProjectCommands,discoverConfigSourceSkills,loadOpencodeGlobalSkills,loadOpencodeProjectSkills,skillsToCommandDefinitionRecord - Simplify
applyCommandConfig():export async function applyCommandConfig(params: { config: Record<string, unknown>; pluginConfig: MatrixxConfig; ctx: { directory: string }; pluginComponents: PluginComponents; }): Promise<void> { const builtinCommands = loadBuiltinCommands(params.pluginConfig.disabled_commands); const systemCommands = (params.config.command as Record<string, unknown>) ?? {}; params.config.command = { ...builtinCommands, ...systemCommands, ...params.pluginComponents.commands, ...params.pluginComponents.skills, }; }
- Remove imports:
-
Update
src/features/builtin-commands/- Remove import of
CommandDefinitionfromcommand-loader - Define
CommandDefinitionlocally or in a shared types file
- Remove import of
command-config-handler.tssimplified to ~20 LOC- No more command discovery from disk
command-loader/can be deleted
- Verify all built-in commands still register
- Verify slash commands still work
- Verify
disabled_commandsconfig still works
- Low: Command loading is straightforward
- Mitigation: Built-in commands are already well-tested
- Remove
loadUserAgents(),loadProjectAgents() applyAgentConfig()should only usecreateBuiltinAgents()
-
Refactor
src/plugin-handlers/agent-config-handler.ts- Remove imports:
loadProjectAgents,loadUserAgents,discoverConfigSourceSkills,discoverOpencodeGlobalSkills,discoverOpencodeProjectSkills - Remove skill discovery logic (lines 47-70)
- Simplify agent loading:
const builtinAgents = await createBuiltinAgents( migratedDisabledAgents, params.pluginConfig.agents, params.ctx.directory, undefined, params.pluginConfig.categories, [], // allDiscoveredSkills — now empty params.ctx.client, browserProvider, currentModel, disabledSkills, useTaskSystem, params.pluginConfig.global_model, availableToolNames, ); const rawPluginAgents = params.pluginComponents.agents; const pluginAgents = Object.fromEntries( Object.entries(rawPluginAgents).map(([key, value]) => [ key, value ? migrateAgentConfig(value as Record<string, unknown>) : value, ]), ); // ... rest of the logic stays the same
- Remove
loadUserAgents()andloadProjectAgents()calls
- Remove imports:
-
Update
src/agents/builtin-agents.ts- Remove
LoadedSkillimport - Update
createBuiltinAgents()signature to not require skills array
- Remove
-
Update
src/agents/agent-builder.ts- Remove
resolveMultipleSkillsimport - Simplify agent building to not resolve skills
- Remove
-
Update
src/agents/builtin-agents/available-skills.ts- Remove
LoadedSkill,SkillScopeimports - Simplify to use
BuiltinSkillonly
- Remove
agent-config-handler.tssimplified- No more agent discovery from disk
agent-loader/can be deleted
- Verify all 14 agents still register
- Verify agent overrides still work
- Verify
disabled_agentsconfig still works
- Medium: Agent building is complex — need to carefully remove skill resolution
- Mitigation: Keep the core agent building logic, only remove disk loading
- Remove
SkillMcpManagerfromcreateManagers() - Remove
mcp-oauth/andskill-mcp-manager/ applyMcpConfig()should only usecreateBuiltinMcps()
-
Refactor
src/create-managers.ts- Remove
SkillMcpManagerimport - Remove
skillMcpManagerfromManagerstype - Remove
new SkillMcpManager()instantiation - Update return type
- Remove
-
Refactor
src/plugin-handlers/mcp-config-handler.ts- Already simple — no changes needed
- Just verify it doesn't reference
SkillMcpManager
-
Update
src/create-tools.ts- Remove
skillMcpManagerfrommanagersparameter - Update
createToolRegistry()call
- Remove
-
Update
src/tools/skill/tools.ts- Remove
SkillMcpManager,SkillMcpClientInfo,SkillMcpServerContextimports - Remove MCP-related logic from skill tool
- Remove
-
Update
src/tools/skill-mcp/tools.ts- Delete entire file — skill-mcp tool no longer needed
-
Update
src/tools/skill/types.ts- Remove
SkillMcpManagerimport - Remove
mcpConfigfrom skill types
- Remove
SkillMcpManagerremoved from codebasemcp-oauth/andskill-mcp-manager/can be deleted- MCP lifecycle delegated to OpenCode
- Verify all 4 built-in MCPs still start
- Verify MCP tools still work
- Verify
disabled_mcpsconfig still works
- High: MCP lifecycle is complex — need to ensure OpenCode handles it correctly
- Mitigation: Test thoroughly with MCP-dependent skills (playwright, websearch)
- Delete all 5 loader modules
-
Delete directories:
rm -rf src/features/opencode-skill-loader/ rm -rf src/features/command-loader/ rm -rf src/features/agent-loader/ rm -rf src/features/mcp-oauth/ rm -rf src/features/skill-mcp-manager/
-
Update
src/features/index.ts(if it exists)- Remove exports of deleted modules
-
Update
src/features/AGENTS.md- Remove documentation for deleted modules
- 5 directories deleted (~7,169 LOC removed)
- Clean feature set
- Run
bun run typecheck— should pass - Run
bun run lint— should pass - Run
bun test— should pass
- Low: All dependencies should be resolved in previous phases
- Mitigation: If typecheck fails, fix remaining imports
- Remove
skills.sourcesfrom config schema (no longer needed) - Remove
skills.enable/skills.disable(usedisabled_skillsinstead)
-
Update
src/config/schema/skills.ts- Remove
sourcesfield - Remove
enable/disablefields - Keep only
disabled_skillsat root level
- Remove
-
Regenerate schema:
bun run build:schema
-
Update
dist/matrixx.schema.json- Should be auto-generated
- Config schema simplified
- No more
skills.sourcesconfiguration
- Verify config validation still works
- Verify
disabled_skillsstill works
- Low: Config schema changes are straightforward
- Mitigation: Keep backward compatibility for one release cycle
- Update all imports that reference deleted modules
- Remove
SkillMcpManagerfromManagerstype - Remove
mergedSkillsfromSkillContext
-
Find all imports:
grep -r "from.*opencode-skill-loader" src/ --include="*.ts" grep -r "from.*command-loader" src/ --include="*.ts" grep -r "from.*agent-loader" src/ --include="*.ts" grep -r "from.*mcp-oauth" src/ --include="*.ts" grep -r "from.*skill-mcp-manager" src/ --include="*.ts"
-
Update each file:
- Replace
LoadedSkillwithBuiltinSkill - Remove discovery function calls
- Remove MCP-related logic
- Replace
-
Key files to update:
src/tools/slashcommand/command-discovery.tssrc/tools/slashcommand/types.tssrc/tools/slashcommand/slashcommand-tool.tssrc/tools/slashcommand/skill-command-converter.tssrc/tools/skill/types.tssrc/tools/skill/tools.tssrc/tools/skill-mcp/tools.ts(delete)src/tools/delegate-task/skill-resolver.tssrc/hooks/auto-slash-command/executor.tssrc/hooks/auto-slash-command/hook.tssrc/agents/builtin-agents.tssrc/agents/agent-builder.tssrc/agents/builtin-agents/available-skills.tssrc/plugin/skill-context.tssrc/plugin/hooks/create-skill-hooks.tssrc/create-tools.tssrc/create-hooks.tssrc/create-managers.tssrc/plugin-handlers/command-config-handler.tssrc/plugin-handlers/agent-config-handler.tssrc/features/builtin-skills/types.tssrc/features/builtin-commands/types.tssrc/features/builtin-commands/commands.ts
- All imports updated
- No references to deleted modules
- Run
bun run typecheck— should pass - Run
bun run lint— should pass
- Medium: Many files to update
- Mitigation: Use grep to find all imports, update systematically
- Verify all functionality still works
- Ensure no regressions
-
Type checking:
bun run typecheck
-
Linting:
bun run lint
-
Unit tests:
bun test -
Integration tests:
- Start OpenCode with Matrixx plugin
- Verify all 45 built-in skills load
- Verify all built-in commands work
- Verify all 14 agents register
- Verify all 4 built-in MCPs start
- Test skill invocation via slash commands
- Test agent delegation
- Test MCP tools (websearch, context7, etc.)
-
Manual testing:
- Create a new session
- Invoke a built-in skill (e.g.,
/git-master) - Delegate to an agent (e.g.,
@oracle) - Use an MCP tool (e.g., websearch)
- Verify no errors in logs
- All tests pass
- No regressions
- High: Complex system with many moving parts
- Mitigation: Test each component individually, then integration
- Update AGENTS.md files
- Update README.md
- Remove obsolete code comments
-
Update
src/features/AGENTS.md- Remove documentation for deleted modules
- Update structure diagram
-
Update
src/AGENTS.md- Update plugin initialization steps
- Remove references to deleted loaders
-
Update
README.md- Remove mentions of local directory loading
- Update configuration examples
-
Remove obsolete comments:
- Search for "claude code", "local directory", "skill discovery"
- Remove or update comments
-
Update
docs/configurations.md- Remove
skills.sourcesdocumentation - Update skill configuration examples
- Remove
- Documentation updated
- No obsolete references
- Review documentation for accuracy
- Verify examples still work
- Low: Documentation updates are straightforward
- Mitigation: Review carefully for accuracy
-
MCP Lifecycle (Phase 4)
- Risk: OpenCode may not handle MCP lifecycle the same way as
SkillMcpManager - Mitigation: Test thoroughly with MCP-dependent skills
- Fallback: Keep
SkillMcpManagerif OpenCode's handling is insufficient
- Risk: OpenCode may not handle MCP lifecycle the same way as
-
Skill Resolution (Phase 3)
- Risk: Agent building may break without skill resolution
- Mitigation: Keep core agent building logic, only remove disk loading
- Fallback: Simplify skill resolution instead of removing it
-
Import Updates (Phase 7)
- Risk: Many files to update, easy to miss some
- Mitigation: Use grep to find all imports, update systematically
- Fallback: Fix typecheck errors iteratively
-
Config Schema Changes (Phase 6)
- Risk: Breaking change for users with
skills.sourcesconfig - Mitigation: Keep backward compatibility for one release cycle
- Fallback: Deprecate instead of remove
- Risk: Breaking change for users with
-
Command Registration (Phase 2)
- Risk: Slash commands may break
- Mitigation: Test all slash commands thoroughly
- Fallback: Keep skill-to-command conversion
-
Agent Loading (Phase 3)
- Risk: Minimal — agent loading is straightforward
- Mitigation: Built-in agents are well-tested
-
Documentation (Phase 9)
- Risk: Minimal — documentation updates are straightforward
- Mitigation: Review carefully for accuracy
If migration fails at any phase:
-
Revert the phase:
git revert HEAD
-
Restore deleted modules:
git checkout HEAD~1 -- src/features/opencode-skill-loader/ git checkout HEAD~1 -- src/features/command-loader/ git checkout HEAD~1 -- src/features/agent-loader/ git checkout HEAD~1 -- src/features/mcp-oauth/ git checkout HEAD~1 -- src/features/skill-mcp-manager/
-
Revert import updates:
git checkout HEAD~1 -- src/
-
Verify:
bun run typecheck bun run lint bun test
Migration is complete when:
- All 5 loader modules deleted
- ~7,169 LOC removed
- All 45 built-in skills load correctly
- All built-in commands work
- All 14 agents register
- All 4 built-in MCPs start
-
bun run typecheckpasses -
bun run lintpasses -
bun testpasses - Integration tests pass
- Documentation updated
- No obsolete references remain
| Phase | Complexity | Time Estimate |
|---|---|---|
| Phase 1: Simplify Skill Context | Medium | 2-3 hours |
| Phase 2: Simplify Command Config | Low | 1 hour |
| Phase 3: Simplify Agent Config | Medium | 2-3 hours |
| Phase 4: Simplify MCP Config | High | 3-4 hours |
| Phase 5: Delete Loader Modules | Low | 30 minutes |
| Phase 6: Update Config Schema | Low | 1 hour |
| Phase 7: Update Dependencies | Medium | 3-4 hours |
| Phase 8: Testing & Validation | High | 4-5 hours |
| Phase 9: Documentation & Cleanup | Low | 1-2 hours |
| Total | 18-24 hours |
Phase 1 (Skill Context)
↓
Phase 2 (Command Config) ──┐
↓ │
Phase 3 (Agent Config) ────┤
↓ │
Phase 4 (MCP Config) ──────┤
↓ │
Phase 5 (Delete Modules) ←─┘
↓
Phase 6 (Config Schema)
↓
Phase 7 (Update Dependencies)
↓
Phase 8 (Testing)
↓
Phase 9 (Documentation)
Critical path: Phase 1 → Phase 7 → Phase 8
Parallelizable: Phases 2, 3, 4 can be done in parallel after Phase 1
src/features/opencode-skill-loader/ (17 files)
src/features/command-loader/ (3 files)
src/features/agent-loader/ (3 files)
src/features/mcp-oauth/ (7 files)
src/features/skill-mcp-manager/ (12 files)
src/plugin/skill-context.ts
src/create-tools.ts
src/create-hooks.ts
src/create-managers.ts
src/plugin/hooks/create-skill-hooks.ts
src/plugin-handlers/command-config-handler.ts
src/plugin-handlers/agent-config-handler.ts
src/tools/slashcommand/command-discovery.ts
src/tools/slashcommand/types.ts
src/tools/slashcommand/slashcommand-tool.ts
src/tools/slashcommand/skill-command-converter.ts
src/tools/skill/types.ts
src/tools/skill/tools.ts
src/tools/skill-mcp/tools.ts (delete)
src/tools/delegate-task/skill-resolver.ts
src/hooks/auto-slash-command/executor.ts
src/hooks/auto-slash-command/hook.ts
src/agents/builtin-agents.ts
src/agents/agent-builder.ts
src/agents/builtin-agents/available-skills.ts
src/features/builtin-skills/types.ts
src/features/builtin-commands/types.ts
src/features/builtin-commands/commands.ts
src/config/schema/skills.ts
No new files needed — we're simplifying, not adding.
// Skill loading
import { discoverOpencodeProjectSkills, mergeSkills } from "./features/opencode-skill-loader"
const skills = await discoverOpencodeProjectSkills(directory)
const merged = mergeSkills(builtinSkills, skills, ...)
// Command loading
import { loadOpencodeProjectCommands } from "./features/command-loader"
const commands = await loadOpencodeProjectCommands(directory)
// Agent loading
import { loadProjectAgents } from "./features/agent-loader"
const agents = loadProjectAgents(directory)
// MCP management
import { SkillMcpManager } from "./features/skill-mcp-manager"
const manager = new SkillMcpManager()// Skill loading
import { createBuiltinSkills } from "./features/builtin-skills"
const skills = createBuiltinSkills({ browserProvider, disabledSkills })
// Command loading
import { loadBuiltinCommands } from "./features/builtin-commands"
const commands = loadBuiltinCommands(disabledCommands)
// Agent loading
import { createBuiltinAgents } from "./agents"
const agents = await createBuiltinAgents(...)
// MCP management
import { createBuiltinMcps } from "./mcp"
const mcps = createBuiltinMcps(disabledMcps, config)
// OpenCode handles MCP lifecycleOpenCode's plugin loader (packages/opencode/src/plugin/index.ts) only calls readV1Plugin(). There is no readV2Plugin() function. The v2 API exists in the @opencode-ai/plugin package but OpenCode's loader doesn't recognize or load v2 plugins. v2 is pre-release infrastructure — it's built but not wired up.
Matrixx's loaders provide functionality OpenCode doesn't have natively:
- Local file discovery (
.opencode/skills/,.opencode/command/) - YAML frontmatter parsing
- Multi-scope priority merging
- Claude Code compatibility (
.claude/paths)
However, the user has decided this functionality is not needed. Users should use OpenCode's native mechanisms (if/when they're added) or rely on Matrixx's built-in skills/commands.
This is a breaking change. Users with custom skills/commands/agents in .opencode/ directories will lose that functionality. They should:
- Use OpenCode's native mechanisms (if available)
- Request features from Matrixx to be added as built-in skills/commands
- Fork Matrixx and add custom loaders
If OpenCode adds native support for local directory loading in the future, Matrixx can re-add loaders that delegate to OpenCode's APIs. For now, we're simplifying to reduce maintenance burden.