The src/config/ module is responsible for:
- Schema Definition: Type-safe configuration validation using Zod schemas
- Configuration Loading: Loading, validating, and merging plugin configuration from multiple sources (user config, project config, environment variables)
- Constants Management: Centralizing agent names, default models, delegation rules, polling intervals, and timeouts
Multi-Source Configuration Merging
- User config:
~/.config/opencode/oh-my-opencode-slim.jsonc(preferred) or.json - Project config:
<directory>/.opencode/oh-my-opencode-slim.jsonc(preferred) or.json - Environment override:
OH_MY_OPENCODE_SLIM_PRESET - Project config takes precedence over user config
- Nested objects (
agents,tmux,fallback) are deep-merged; arrays and primitives are replaced
Preset System
- Named presets contain agent configuration templates
- Presets are merged with root-level agent config (root overrides)
- Supports preset selection via config file or environment variable
Subagent Delegation Rules
- Explicitly defines which agents can spawn which subagents
orchestrator: can spawn all subagents (full delegation)fixer: leaf node — prompt forbids delegationdesigner: leaf node (cannot spawn subagents)explorer,librarian,oracle: leaf nodes (cannot spawn subagents)
Configuration Schema Hierarchy
PluginConfig
├── preset?: string
├── setDefaultAgent?: boolean
├── scoringEngineVersion?: 'v1' | 'v2-shadow' | 'v2'
├── balanceProviderUsage?: boolean
├── manualPlan?: ManualPlan
├── presets?: Record<string, Preset>
├── agents?: Record<string, AgentOverrideConfig>
├── disabled_mcps?: string[]
├── tmux?: TmuxConfig
├── background?: BackgroundTaskConfig
└── fallback?: FailoverConfig
AgentOverrideConfig
├── model?: string | ModelEntry[]
├── temperature?: number
├── variant?: string
├── skills?: string[] // "*" = all, "!item" = exclude
└── mcps?: string[] // "*" = all, "!item" = exclude
TmuxConfig
├── enabled: boolean
├── layout: TmuxLayout
└── main_pane_size: number
FailoverConfig
├── enabled: boolean
├── timeoutMs: number
├── retryDelayMs: number
└── chains: Record<string, string[]>
Agent Names
ORCHESTRATOR_NAME:'orchestrator'SUBAGENT_NAMES:['explorer', 'librarian', 'oracle', 'designer', 'fixer']ALL_AGENT_NAMES:['orchestrator', 'explorer', 'librarian', 'oracle', 'designer', 'fixer']AGENT_ALIASES: Legacy name mappings ({ explore: 'explorer' })
TypeScript Types
PluginConfig: Main configuration objectAgentOverrideConfig: Per-agent configuration overridesTmuxConfig: Tmux integration settingsTmuxLayout: Layout enum (main-horizontal,main-vertical,tiled,even-horizontal,even-vertical)Preset: Named agent configuration presetsAgentName: Union type of all agent namesMcpName: Union type of available MCPs ('websearch','context7','grep_app')BackgroundTaskConfig: Background task concurrency settingsFailoverConfig: Failover behavior configurationModelEntry: Normalized model entry with optional per-model variant ({ id: string; variant?: string })ManualAgentName: Union type for manual agent configurationManualPlan: Full manual planning configuration
loadPluginConfig(directory)
│
├─→ Find user config path
│ └─→ findConfigPath(~/.config/opencode/oh-my-opencode-slim)
│ └─→ Prefers .jsonc over .json
│
├─→ Load user config with loadConfigFromPath()
│ └─→ stripJsonComments() → JSON.parse()
│ └─→ PluginConfigSchema.safeParse()
│ └─→ Returns null if invalid/missing
│
├─→ Find project config path
│ └─→ findConfigPath(<directory>/.opencode/oh-my-opencode-slim)
│
├─→ Load project config (same validation)
│
├─→ Deep merge configs (project overrides user)
│ ├─→ Top-level: project replaces user
│ └─→ Nested (agents, tmux, fallback): deepMerge()
│
├─→ Apply environment preset override
│ └─→ OH_MY_OPENCODE_SLIM_PRESET takes precedence
│
└─→ Resolve and merge preset
├─→ Find preset in config.presets[preset]
├─→ Deep merge preset agents with root agents
└─→ Warn if preset not found
deepMerge(base?, override?)
│
├─→ If base is undefined → return override
├─→ If override is undefined → return base
│
└─→ For each key in override
├─→ If both values are non-null, non-array objects
│ └─→ Recursively deepMerge
└─→ Otherwise → override replaces base
loadAgentPrompt(agentName, preset?)
│
├─→ Validate preset name (alphanumeric + underscore/dash)
│
├─→ Build prompt search dirs
│ ├─→ If preset is safe:
│ │ 1) ~/.config/opencode/oh-my-opencode-slim/{preset}
│ │ 2) ~/.config/opencode/oh-my-opencode-slim
│ └─→ Otherwise:
│ 1) ~/.config/opencode/oh-my-opencode-slim
│
├─→ Read first existing {agentName}.md from search dirs
│ └─→ If found → replacement prompt
│
└─→ Read first existing {agentName}_append.md from search dirs
└─→ If found → append prompt
External Dependencies
zod: Runtime schema validationnode:fs,node:path: File system operations
Internal Dependencies
src/cli/config-io.ts- JSONC comment stripping utility (stripJsonComments)src/cli/paths.ts- Config directory resolution (getConfigDir)
Direct Consumers
src/index.ts- Main plugin entry point (imports configuration)src/agents/index.ts- Agent configuration and initializationsrc/cli/providers.ts- CLI provider resolution
src/config/
├── loader.ts # Config loading, merging, and prompt loading
├── schema.ts # Zod schemas and TypeScript types
└── constants.ts # Agent names, defaults, timeouts, delegation rules
POLL_INTERVAL_MS(500ms): Standard polling intervalPOLL_INTERVAL_SLOW_MS(1000ms): Slower polling for background tasksPOLL_INTERVAL_BACKGROUND_MS(2000ms): Background task polling
DEFAULT_TIMEOUT_MS(2 minutes): Default operation timeoutMAX_POLL_TIME_MS(5 minutes): Maximum polling durationFALLBACK_FAILOVER_TIMEOUT_MS(15 seconds): Failover timeout
STABLE_POLLS_THRESHOLD(3): Number of stable polls before considering state settled
| Agent | Default Model |
|---|---|
| orchestrator | runtime-resolved |
| oracle | openai/gpt-5.4 |
| librarian | openai/gpt-5.4-mini |
| explorer | openai/gpt-5.4-mini |
| designer | openai/gpt-5.4-mini |
| fixer | openai/gpt-5.4-mini |
| Parent Agent | Can Spawn |
|---|---|
| orchestrator | explorer, librarian, oracle, designer, fixer |
| fixer | (none - leaf node) |
| designer | (none - leaf node) |
| explorer | (none - leaf node) |
| librarian | (none - leaf node) |
| oracle | (none - leaf node) |
Configuration Loading
- Missing config files: Returns empty config (expected behavior)
- Invalid JSON/JSONC: Logs warning, returns null
- Schema validation failure: Logs detailed Zod error format, returns null
- File read errors (non-ENOENT): Logs warning, returns null
Prompt Loading
- Missing prompt files: Returns empty object (expected behavior)
- File read errors: Logs warning, continues to next search path
Preset Resolution
- Invalid preset name (contains unsafe characters): Ignored, uses root config
- Missing preset: Logs warning with available presets, continues without preset
Adding New Agents
- Add to
SUBAGENT_NAMESinconstants.ts - Add default model to
DEFAULT_MODELS - Add to
SUBAGENT_DELEGATION_RULES - Add to schema in
schema.tsif needed (ManualPlanSchema, FallbackChainsSchema)
Adding New MCPs
- Add to
McpNameSchemaenum inschema.ts
Adding New Configuration Options
- Add to
PluginConfigSchemainschema.ts - Update deep merge logic in
loader.tsif nested object