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/
Deploy
Section titled “Deploy”auberge deploy opencode -H ruche # this App aloneauberge deploy ruche -H ruche # the whole agent tier[!IMPORTANT] The role is guarded on
when: "'agent' in group_names", so the Host must carrytags = ["agent"]inhosts.tomlor the deploy is a green no-op that installs nothing.auberge host listshows the TAGS column. Not to be confused withtailnet_tag = "agent", an unrelated field naming the ACL tier.
Required config
Section titled “Required config”| 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.
Permission baseline
Section titled “Permission baseline”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.
Rule order is load-bearing
Section titled “Rule order is load-bearing”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.
opencode debug config # the resolved configuration, managed tier includedopencode --version # what the install guard reads back