Home
Home/s10
s1060 lines of code

Config & Session

Configure Once, Run Everywhere

Key Insight:

A single config file controls the entire agent harness behavior.

OpenCode uses a single configuration file (opencode.jsonc) that declares the model, plugins, skill paths, and all other settings. The default file resides at ~/.config/opencode/opencode.jsonc. Projects can override settings by placing their own opencode.jsonc in the project root; settings merge rather than replace.

Architecture Flow

The Problem: Every Project Is Different, Every Developer Has Preferences

A developer might prefer Claude Sonnet for most tasks but need GPT-4 for a specific project. They might have personal skill collections while their team maintains shared project skills. The config system must reconcile global defaults, which are sensible for everyone, with project overrides that are specific to a repo, while preserving the ability to override anything without copying everything. Deep merge solves this: global config provides defaults; project config overrides specific fields; everything else remains unchanged.

Discoverability and the $schema

The opencode.jsonc file references a JSON Schema through its $schema URL. This is not decorative: it enables IDE autocompletion, validation, and inline documentation when editing the config file. The schema also serves as the canonical reference for all available configuration options. New options are added to the schema first, then implemented in the code. This documentation-driven approach ensures the config surface is always documented and validated.

Real Implementation: Event-Sourced Sessions with SQLite

OpenCode's session system (packages/core/src/session.ts) goes beyond config management. Sessions are event-sourced and stored in SQLite via Drizzle ORM. Each session maintains a timeline of durable events (Created, PromptSubmitted, StepEnded, Compacted, and others) that are projected into the current context. This means sessions survive restarts, support revert and rollback through event replay, and can be shared between processes through the same SQLite store. The SessionRunCoordinator serializes execution per session with wake coalescing: if two prompts arrive simultaneously, they are queued and processed sequentially rather than in parallel.

Design Decisions

Config discovery walks up the directory tree from the project root, not from the current working directory. This means any subdirectory within a project correctly resolves to the project's opencode.jsonc.

JSONC format (JSON with comments) is used instead of plain JSON. Comments make the config self-documenting: developers can annotate their choices inline without maintaining a separate documentation file.

Comparison: Claude Code

Both systems use config files, but OpenCode's multi-source deepMerge pattern is more elaborate. The global config (~/.config/opencode/) provides defaults, the project config overrides specifics, and the two are merged recursively. Claude Code uses a simpler single-config approach. OpenCode's session system also adds compaction and message versioning, which are critical for long-running sessions that would otherwise exceed context windows.

Deep Dive: Design Decisions

One Config to Rule Them All

opencode.jsonc (or opencode.json) is the single configuration file. It declares the model, plugins, skill paths, and other settings. Everything the agent needs to start is in one place.

Alternatives: Multiple config files (one per concern) would be more modular but harder to discover and debug. A single file is simpler to understand and version-control.

Global Config with Per-Project Override

The default config lives at ~/.config/opencode/opencode.jsonc. Projects can override by placing their own opencode.jsonc in the project root. Settings merge, not replace.

Alternatives: Only global config would be simpler but not flexible. Only per-project would require setup for every project. The merge model gives both consistency and flexibility.

Learn OpenCode — Built with Next.js