Model: openai/gpt-5.4 Generated: 2026-04-01 Book: Claude Code VS OpenCode: Architecture, Design and The Road Ahead Chapter: 8 — Configuration and Customization Token Usage: N/A (runtime does not expose per-file token counts)
8.1 Multi-Level Config Precedence
Configuration precedence is where an agent stops being a toy and becomes an operating system. The core question is simple: when the same option is defined in multiple places, which one wins? But behind that question lies a deeper design problem: how much flexibility can a system offer before it becomes mentally expensive to use?
OpenCode, Claude Code, and Oh-My-OpenCode (OMO) answer this question very differently.
OpenCode: seven layers, maximum flexibility
OpenCode implements the richest precedence stack of the three. In config/config.ts, the loading order is explicitly documented from low to high precedence:
- remote
.well-known/opencode - global
~/.config/opencode/opencode.jsonc - custom
OPENCODE_CONFIGpath - project
opencode.jsonc .opencode/directory config- inline
OPENCODE_CONFIG_CONTENT - managed enterprise config
This is not just a list of files. It is a policy hierarchy.
The remote .well-known/opencode layer acts like organization defaults. It allows a hosted control plane to publish baseline behavior. The global config in the user home directory then personalizes the tool for one developer across projects. OPENCODE_CONFIG adds an explicit override path, useful for scripts, experiments, or containerized environments. Project config makes the repository itself opinionated. The .opencode/ directory adds a content-oriented layer: not only config files, but agents, commands, modes, and plugins. Then OPENCODE_CONFIG_CONTENT provides an inline ephemeral override, ideal for automation. Finally, managed enterprise config wins over everything else.
In other words, OpenCode treats configuration as a merge graph rather than a single settings file. That is powerful, especially in teams that need central policy, local personalization, and per-project conventions simultaneously.
config/paths.ts reinforces this design by traversing upward for project files and .opencode directories. This upward search is important. It means configuration is not only attached to the current directory, but to the directory tree. The closer a config is to the working directory, the more specific it becomes.
There is also a subtle implementation detail with large consequences: OpenCode uses JSONC parsing, environment substitution, file inclusion, and deep merging. JSONC means JSON with comments and trailing commas. That sounds minor, but in practice it converts a machine-only format into a human-maintainable one.
Claude Code: fewer layers, lower cognitive load
Claude Code is much simpler. At a high level, its configuration model is:
- global
~/.claude/settings.json - project
.claude/settings.json - managed settings
The surrounding codebase contains more nuance, including managed file directories and remote managed settings, but the mental model exposed to the user is intentionally smaller than OpenCode’s. The settings system centers on one global file and one project file, with enterprise policy layered on top.
This simplicity is a product decision. Claude Code is optimized for reliability and predictability in a commercial environment. Fewer layers mean fewer surprise interactions. A developer usually knows where to look: either their global settings, the repository’s .claude/settings.json, or the organization policy.
The tradeoff is reduced composability. OpenCode supports use cases like inline config injection and alternate config roots much more naturally. Claude Code instead prefers a bounded configuration surface. That makes support, documentation, and enterprise governance easier, but it gives advanced users fewer knobs.
OMO: three-level plugin config, deliberately narrow
OMO adds its own configuration system on top of OpenCode, but it keeps that system intentionally small. In src/plugin-config.ts, the load order is:
- defaults
- user
~/.config/opencode/oh-my-opencode.jsonc - project
.opencode/oh-my-opencode.jsonc
This is just three levels. Compared with OpenCode’s seven, it is refreshingly constrained.
Why can OMO afford to do that? Because it is not replacing OpenCode’s base config. It is configuring the OMO plugin layer itself. OpenCode still governs host-level behavior such as global agent configuration, project discovery, remote config, and managed enterprise overrides. OMO only needs enough structure to express plugin-specific concerns: agents, categories, hooks, commands, skills, Claude Code compatibility options, experimental behavior, and so on.
The schema footprint is large even though the precedence chain is small. The directory src/config/schema/ contains 22 Zod v4 schema files. Zod is a TypeScript-first validation library; a schema here means a machine-checked description of valid config structure. This separation is important: OMO keeps the number of precedence layers low while still allowing a rich internal shape.
OMO also supports JSONC. That matters even more in OMO than in many systems because OMO config is often read and edited by humans experimenting with agent orchestration. Comments and trailing commas make exploratory tuning safer.
Another notable design choice is partial fallback. If a config file contains an invalid section, OMO can still load the valid sections and skip the broken ones. This is a developer-experience choice. It favors graceful degradation over all-or-nothing rejection.
How OMO’s three layers coexist with OpenCode’s seven
The cleanest way to think about OMO is as a nested configuration subsystem.
OpenCode first resolves its own precedence stack and loads the host environment. Inside that host, OMO then loads oh-my-opencode.jsonc using its own narrower precedence chain. So the systems do not compete for the same namespace; they operate at different architectural levels.
That separation is one of OMO’s most elegant design decisions. If OMO had tried to mirror all seven OpenCode layers, the resulting mental model would be chaotic: users would have to reason about two overlapping precedence ladders. Instead, OMO says: host-level concerns belong to OpenCode; orchestration-level concerns belong to OMO.
This is a useful general lesson in extensible agent design. Plugins should not duplicate the host’s configuration hierarchy unless they absolutely must. Otherwise, every extension becomes a second operating system inside the first.
Flexibility versus confusion
This chapter’s real theme is not “which system is best,” but “what kind of confusion each system is willing to tolerate.”
OpenCode maximizes flexibility. It is excellent for power users, platform engineers, and plugin authors. But seven precedence levels are hard to hold in working memory. When something behaves unexpectedly, debugging config interactions can become a genuine systems problem.
Claude Code minimizes that problem by shrinking the stack. It gives up some flexibility in exchange for a configuration model that is easier to explain, teach, and support.
OMO chooses a hybrid path. It inherits a complex host, but its own layer stays intentionally compact. That is arguably the most scalable pattern: let the platform be expressive, while each extension remains disciplined.
The broader design principle is clear. More layers increase adaptability, but they also increase interpretive burden. In human-computer interaction terms, configuration precedence is a form of hidden control flow. The more hidden branches exist, the more users must simulate the system in their heads.
The best agent architectures therefore do not merely add precedence levels because they can. They add them only when each level corresponds to a distinct social scope: organization, user, project, runtime, or policy. When the levels map cleanly to real-world ownership boundaries, users can understand them. When they do not, flexibility turns into fog.