codemap.md 8.6 KB

Config Module Codemap

Responsibility

The src/config/ module is responsible for:

  1. Schema Definition: Type-safe configuration validation using Zod schemas
  2. Configuration Loading: Loading, validating, and merging plugin configuration from multiple sources (user config, project config, environment variables)
  3. Constants Management: Centralizing agent names, default models, delegation rules, polling intervals, and timeouts

Design

Key Patterns

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 delegation
  • designer: leaf node (cannot spawn subagents)
  • explorer, librarian, oracle: leaf nodes (cannot spawn subagents)

Core Abstractions

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 object
  • AgentOverrideConfig: Per-agent configuration overrides
  • TmuxConfig: Tmux integration settings
  • TmuxLayout: Layout enum (main-horizontal, main-vertical, tiled, even-horizontal, even-vertical)
  • Preset: Named agent configuration presets
  • AgentName: Union type of all agent names
  • McpName: Union type of available MCPs ('websearch', 'context7', 'grep_app')
  • BackgroundTaskConfig: Background task concurrency settings
  • FailoverConfig: Failover behavior configuration
  • ModelEntry: Normalized model entry with optional per-model variant ({ id: string; variant?: string })
  • ManualAgentName: Union type for manual agent configuration
  • ManualPlan: Full manual planning configuration

Flow

Configuration Loading Flow

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

Deep Merge Algorithm

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

Prompt Loading Flow

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

Integration

Dependencies

External Dependencies

  • zod: Runtime schema validation
  • node: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)

Consumers

Direct Consumers

  • src/index.ts - Main plugin entry point (imports configuration)
  • src/agents/index.ts - Agent configuration and initialization
  • src/cli/providers.ts - CLI provider resolution

File Organization

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

Constants Reference

Polling Configuration

  • POLL_INTERVAL_MS (500ms): Standard polling interval
  • POLL_INTERVAL_SLOW_MS (1000ms): Slower polling for background tasks
  • POLL_INTERVAL_BACKGROUND_MS (2000ms): Background task polling

Timeouts

  • DEFAULT_TIMEOUT_MS (2 minutes): Default operation timeout
  • MAX_POLL_TIME_MS (5 minutes): Maximum polling duration
  • FALLBACK_FAILOVER_TIMEOUT_MS (15 seconds): Failover timeout

Stability

  • STABLE_POLLS_THRESHOLD (3): Number of stable polls before considering state settled

Default Models

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

Delegation Rules

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)

Error Handling

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

Extension Points

Adding New Agents

  1. Add to SUBAGENT_NAMES in constants.ts
  2. Add default model to DEFAULT_MODELS
  3. Add to SUBAGENT_DELEGATION_RULES
  4. Add to schema in schema.ts if needed (ManualPlanSchema, FallbackChainsSchema)

Adding New MCPs

  1. Add to McpNameSchema enum in schema.ts

Adding New Configuration Options

  1. Add to PluginConfigSchema in schema.ts
  2. Update deep merge logic in loader.ts if nested object