Headroom for Teams: 3 months free with a 12-month plan →
Headroom

OpenCode Integration

Route OpenCode traffic through Headroom for token compression, MCP tools, and cached model access. One command to wrap, one to unwrap.

Use headroom wrap opencode to route OpenCode LLM traffic through the Headroom proxy with a single command. The wrapper starts or reuses the proxy, writes OpenCode config, injects Headroom MCP tools, and launches OpenCode with the generated config.

The headroom-opencode npm package also exports a native OpenCode plugin. The plugin can be used directly from OpenCode config when you want in-process transport interception plus the Headroom retrieve tool.

Quick Start

headroom wrap opencode

When you are done:

headroom unwrap opencode

What wrap opencode Does

StepWhat happens
ProxyStarts the Headroom proxy unless --no-proxy is set
Provider injectionWrites a headroom provider using @ai-sdk/openai-compatible into opencode.json, pointing at http://127.0.0.1:<port>/v1
Runtime envSets OPENCODE_CONFIG_CONTENT with provider, plugin, and optional local MCP config so OpenCode picks up Headroom at launch
Provider compatibilityLeaves OPENAI_BASE_URL and ANTHROPIC_BASE_URL untouched so OpenCode /connect providers keep their own routing
MCP setupRegisters the Headroom MCP server (headroom_compress, headroom_retrieve, headroom_stats)
Serena MCPOptionally registers Serena code graph tools (--no-serena to skip)
BackupSnapshots opencode.json to opencode.json.headroom-backup before making any changes
LaunchStarts the opencode binary through the proxy

Options

headroom wrap opencode \
  --port 8787 \
  --no-mcp \
  --no-serena \
  --code-graph \
  --no-proxy \
  --openai-api-url https://api.deepseek.com/v1 \
  --learn \
  --memory \
  --backend anthropic \
  --anyllm-provider ... \
  --region ... \
  -- <opencode args>

