Summary
Custom agents defined in .opencode/agents/ (or .claude/agents/) are correctly loaded and registered in OpenCode — they can be invoked via @agent_name. However, they are completely invisible to orchestrator agents (Sisyphus, Hephaestus, Atlas) because they are never injected into the availableAgents list that builds the orchestrator's system prompt.
This means orchestrators will never autonomously delegate to user-defined custom agents, defeating the purpose of the multi-agent orchestration system.
Steps to Reproduce
-
Create a custom agent in .opencode/agents/researcher.md:
---
description: Research agent for deep analysis
mode: subagent
---
You are a research agent...
-
Start OpenCode with oh-my-opencode plugin
-
Verify @researcher works (it does — agent is registered)
-
Ask Sisyphus a question that would benefit from delegating to researcher
-
Observe: Sisyphus never mentions or delegates to researcher — it doesn't know it exists
Root Cause Analysis
Layer 1: Custom agents ARE loaded and registered ✅
config-handler.ts (lines 392-403) correctly merges custom agents into config.agent:
config.agent = {
...agentConfig, // plugin built-in (sisyphus, etc.)
...builtinAgents, // other built-in agents
...userAgents, // ~/.claude/agents/ ✅ loaded
...projectAgents, // .claude/agents/ ✅ loaded
...pluginAgents, // Claude Code plugins
...filteredConfigAgents, // OpenCode native agents (includes .opencode/agents/) ✅ loaded
};
Layer 2: Custom agents are NOT in availableAgents ❌
src/agents/utils.ts (lines 252-345) builds availableAgents exclusively from agentSources — a hardcoded map of built-in agents:
const availableAgents: AvailableAgent[] = [] // starts empty
for (const [name, source] of Object.entries(agentSources)) { // only built-in agents
// ...
const metadata = agentMetadata[agentName]
if (metadata) {
availableAgents.push({...}) // only agents with metadata
}
}
agentSources (lines 23-35) is hardcoded:
const agentSources: Record<BuiltinAgentName, AgentSource> = {
sisyphus, hephaestus, oracle, librarian, explore,
"multimodal-looker", metis, momus, atlas
}
Layer 3: availableAgents is the SOLE source for orchestrator prompts ❌
availableAgents is passed to createSisyphusAgent() (line 373-379), createHephaestusAgent() (line 418-424), and createAtlasAgent() (line 467-472). These use dynamic-agent-prompt-builder.ts to render Delegation Table, Key Triggers, and Agent Selection sections.
Result: Custom agents exist in the system but orchestrators are blind to them.
Impact
| Capability |
Status |
@custom_agent manual invocation |
✅ Works |
| Custom agent appears in system prompt |
❌ Missing |
| Sisyphus auto-delegates to custom agent |
❌ Impossible |
| Atlas orchestrates with custom agent |
❌ Impossible |
| Hephaestus delegates to custom agent |
❌ Impossible |
Proposed Fix
Collect custom agents (from userAgents, projectAgents, pluginAgents, and filteredConfigAgents) and append them to availableAgents before passing to orchestrator agent factories.
Rough approach:
// In createBuiltinAgents() or in config-handler.ts after agent merging
// Collect custom agents as AvailableAgent entries
const customAgentEntries: AvailableAgent[] = [
...Object.entries(userAgents),
...Object.entries(projectAgents),
...Object.entries(pluginAgents),
].map(([name, config]) => ({
name,
description: config.description ?? "",
metadata: {
category: "custom",
cost: "unknown",
triggers: [],
},
}));
// Merge into availableAgents before creating orchestrator agents
const allAvailableAgents = [...availableAgents, ...customAgentEntries];
The dynamic-agent-prompt-builder.ts would need a section to render custom agents separately (e.g., "User-Defined Agents" table) so orchestrators know they exist and when to use them.
Environment
- oh-my-opencode version: latest (dev branch)
- OpenCode: >= 1.0.150
- Relevant files:
src/agents/utils.ts (lines 228-485) — createBuiltinAgents()
src/agents/dynamic-agent-prompt-builder.ts — prompt rendering
src/plugin-handlers/config-handler.ts (lines 392-403) — agent merging
src/features/claude-code-agent-loader/loader.ts — .claude/agents/ loader
Summary
Custom agents defined in
.opencode/agents/(or.claude/agents/) are correctly loaded and registered in OpenCode — they can be invoked via@agent_name. However, they are completely invisible to orchestrator agents (Sisyphus, Hephaestus, Atlas) because they are never injected into theavailableAgentslist that builds the orchestrator's system prompt.This means orchestrators will never autonomously delegate to user-defined custom agents, defeating the purpose of the multi-agent orchestration system.
Steps to Reproduce
Create a custom agent in
.opencode/agents/researcher.md:Start OpenCode with oh-my-opencode plugin
Verify
@researcherworks (it does — agent is registered)Ask Sisyphus a question that would benefit from delegating to
researcherObserve: Sisyphus never mentions or delegates to
researcher— it doesn't know it existsRoot Cause Analysis
Layer 1: Custom agents ARE loaded and registered ✅
config-handler.ts(lines 392-403) correctly merges custom agents intoconfig.agent:Layer 2: Custom agents are NOT in
availableAgents❌src/agents/utils.ts(lines 252-345) buildsavailableAgentsexclusively fromagentSources— a hardcoded map of built-in agents:agentSources(lines 23-35) is hardcoded:Layer 3:
availableAgentsis the SOLE source for orchestrator prompts ❌availableAgentsis passed tocreateSisyphusAgent()(line 373-379),createHephaestusAgent()(line 418-424), andcreateAtlasAgent()(line 467-472). These usedynamic-agent-prompt-builder.tsto render Delegation Table, Key Triggers, and Agent Selection sections.Result: Custom agents exist in the system but orchestrators are blind to them.
Impact
@custom_agentmanual invocationProposed Fix
Collect custom agents (from
userAgents,projectAgents,pluginAgents, andfilteredConfigAgents) and append them toavailableAgentsbefore passing to orchestrator agent factories.Rough approach:
The
dynamic-agent-prompt-builder.tswould need a section to render custom agents separately (e.g., "User-Defined Agents" table) so orchestrators know they exist and when to use them.Environment
src/agents/utils.ts(lines 228-485) —createBuiltinAgents()src/agents/dynamic-agent-prompt-builder.ts— prompt renderingsrc/plugin-handlers/config-handler.ts(lines 392-403) — agent mergingsrc/features/claude-code-agent-loader/loader.ts—.claude/agents/loader