Skip to content

OpenCode

The agent runtime on ruche, the disposable agent Host. Model-agnostic, driven through OpenRouter. Docs: opencode.ai/docs

  • URL: no public URL — a CLI, started per session
  • Data: nothing durable. Config in /etc/opencode/, workspace in ~/workspace/
Terminal window
auberge deploy opencode -H ruche # this App alone
auberge deploy ruche -H ruche # the whole agent tier

[!IMPORTANT] The role is guarded on when: "'agent' in group_names", so the Host must carry tags = ["agent"] in hosts.toml or the deploy is a green no-op that installs nothing. auberge host list shows the TAGS column. Not to be confused with tailnet_tag = "agent", an unrelated field naming the ACL tier.

Key Purpose
opencode_openrouter_api_key OpenRouter API key — the only model credential on the Host

Mint the key at openrouter.ai/keys and store it the way every other secret is stored — a ! command reference in config.toml, never a literal.

The role deploys /etc/opencode/opencode.json: allow-all per tool plus an explicit deny list, per ADR-0065.

Denied Why
sudo, doas keeps the box’s own config out of ordinary reach
git push --force / -f / +ref:ref rewrites history other people and CI depend on
root- and $HOME-anchored rm -rf, mkfs, dd recoverable only by rebuilding the Host
reading *.env and /etc/opencode/* keeps credentials out of transcripts by default

bash is allow-all, so the read denies do not stop cat reaching .env or the key file. They keep those out of context by default, which matters because transcripts leave the box.

OpenCode flattens the whole permission object into one list in key order and takes the last match. Two consequences the file’s shape hides:

  • The catch-all "*": "allow" must be first in each block.
  • There must be no top-level "*". It matches every tool, and merging with any lower-precedence config that mentions the same tool sinks it below the whole deny list — measured moving from index 0 to index 17, behind all sixteen denies, on a project config that only set {"bash":{"harmless-noop":"deny"}}.

tests/opencode_permission_baseline.rs simulates that evaluation and fails the build on either.

The OpenRouter key never appears in the config. It lands in /etc/opencode/openrouter.key (mode 0640, root-owned, agent-readable) and the config references it as {file:/etc/opencode/openrouter.key}.

AGENTS.md is deployed root-owned to the workspace root and named in the config’s instructions, so it loads in every session regardless of where one starts.

Model routing defaults to openrouter/anthropic/claude-sonnet-5, with openrouter/anthropic/claude-haiku-4.5 for lightweight calls. Override with opencode_model / opencode_small_model.

Terminal window
opencode debug config # the resolved configuration, managed tier included
opencode --version # what the install guard reads back