04. Project configuration and CLI settings¶
🎯 Objective¶
Understand the difference between server/project configuration (opencode.json(c)) and terminal client configuration (cli.json), and use both.
🧩 Two distinct configurations¶
| File | Controls | Scope |
|---|---|---|
opencode.json(c) |
Server and project: model, agents, commands, permissions, MCP, providers, formatters... | Global/system/project |
cli.json |
Terminal client only: theme, keybinds, tabs, diffs, sounds, mini... | User-global |
Rule of thumb: no theme/keybind goes in
opencode.json; no model/agent/permission goes incli.json.
📋 opencode.json(c) — server and project¶
{
"$schema": "https://opencode.ai/config.json",
"model": "anthropic/claude-sonnet-4-5",
"permissions": [
{ "action": "shell", "resource": "git push *", "effect": "ask" }
]
}
Full commented example:
exemplos/opencode.jsonc.
Locations and precedence¶
/etc/opencode/opencode.json # system (Linux)
~/.config/opencode/opencode.json # user-global
<project>/opencode.json # project
<project>/.opencode/opencode.json # project (.opencode overrides the direct file)
The search goes up from the current directory to the filesystem root. Discovered .opencode configs override direct configs. System and managed preferences have the highest precedence.
Common fields¶
model, default_agent, permissions, policies, agents, commands, plugins, providers, mcp, skills, instructions, references, formatter, shell, update, watcher, compaction, warming, snapshots, media, tool_output, websearch, worktree.
Variables and secrets¶
{
"model": "{env:OPENCODE_MODEL}",
"providers": {
"anthropic": { "settings": { "apiKey": "{env:ANTHROPIC_API_KEY}" } }
}
}
{env:VAR}substitutes an environment variable{file:path}inserts the contents of a file (good for keys kept out of Git)
🎛️ cli.json — terminal client¶
{
"$schema": "https://opencode.ai/v2/cli.json",
"theme": { "name": "tokyonight", "mode": "system" },
"keybinds": { "leader": "ctrl+x" },
"session": { "thinking": "show", "tps": true },
"diffs": { "source": "branch", "view": "auto" },
"attention": { "notifications": true, "sound": true }
}
- Path:
~/.config/opencode/cli.json(or$XDG_CONFIG_HOME/opencode/cli.json). There is no per-projectcli.json. - Inline config:
OPENCODE_CLI_CONFIG_CONTENT='{"tabs":{"mode":"off"}}' opencode - Main groups:
theme,animations,cursor,mouse,scroll,prompt,session,tabs,diffs,attention,terminal,mini,keybinds,plugins,debug. - Prefer Ctrl+P → Open settings in the TUI to change the essentials.
🖋️ Formatters (auto-format files)¶
Disabled by default; enable in opencode.json(c) to have OpenCode format files after write/edit/patch:
// enable every available built-in formatter
{ "formatter": true }
// or customize/extend:
{
"formatter": {
"prettier": { "extensions": [".js", ".ts"] },
"deno-markdown": { "command": ["deno", "fmt", "$FILE"], "extensions": [".md"] }
}
}
There are built-in formatters (gofmt, prettier, biome, ruff, rustfmt, shfmt, terraform…). command is an array (not a shell), with $FILE replaced by the absolute path.
❓ Hands-on challenge¶
- Create an
opencode.jsoncin your project with$schemaand amodel - Set
{ "action": "shell", "resource": "git push *", "effect": "ask" }inpermissionsand test it - Adjust the theme and a keybind in
cli.jsonand restart the TUI - Enable
formatter: trueand see a file formatted after an edit
📚 Official source¶
- Config · CLI settings · Keybinds · Formatters
Next step: Lesson 05 — Models & Providers · Back to module