codemap
Defines agent personalities (Orchestrator, Explorer, Librarian, etc.) and manages their configuration lifecycle. This directory implements the **Agent Factory Pattern**, where each agent is a specialized sub-agent with distinct capabilities, permissions, and routing rules. The
$ npx -y skills add alvinunreal/oh-my-opencode-slim --agent claude-codeHow it fires
How this agent gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
Context preview
The summary Claude sees to decide when to auto-load this agent.
Defines agent personalities (Orchestrator, Explorer, Librarian, etc.) and manages their configuration lifecycle. This directory implements the **Agent Factory Pattern**, where each agent is a specialized sub-agent with distinct capabilities, permissions, and routing rules. The
Agent definition
codemap.mdsrc/agents/
Responsibility
Defines agent personalities (Orchestrator, Explorer, Librarian, etc.) and manages their configuration lifecycle. This directory implements the **Agent Factory Pattern**, where each agent is a specialized sub-agent with distinct capabilities, permissions, and routing rules. The Orchestrator agent (src/agents/index.ts) coordinates task delegation to these specialists.
Design
Agent Types and Factories
Each agent is a **prompt-driven specialist** with a factory function that creates an `AgentDefinition`:
| Agent | Factory | Role | Permissions | Model Default | |-------|---------|------|-------------|---------------| | **orchestrator** | `createOrchestratorAgent()` | Workflow manager that delegates tasks to specialists | Primary agent with full tool access | Resolved from config or runtime preset | | **explorer** | `createExplorerAgent()` | Fast codebase search and pattern matching | Read-only (glob, grep, ast_grep_search) | DEFAULT_MODELS.explorer | | **librarian** | `createLibrarianAgent()` | External documentation and library research | Read-only (context7, gh_grep) | DEFAULT_MODELS.librarian | | **oracle** | `createOracleAgent()` | Strategic technical advisor and code reviewer | Read-only (read, glob, grep, ast_grep_search) | DEFAULT_MODELS.oracle | | **designer** | `createDesignerAgent()` | UI/UX design, review, and implementation | Read/write (read, glob, grep, write, edit) | DEFAULT_MODELS.designer | | **fixer** | `createFixerAgent()` | Fast implementation specialist for bounded tasks | Read/write (read, glob, grep, write, edit) | DEFAULT_MODELS.fixer | | **observer** | `createObserverAgent()` | Visual analysis specialist (images, PDFs, diagrams) | Read-only (read, glob, grep, ast_grep_search) | DEFAULT_MODELS.observer | | **council** | `createCouncilAgent()` | Multi-LLM consensus synthesis from councillor responses | Read-only | DEFAULT_MODELS.council | | **councillor** | `createCouncillorAgent()` | Read-only council advisor; registered dynamically per preset seat as `councillor-<name>` | Read-only (read, glob, grep, ast_grep_search) | Inherited from council preset |
Configuration System
- **Default prompts**: Each agent factory has a base prompt defined in its file (e.g., `explorer.ts`, `oracle.ts`)
- **User overrides**: From `~/.config/opencode/oh-my-opencode-slim.json` via `loadAgentPrompt()`
- **Permission wildcards**: Applied via `applyDefaultPermissions()` in `index.ts`
- **Model resolution**: Supports both string models and priority-ordered arrays (`_modelArray`) for runtime fallback
- **Skill permissions**: Per-agent MCP and tool access controlled via `getSkillPermissionsForAgent()`
Agent Lifecycle
1. **Agent creation**: `createAgents(config)` instantiates all agents with merged configuration 2. **Permission application**: `applyDefaultPermissions()` sets read/write permissions based on agent type 3. **Display name injection**: Orchestrator prompt rewrites `@agent` mentions to user-configured display names 4. **Configuration export**: `getAgentConfigs()` converts `AgentDefinition` to OpenCode SDK format with classification metadata
Flow
Agent Instantiation Sequence (src/agents/index.ts)
// 1. Gather sub-agent definitions with custom prompts
const protoSubAgents = Object.entries(SUBAGENT_FACTORIES)
.filter(([name]) => !disabled.has(name))
.map(([name, factory]) => {
const customPrompts = loadAgentPrompt(name, config?.preset);
return factory(getModelForAgent(name), customPrompts.prompt, customPrompts.appendPrompt);
});
// 2. Apply overrides and default permissions
const builtInSubAgents = protoSubAgents.map((agent) => {
const override = getAgentOverride(config, agent.name);
if (override) applyOverrides(agent, override);
applyDefaultPermissions(agent, override?.skills, config?.disabled_skills);
return agent;
});
// 3. Create Orchestrator (with its own overrides and custom prompts)
const orchestrator = createOrchestratorAgent(
orchestratorModel,
orchestratorPrompts.prompt,
orchestratorPrompts.appendPrompt,
disabled,
);
applyDefaultPermissions(orchestrator, orchestratorOverride?.skills, config?.disabled_skills);
// 4. Collect display names and inject into orchestrator prompt
const displayNameMap = new Map<string, string>();
// ... populate from orchestrator and all subagents ...
injectDisplayNames(orchestrator, displayNameMap);
// 5. Inject council-dispatch instructions when dynamic councillors exist
// 6. Return agents array [orchestrator, ...allSubAgents]
return [orchestrator, ...allSubAgents];Agent Configuration Export
export function getAgentConfigs(config?: PluginConfig): Record<string, SDKAgentConfig> {
const agents = createAgents(config);
const applyClassification = (name: string, sdkConfig: SDKAgentConfig) => {
if (name === 'council') {
sdkConfig.mode = 'all'; // Primary + subagent
} else if (name === 'councillor') {
sdkConfig.mode = 'subagent';
sdkConfig.hidden = true; // Internal only
} else if (isSubagent(name)) {
sdkConfig.mode = 'subagent';
} else if (name === 'orchestrator') {
sdkConfig.mode = 'primary';
}
};
// Build SDK config with classification and MCP permissions
const entries: Array<[string, SDKAgentConfig]> = [];
for (const a of agents) {
const sdkConfig = { ...a.config, description: a.description };
applyClassification(a.name, sdkConfig);
// Handle display names: create both displayName and hidden alias
if (a.displayName) {
entries.push([normalizeAgentName(a.displayName), sdkConfig]);
entries.push([a.name, { ...sdkConfig, hidden: true }]);
} else {
entries.push([a.name, sdkConfig]);
}
}
return Object.fromEntries(entries);
}Model Resolution and Fallback
- **Priority arrays**: When `model` is configured as an array in user config, it's stored as `_modelArray`
- **Runtime fallback**: ForegroundF
Read more
src/agents/
Responsibility
Defines agent personalities (Orchestrator, Explorer, Librarian, etc.) and manages their configuration lifecycle. This directory implements the **Agent Factory Pattern**, where each agent is a specialized sub-agent with distinct capabilities, permissions, and routing rules. The Orchestrator agent (src/agents/index.ts) coordinates task delegation to these specialists.
Design
Agent Types and Factories
Each agent is a **prompt-driven specialist** with a factory function that creates an `AgentDefinition`:
| Agent | Factory | Role | Permissions | Model Default | |-------|---------|------|-------------|---------------| | **orchestrator** | `createOrchestratorAgent()` | Workflow manager that delegates tasks to specialists | Primary agent with full tool access | Resolved from config or runtime preset | | **explorer** | `createExplorerAgent()` | Fast codebase search and pattern matching | Read-only (glob, grep, ast_grep_search) | DEFAULT_MODELS.explorer | | **librarian** | `createLibrarianAgent()` | External documentation and library research | Read-only (context7, gh_grep) | DEFAULT_MODELS.librarian | | **oracle** | `createOracleAgent()` | Strategic technical advisor and code reviewer | Read-only (read, glob, grep, ast_grep_search) | DEFAULT_MODELS.oracle | | **designer** | `createDesignerAgent()` | UI/UX design, review, and implementation | Read/write (read, glob, grep, write, edit) | DEFAULT_MODELS.designer | | **fixer** | `createFixerAgent()` | Fast implementation specialist for bounded tasks | Read/write (read, glob, grep, write, edit) | DEFAULT_MODELS.fixer | | **observer** | `createObserverAgent()` | Visual analysis specialist (images, PDFs, diagrams) | Read-only (read, glob, grep, ast_grep_search) | DEFAULT_MODELS.observer | | **council** | `createCouncilAgent()` | Multi-LLM consensus synthesis from councillor responses | Read-only | DEFAULT_MODELS.council | | **councillor** | `createCouncillorAgent()` | Read-only council advisor; registered dynamically per preset seat as `councillor-<name>` | Read-only (read, glob, grep, ast_grep_search) | Inherited from council preset |
Configuration System
- **Default prompts**: Each agent factory has a base prompt defined in its file (e.g., `explorer.ts`, `oracle.ts`)
- **User overrides**: From `~/.config/opencode/oh-my-opencode-slim.json` via `loadAgentPrompt()`
- **Permission wildcards**: Applied via `applyDefaultPermissions()` in `index.ts`
- **Model resolution**: Supports both string models and priority-ordered arrays (`_modelArray`) for runtime fallback
- **Skill permissions**: Per-agent MCP and tool access controlled via `getSkillPermissionsForAgent()`
Agent Lifecycle
1. **Agent creation**: `createAgents(config)` instantiates all agents with merged configuration 2. **Permission application**: `applyDefaultPermissions()` sets read/write permissions based on agent type 3. **Display name injection**: Orchestrator prompt rewrites `@agent` mentions to user-configured display names 4. **Configuration export**: `getAgentConfigs()` converts `AgentDefinition` to OpenCode SDK format with classification metadata
Flow
Agent Instantiation Sequence (src/agents/index.ts)
// 1. Gather sub-agent definitions with custom prompts
const protoSubAgents = Object.entries(SUBAGENT_FACTORIES)
.filter(([name]) => !disabled.has(name))
.map(([name, factory]) => {
const customPrompts = loadAgentPrompt(name, config?.preset);
return factory(getModelForAgent(name), customPrompts.prompt, customPrompts.appendPrompt);
});
// 2. Apply overrides and default permissions
const builtInSubAgents = protoSubAgents.map((agent) => {
const override = getAgentOverride(config, agent.name);
if (override) applyOverrides(agent, override);
applyDefaultPermissions(agent, override?.skills, config?.disabled_skills);
return agent;
});
// 3. Create Orchestrator (with its own overrides and custom prompts)
const orchestrator = createOrchestratorAgent(
orchestratorModel,
orchestratorPrompts.prompt,
orchestratorPrompts.appendPrompt,
disabled,
);
applyDefaultPermissions(orchestrator, orchestratorOverride?.skills, config?.disabled_skills);
// 4. Collect display names and inject into orchestrator prompt
const displayNameMap = new Map<string, string>();
// ... populate from orchestrator and all subagents ...
injectDisplayNames(orchestrator, displayNameMap);
// 5. Inject council-dispatch instructions when dynamic councillors exist
// 6. Return agents array [orchestrator, ...allSubAgents]
return [orchestrator, ...allSubAgents];Agent Configuration Export
export function getAgentConfigs(config?: PluginConfig): Record<string, SDKAgentConfig> {
const agents = createAgents(config);
const applyClassification = (name: string, sdkConfig: SDKAgentConfig) => {
if (name === 'council') {
sdkConfig.mode = 'all'; // Primary + subagent
} else if (name === 'councillor') {
sdkConfig.mode = 'subagent';
sdkConfig.hidden = true; // Internal only
} else if (isSubagent(name)) {
sdkConfig.mode = 'subagent';
} else if (name === 'orchestrator') {
sdkConfig.mode = 'primary';
}
};
// Build SDK config with classification and MCP permissions
const entries: Array<[string, SDKAgentConfig]> = [];
for (const a of agents) {
const sdkConfig = { ...a.config, description: a.description };
applyClassification(a.name, sdkConfig);
// Handle display names: create both displayName and hidden alias
if (a.displayName) {
entries.push([normalizeAgentName(a.displayName), sdkConfig]);
entries.push([a.name, { ...sdkConfig, hidden: true }]);
} else {
entries.push([a.name, sdkConfig]);
}
}
return Object.fromEntries(entries);
}Model Resolution and Fallback
- **Priority arrays**: When `model` is configured as an array in user config, it's stored as `_modelArray`
- **Runtime fallback**: ForegroundF
Lean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks
Repo: alvinunreal/oh-my-opencode-slim