Pass --openai-api-url when OpenCode should route through a third-party OpenAI-compatible provider instead of OpenAI itself — DeepSeek, Together, OpenRouter, or a self-hosted gateway. Without it, OpenAI-compatible traffic is forwarded to the default upstream (https://api.openai.com/v1), so a non-OpenAI key is rejected with 401 Incorrect API key provided. Setting OPENAI_TARGET_API_URL before wrapping has the same effect. See OpenCode + DeepSeek for a full walkthrough.

The flag means the same thing whether or not wrap starts the proxy:

# wrap starts the proxy and points it at DeepSeek
headroom wrap opencode --openai-api-url https://api.deepseek.com/v1

# reuse a proxy you started yourself — it must already target that upstream
headroom proxy --port 8787 --openai-api-url https://api.deepseek.com/v1
headroom wrap opencode --no-proxy --openai-api-url https://api.deepseek.com/v1

With --no-proxy, wrap never starts or re-points a proxy. It checks the one listening on --port and exits with an error — before it rewrites opencode.json — if nothing is listening, the listener is not a Headroom proxy, or it forwards OpenAI-compatible traffic to a different upstream. Start the proxy with the upstream you want, or drop --no-proxy and let wrap start it.

Provider Model Mapping

The generated headroom provider exposes these models through the proxy:

Provider modelUpstream model
headroom/claude-sonnet-4-6Claude Sonnet 4.6, 200K context, 16K output
headroom/claude-opus-4-6Claude Opus 4.6, 200K context, 16K output
headroom/claude-haiku-4-5-20251001Claude Haiku 4.5, 200K context, 8K output
headroom/gpt-4oGPT-4o, 128K context, 16K output
headroom/gpt-4.1GPT-4.1, 1M context, 32K output

The default model is headroom/claude-sonnet-4-6. Change it in opencode.json or in the generated OPENCODE_CONFIG_CONTENT payload.

Environment Variables

VariableDescription
OPENCODE_CONFIG_CONTENTJSON payload with provider, plugin, and optional local MCP config injected by wrap
HEADROOM_PROXY_URLProxy URL passed to Headroom MCP when a non-default port is used, and to the native plugin when configured
OPENAI_TARGET_API_URLUpstream for OpenAI-compatible traffic when --openai-api-url is not passed; defaults to https://api.openai.com/v1
HEADROOM_OPENCODE_EXCLUDE_HOSTSComma-separated hosts (and their subdomains) the native plugin sends straight upstream instead of through the proxy, for example opencode.ai,.corp.internal

Failure Learning

headroom learn supports OpenCode as a scan target. It reads past sessions from the newer of ~/.local/share/opencode/opencode-local.db and ~/.local/share/opencode/opencode.db, or from HEADROOM_OPENCODE_DB when you set an explicit override, and writes corrections to your project's AGENTS.md.

headroom learn --agent opencode --apply

See Failure Learning for details on the learn system.

Persistent Installs

headroom install supports OpenCode as a target for persistent provider wiring. Use provider scope when you want Headroom to edit opencode.json directly:

headroom install apply --preset persistent-service --scope provider --providers manual --target opencode

This writes the Headroom provider into ~/.config/opencode/opencode.json and keeps the proxy running on port 8787.

The default user scope only writes shell environment configuration. For OpenCode, direct provider config requires --scope provider.

Native OpenCode Plugin

The headroom-opencode package's default export is a native OpenCode plugin that works with both OpenCode 1.x and 2.x. It installs Headroom transport interception inside OpenCode, exposes the headroom_retrieve tool, and adds Headroom metadata (HEADROOM_ACTIVE, HEADROOM_PROXY_URL, HEADROOM_PROJECT) to the environment of shell commands OpenCode runs.

Register it in opencode.json:

{
  "plugin": [
    ["headroom-opencode", { "proxyUrl": "http://127.0.0.1:8787" }]
  ]
}

OpenCode 2.x migrates the 1.x plugin key automatically. To configure it the 2.x way, use "plugins": [{ "package": "headroom-opencode", "options": { "proxyUrl": "http://127.0.0.1:8787" } }]. Without proxyUrl, the plugin reads HEADROOM_PROXY_URL and falls back to http://127.0.0.1:8787.

The default export has server for OpenCode 1.x and setup for OpenCode 2.x. Each version ignores the other's field. HeadroomPlugin (1.x) and headroomSetup (2.x) are also exported by name for custom wrappers.

Use this plugin when OpenCode should intercept provider traffic in-process. Use headroom wrap opencode when you want the CLI to manage the proxy, config injection, MCP registration, backups, and unwrap behavior.

The plugin routes every external HTTP(S) request through the proxy. To keep a provider or gateway off the proxy while leaving the plugin loaded, pass excludeHosts in the plugin options or set HEADROOM_OPENCODE_EXCLUDE_HOSTS before launching OpenCode. An entry matches the host and all of its subdomains; excluded requests are sent as-is, with no compression or telemetry.

// opencode.json
{
  "plugin": [["/path/to/headroom/providers/opencode/_dist/entry.opencode.js", { "excludeHosts": ["opencode.ai"] }]]
}

Programmatic Config Helpers

The package also exports helpers for custom integrations:

import {
  buildOpencodeConfigContent,
  createHeadroomProvider,
  createHeadroomRetrieveTool,
} from "headroom-opencode";

const provider = createHeadroomProvider({ proxyPort: 8787 });
const config = buildOpencodeConfigContent({
  proxyPort: 8787,
  defaultModel: "claude-sonnet-4-6",
});
const retrieve = createHeadroomRetrieveTool({
  proxyBaseUrl: "http://127.0.0.1:8787",
});

How It Works Under The Hood

  1. Config injection. The wrapper writes a provider.headroom block into opencode.json. The provider uses @ai-sdk/openai-compatible, which OpenCode supports natively. Model mappings route requests through http://127.0.0.1:<port>/v1.
  2. Runtime config. OPENCODE_CONFIG_CONTENT is set as an env var containing provider, plugin, and optional local MCP JSON. OpenCode reads it at startup and merges it with on-disk config.
  3. MCP tools. Headroom registers headroom_compress, headroom_retrieve, and headroom_stats through headroom mcp serve unless --no-mcp is set.
  4. Native plugin path. wrap loads the transport plugin from a local directory (plugins/opencode/dist/ in a checkout, headroom/providers/opencode/_dist/ in the wheel), because OpenCode 2.x only accepts local plugins as directories. The plugin uses HEADROOM_PROXY_URL or http://127.0.0.1:8787 to reach the proxy.
  5. Unwrap. headroom unwrap opencode restores opencode.json from the pre-wrap backup when present, strips Headroom marker blocks when no backup exists, and unregisters Headroom MCP servers.

Troubleshooting

OpenCode does not use the headroom provider.

Check that OPENCODE_CONFIG_CONTENT is set and contains the provider.headroom block. The wrap command prints the env vars it sets.

OpenCode 2.x traffic does not show up in Headroom.

OpenCode 2.x connects to a shared background service by default. A service that was already running when you wrapped never sees Headroom's config. headroom wrap opencode adds --standalone on 2.x so OpenCode runs a private server with that config instead. If you pass --server <url>, that server must be started with Headroom's config too. Check what OpenCode actually loaded with opencode api plugin.list --param directory="$PWD", which should list headroom.

The native plugin cannot reach Headroom.

Set HEADROOM_PROXY_URL to the running proxy URL, for example http://127.0.0.1:8787.

One provider rejects requests only while the plugin is loaded.

Some gateways validate the client on the wire and reject the proxy hop. Exclude that host with HEADROOM_OPENCODE_EXCLUDE_HOSTS=<host> (or the excludeHosts plugin option); Headroom keeps routing every other provider.

Provider not found after unwrap.

If unwrap left the provider configured, run headroom unwrap opencode again, or manually restore from ~/.config/opencode/opencode.json.headroom-backup.

Proxy port conflict.

Use --port to select a specific port, or let the proxy auto-select an available one.

On this page