# Configuration Reference Complete reference for all configuration files and options in oh-my-opencode-slim. For repository-specific configurations, custom agents, and prompt directory lookups, see the [Project-local Customization Guide](project-local-customization.md). --- ## Config Files | File | Purpose | |------|---------| | `~/.config/opencode/opencode.json` | OpenCode core settings (plugin registration, providers) | | `~/.config/opencode/oh-my-opencode-slim.json` | Plugin settings - agents, multiplexer, MCPs, council | | `~/.config/opencode/oh-my-opencode-slim.jsonc` | Same, but with JSONC (comments + trailing commas). Takes precedence over `.json` if both exist | | `.opencode/oh-my-opencode-slim.json` | Project-local overrides (optional, higher precedence than user config) | > **💡 JSONC recommended:** Use the `.jsonc` extension to add comments and trailing commas. If both `.jsonc` and `.json` exist, `.jsonc` takes precedence. Set `OPENCODE_CONFIG_DIR` to use a custom user config directory instead of `~/.config/opencode`; install and runtime config discovery both honor it. Set `OH_MY_OPENCODE_SLIM_DISABLE` to `1`, `true`, `yes`, or `on` to make oh-my-opencode-slim return during startup without registering agents, tools, MCPs, hooks, Companion, or the TUI sidebar. This is a temporary escape hatch: ```bash OH_MY_OPENCODE_SLIM_DISABLE=1 opencode ``` If OmO-slim detects an invalid plugin config for the current project, the TUI sidebar shows a warning. Run `oh-my-opencode-slim doctor` from your project root for full diagnostics. The TUI sidebar uses the compact layout by default. Set `compactSidebar` to `false` in `oh-my-opencode-slim.jsonc` to use the expanded layout: ```jsonc { "compactSidebar": false } ``` --- ## Prompt Overriding Customize agent prompts without modifying source code. Create markdown files in `~/.config/opencode/oh-my-opencode-slim/`: | File | Effect | |------|--------| | `{agent}.md` | Replaces the agent's default prompt entirely | | `{agent}_append.md` | Appends custom instructions to the default prompt | When a `preset` is active, the plugin checks preset directories before falling back to root directories. Both global user prompt directories and project-local prompt directories are searched. For the complete lookup precedence order, see [Project-local Customization](project-local-customization.md). **Example directory structure:** ``` ~/.config/opencode/oh-my-opencode-slim/ ├── best/ │ ├── orchestrator.md # Preset-specific override (used when preset=best) │ └── explorer_append.md ├── orchestrator.md # Fallback override ├── orchestrator_append.md ├── explorer.md └── ... ``` Both `{agent}.md` and `{agent}_append.md` can coexist - the full replacement takes effect first, then the append. If neither exists, the built-in default prompt is used. --- ## JSONC Format All config files support **JSONC** (JSON with Comments): - Single-line comments (`//`) - Multi-line comments (`/* */`) - Trailing commas in arrays and objects **Example:** ```jsonc { // Active preset "preset": "openai", /* Agent model mappings */ "presets": { "openai": { "oracle": { "model": "openai/gpt-5.6-sol" }, "explorer": { "model": "openai/gpt-5.6-luna" }, }, }, "multiplexer": { "type": "tmux", "layout": "main-vertical", }, } ``` --- ## Full Option Reference | Option | Type | Default | Description | |--------|------|---------|-------------| | `preset` | string | - | Active preset name (e.g. `"openai"`, `"best"`) | | `stripOrchestratorModel` | boolean | `false` | Preserve a runtime `/model` selection for the orchestrator after subagent dispatch by omitting its configured model from the SDK config. A selected preset's explicit `orchestrator.model` is retained. Without a runtime selection, this opt-in delegates the initial orchestrator choice to OpenCode's session default. | ### Runtime Preset Switching Presets can also be switched at runtime without restarting using the `/preset` command. See [Preset Switching](preset-switching.md) for details. | `presets` | object | - | Named preset configurations | |-----------|--------|---|-----------------------------| | `presets...model` | string | - | Model ID in `provider/model` format | | `presets...temperature` | number | - | Temperature (0–2) | | `presets...variant` | string | - | Reasoning effort: `"low"`, `"medium"`, `"high"` | | `presets...displayName` | string | - | Custom user-facing alias for the agent (e.g. `"advisor"` for `oracle`) | | `presets...skills` | string[] | - | Skills the agent can use (`"*"`, `"!item"`, explicit list) | | `presets...mcps` | string[] | - | MCPs the agent can use (`"*"`, `"!item"`, explicit list) | | `presets...options` | object | - | Provider-specific model options passed to the AI SDK (e.g., `textVerbosity`, `thinking` budget) | | `agents..model` | string\|array | - | Required for custom agents inferred from unknown `agents` keys | | `agents..prompt` | string | - | Full execution prompt for a custom agent | | `agents..orchestratorPrompt` | string | - | Exact `@agent` block injected into the orchestrator prompt; must start with `@` | | `agents..permission` | object \| string | - | Tool-level permission rules enforced by the SDK. See [Agent Permissions](#agent-permissions) | | `agents..displayName` | string | - | Custom user-facing alias for the agent in the active config | | `acpAgents..command` | string | - | Command for an external ACP-compatible agent; creates a wrapper subagent named `` | | `acpAgents..args` | string[] | `[]` | Arguments for the ACP agent command | | `acpAgents..env` | object | `{}` | Extra environment variables for the ACP subprocess | | `acpAgents..cwd` | string | session directory | Working directory override for this ACP subprocess; protocol paths should be absolute | | `acpAgents..description` | string | - | Description shown to OpenCode and injected into the orchestrator routing prompt | | `acpAgents..prompt` | string | generated wrapper prompt | Optional full prompt for the lightweight wrapper subagent | | `acpAgents..orchestratorPrompt` | string | generated routing block | Optional exact routing block injected into the orchestrator prompt | | `acpAgents..wrapperModel` | string | fixer default | Cheap OpenCode model used by the wrapper subagent that calls `acp_run` | | `acpAgents..permissionMode` | string | `ask` | How ACP permission requests are handled: `ask`, `allow`, or `reject` | | `acpAgents..timeoutMs` | integer | `0` | Timeout for a single ACP run in milliseconds. `0` disables the timeout so external agents can run indefinitely. Finite values can be up to `2147483647`ms (~24.8 days) | | `disabled_agents` | string[] | `["observer"]` | Agent names to disable globally. Set to `[]` to enable Observer; this is global, not per-preset | | `image_routing` | `"auto"` \| `"direct"` | omitted (legacy conditional) | Optional. When omitted, images are intercepted only when Observer is enabled, preserving existing behavior. Explicit `"auto"` requires Observer enabled and saves image attachments to disk before nudging delegation to @observer. `"direct"`: always pass images to the orchestrator. | | `autoUpdate` | boolean | `true` | Automatically install plugin updates in the background; set to `false` for notification-only mode | | `multiplexer.type` | string | `"none"` | Multiplexer mode: `auto`, `tmux`, `zellij`, `herdr`, `cmux`, `kitty`, or `none` | | `multiplexer.layout` | string | `"main-vertical"` | Layout preset: `main-vertical`, `main-horizontal`, `tiled`, `even-horizontal`, `even-vertical`. Tmux applies full layouts; Zellij and Herdr map supported layouts to split directions; cmux maintains a right-hand agent column | | `multiplexer.main_pane_size` | number | `60` | Main pane size as percentage (20–80) for tmux main layouts; ignored by Zellij, Herdr, and cmux | | `multiplexer.zellij_pane_mode` | string | `"agent-tab"` | Zellij pane placement: `agent-tab` creates/reuses a dedicated `opencode-agents` tab; `current-tab` opens subagents as panes in the tab containing the parent OpenCode pane, falling back to the focused tab if the parent pane cannot be resolved | | `tmux.enabled` | boolean | `false` | Legacy alias for `multiplexer.type = "tmux"` | | `tmux.layout` | string | `"main-vertical"` | Legacy alias for `multiplexer.layout` | | `tmux.main_pane_size` | number | `60` | Legacy alias for `multiplexer.main_pane_size` | | `backgroundJobs.maxSessionsPerAgent` | integer | `2` | Maximum completed/reconciled reusable child sessions per specialist type in the current orchestrator session (1–10) | | `backgroundJobs.readContextMinLines` | integer | `10` | Minimum number of lines read from a file before it appears in reusable background-job context (0–1000) | | `backgroundJobs.readContextMaxFiles` | integer | `8` | Maximum number of recent read-context files shown per reusable child session (0–50) | | `backgroundJobs.maxRetainedSnapshots` | integer | `20` | Maximum board snapshots retained per checkpoint cache epoch (1–100). Adding a snapshot beyond the limit starts a new epoch with only the current snapshot, intentionally creating one cache miss | | `backgroundJobs.strategy` | `"latest"` \| `"checkpoint-compatible"` | `"latest"` | Board injection strategy. `latest` preserves the current strip-and-replace behavior; `checkpoint-compatible` appends only when the formatted board changes and uses `backgroundJobs.maxRetainedSnapshots` per cache epoch. Cache state resets on compaction/session boundaries and is lost on plugin restart | | `backgroundJobs.continueOnIdle` | boolean | `false` | **Beta opt-in.** Set `true` to let idle orchestrator sessions with incomplete todos receive one automatic hidden continuation prompt. When omitted or `false`, idle reconciliation and background-job orchestration remain active without automatic continuation prompts. See [Background Orchestration](background-orchestration.md#incomplete-todo-continuation-nudge) | | `disabled_mcps` | string[] | `[]` | MCP server IDs to disable globally | | `fallback.enabled` | boolean | `true` | Enable model failover on timeout/error | | `fallback.timeoutMs` | number | `15000` | Time before aborting and trying next model | | `fallback.retryDelayMs` | number | `500` | Delay between retry attempts | | `fallback.maxRetries` | number | `3` | Maximum failover attempts before giving up | | `fallback.runtimeOverride` | boolean | `true` | Allow per-call model overrides to bypass the fallback chain | | `fallback.retry_on_empty` | boolean | `true` | Treat silent empty provider responses (0 tokens) as failures and retry. Set `false` to accept empty responses | | `council.presets` | object | - | **Required if using council.** Named councillor presets | | `council.presets...model` | string | - | Councillor model | | `council.presets...variant` | string | - | Councillor variant | | `council.presets...prompt` | string | - | Optional role guidance for the councillor | | `council.default_preset` | string | `"default"` | Default preset when none is specified | | — | — | — | *Timeouts, execution mode, and retries are now handled by the orchestrator's council-mode prompt instructions; see `src/agents/council.ts`.* | | `interview.maxQuestions` | integer | `2` | Max questions per interview round (1–10) | | `interview.outputFolder` | string | `"interview"` | Directory where interview markdown files are written (relative to project root) | | `interview.autoOpenBrowser` | boolean | `true` | Automatically open the interview UI in your default browser during interactive runs; suppressed in tests and CI | | `interview.port` | integer | `0` | Interview server port (0–65535). `0` = OS-assigned random port (per-session mode). Any value > 0 enables [dashboard mode](interview.md#dashboard-mode) | | `interview.dashboard` | boolean | `false` | Enable [dashboard mode](interview.md#dashboard-mode) on the default port (43211). Setting `port` > 0 also enables dashboard mode. If both are set, `port` takes precedence | | `companion.enabled` | boolean | `false` | Enable/disable the floating window Rust companion | | `companion.binaryPath` | string | - | Optional path to a custom companion binary to launch instead of the default install path | | `companion.position` | string | `"bottom-right"` | The initial corner position of the companion window: `bottom-right`, `bottom-left`, `top-right`, or `top-left` | | `companion.size` | string | `"medium"` | The default size preset of the companion window: `small` (80px), `medium` (120px), or `large` (160px) | > **niri note:** `companion-v0.1.3` includes the fixed native companion release. > To make it open as a bottom-right overlay, add a niri rule matching its stable > `app-id`/title (`oh-my-opencode-slim-companion`), for example: > > ```kdl > window-rule { > match app-id=r"^oh-my-opencode-slim-companion$" > match title=r"^oh-my-opencode-slim-companion$" > open-floating true > open-focused false > default-floating-position x=16 y=16 relative-to="bottom-right" > } > ``` ### ACP-connected agents Use `acpAgents` to expose external Agent Client Protocol servers as optional OpenCode subagents. The plugin creates a lightweight wrapper agent for each entry. The wrapper calls the built-in `acp_run` tool, which starts the ACP process, creates a session, sends the task, and returns the streamed result. `command` is only the executable; put flags and subcommands in `args`. See **[ACP Agents](acp-agents.md)** for the dedicated setup guide, auth notes, and troubleshooting. ```jsonc { "acpAgents": { "claude-research": { "command": "claude-code-acp", "args": [], "description": "Claude Code subscription agent for deep research", "wrapperModel": "openai/gpt-5.6-luna", "permissionMode": "ask", "timeoutMs": 300000 }, "gemini-acp": { "command": "gemini", "args": ["--experimental-acp"], "description": "Gemini CLI through ACP" } } } ``` After restart, the orchestrator can delegate to `@claude-research` or `@gemini-acp`. Use safe names matching `^[a-z][a-z0-9_-]*$`; names cannot conflict with built-in or custom agents. `permissionMode` controls ACP permission requests, but the plugin still asks before launching the configured subprocess. ### Council configuration note - The **Council agent model** is configured like any other agent, for example in `presets..council.model`. - The **councillor models** are configured separately under `council.presets...model`. - `council.master*` fields have been removed. A deprecation warning is logged this release if a config still contains them. ### Manual Update Mode Set `autoUpdate` to `false` if you want update notifications without automatic `bun install` runs. ```jsonc { "autoUpdate": false } ``` With `autoUpdate` set to `false`, this becomes notification-only mode: you'll see that a new version is available, but the plugin won't install it automatically. Auto-update never crosses major versions. For example, a 1.x install can auto-update to a newer 1.x release, but it won't auto-install 2.x. When a newer major is available, the plugin shows a migration command instead. > Pinned plugin entries in `opencode.json` (for example > `"oh-my-opencode-slim@1.0.1"`) are the true version lock. Those stay pinned > regardless of `autoUpdate`. ### Background Job Management Background job management is enabled by default and does not need to be present in the starter config. Add `backgroundJobs` only if you want to tune how many completed/reconciled child-agent sessions are reusable, how much read context is shown, how board snapshots are injected, or to opt into beta automatic incomplete-todo continuation prompts on idle: ```jsonc { "backgroundJobs": { "continueOnIdle": true } } ``` Without that opt-in, idle reconciliation and background-job orchestration remain enabled but no hidden continuation prompts are sent. See the [Background Orchestration](background-orchestration.md) guide for the concept, defaults, and examples. ### Agent Display Names Use `displayName` to give an agent a user-facing alias while keeping the internal agent name unchanged. ```jsonc { "agents": { "oracle": { "displayName": "advisor" }, "explorer": { "displayName": "researcher" } } } ``` With this config, users can refer to `@advisor` and `@researcher`, while the plugin still routes them to `oracle` and `explorer` internally. Notes: - `displayName` works in both top-level `agents` overrides and inside `presets` - `@` prefixes and surrounding whitespace are normalized automatically - Display names must be unique - Display names cannot conflict with internal agent names like `oracle` or `explorer` ### Custom Agents Unknown keys under `agents` are treated as custom subagents. A custom agent needs its own `model`, a normal `prompt`, and optionally an `orchestratorPrompt` that teaches the orchestrator exactly when to delegate to it. ```jsonc { "agents": { "janitor": { "model": "github-copilot/gpt-5.6", "prompt": "You are Janitor. Audit codebase entropy, dead code, docs drift, naming inconsistencies, and unnecessary complexity. Prefer analysis and plans over direct edits.", "orchestratorPrompt": "@janitor\n- Role: Maintenance specialist for codebase cleanup and entropy reduction\n- **Delegate when:** after large refactors • cleanup/technical-debt review • dead code or docs drift is suspected\n- **Don't delegate when:** feature implementation • urgent debugging • UI/UX work" } } } ``` Notes: - Custom agent names must be safe identifiers such as `janitor` or `security-reviewer` - Custom agents without a `model` are skipped with a warning - Disabled custom agents are not registered or injected into the orchestrator prompt ### Agent Permissions The `permission` field provides deterministic, tool-level permission restrictions on custom agents, built-in agent overrides, and presets. Unlike prompt instructions ("do not edit files"), these rules are enforced by the OpenCode SDK at the tool-call level. The field accepts either: 1. **Shorthand string** — `"ask"`, `"allow"`, or `"deny"` applied to all tools 2. **Object** — keys are tool names, values are `"ask" | "allow" | "deny"` or (for rule keys) a pattern-to-action map **Example: read-only `planner` agent:** ```jsonc { "agents": { "planner": { "model": "openai/gpt-5.5", "variant": "high", "skills": [], "mcps": ["context7", "websearch"], "permission": { "edit": "deny", "bash": { "*": "ask", "git status*": "allow", "git diff*": "allow", "grep *": "allow" }, "webfetch": "allow", "websearch": "allow", "task": "deny" }, "prompt": "You are Planner. Create implementation plans only. Do not implement code." } } } ``` **Example: `security-reviewer` agent:** ```jsonc { "agents": { "security-reviewer": { "model": "anthropic/claude-sonnet-4-5", "permission": { "edit": "deny", "bash": "deny", "webfetch": "allow" }, "prompt": "You are a security reviewer. Inspect code and report findings. Do not patch anything." } } } ``` #### Permission keys | Key | Value type | Description | |-----|------------|-------------| | `read` | string or object | File reading | | `edit` | string or object | File editing | | `glob` | string or object | File pattern matching | | `grep` | string or object | Content search | | `list` | string or object | Directory listing | | `bash` | string or object | Shell command execution | | `task` | string or object | Subagent task delegation | | `external_directory` | string or object | Access to directories outside the workspace | | `lsp` | string or object | Language server protocol operations | | `skill` | string or object | Skill execution | | `todowrite` | string only | Todo list writing | | `question` | string only | Asking the user questions | | `webfetch` | string only | Web content fetching | | `websearch` | string only | Web search | | `codesearch` | string only | Code search | | `doom_loop` | string only | Doom loop prevention | Keys marked "string or object" accept pattern-based rules (e.g. `bash: { "git status*": "allow", "*": "ask" }`). Keys marked "string only" accept a single `"ask"`, `"allow"`, or `"deny"` value. Unknown tool names (including MCP-derived keys) pass through without error. #### Merge semantics When a user supplies `permission` and also uses the `skills` or `mcps` arrays on the same agent, the plugin merges them: 1. **User-supplied `permission` is the base layer.** 2. **Plugin-generated rules from the `skills` array override `permission.skill`** — the `skills` array is authoritative for skill gating. 3. **Plugin-generated rules from the `mcps` array set `permission._*` keys** — the `mcps` array is authoritative for MCP gating. 4. **User-supplied keys for standard tools** (`edit`, `bash`, `webfetch`, `task`, etc.) survive the merge untouched. Use the `skills`/`mcps` arrays for skill and MCP gating. Use `permission` for everything else (file access, bash, web, task delegation). ### Desktop Companion App The desktop companion app provides a visual status overlay showing running and active agents. For quick installation instructions, binary paths, config defaults, and release information, see the full **[Desktop Companion Guide](companion.md)**. Once installed, configure it in your `oh-my-opencode-slim` settings: ```jsonc { "companion": { "enabled": true, "position": "bottom-right", // optional: bottom-right, bottom-left, top-right, top-left "size": "medium" // optional: small, medium, large } } ```