Skip to content

Claude Code is the provider.

The official Claude CLI, with your login, in opencode. Claude keeps its own tools, MCP servers and skills, opencode runs everything that touches your machine, and your login stays in the Claude Code CLI.

tl;dr just install, and support it v0.36.5
{
  "plugin": ["@khalilgharbaoui/opencode-claude-code-plugin"]
}

Add to opencode.json, then relaunch. Requires claude installed and logged in.

  1. opencodeyourun the suite. which test files cover the proxy broker?
  2. pluginspawnclaude --print --output-format stream-json --input-format stream-json --model claude-sonnet-5-5
  3. pluginwith--mcp-config <0600, bearer token inside> --append-system-prompt-file <0600> --disallowedTools Bash Edit MultiEdit Write WebFetch Agent
  4. claude{"type":"system","subtype":"init", … "mcp_servers":[{"name":"opencode_proxy","status":"connected"}]}
  5. claude{"type":"assistant", … {"type":"tool_use","name":"Grep","input":{"pattern":"queuePendingProxyCall"}}} · ran inside Claude Code
  6. claude{"type":"assistant", … {"type":"tool_use","name":"mcp__opencode_proxy__bash","input":{"command":"npm test"}}}
  7. plugintool-callbash → opencode. The CLI's HTTP request stays open, with a keepalive every 15 s.
  8. opencodepermissionrun npm test?
  9. opencodeyouallow once
  10. opencodebashran here, under opencode's own permissions and audit log · 1,083 tests
  11. plugintool-result→ claude. The held request resolves; the model carries on.
  12. claude{"type":"assistant", … {"type":"text","text":"test-broker.ts and test-proxy-task.ts: per-tool deadlines, the guard, stall warnings, fan-out, late results."}}
  13. claude{"type":"result","subtype":"success","is_error":false}
  14. opencodereplytest-broker.ts and test-proxy-task.ts cover the broker: per-tool deadlines, the guard, stall warnings, fan-out and late results. All 1,083 tests pass. · the CLI authenticated this turn; the plugin read no token
  1. opencodeyoudoes this plugin ever touch my Claude login?
  2. pluginreusethe conversation's claude process is still alive: nothing is spawned, only the new message is written to its stdin. Full context kept.
  3. claude{"type":"assistant", … {"type":"tool_use","name":"Read","input":{"file_path":"docs/introduction.md"}}} · ran inside Claude Code, not through the proxy
  4. plugintool-callRead → opencode, as a tool part only: Claude Code runs it, opencode renders the row.
  5. claude{"type":"user", … {"type":"tool_result","tool_use_id":"toolu_01…","content":"# Introduction …"}}
  6. opencodereaddocs/introduction.md · ran by Claude Code, shown here as it completes
  7. claude{"type":"assistant", … {"type":"text","text":"No. The plugin never reads, stores or replays an OAuth token of its own …"}}
  8. claude{"type":"result","subtype":"success","is_error":false}
  9. opencodereplyNo. The claude CLI holds your login and does its own authenticating. The plugin never reads, stores or replays a token of its own: there is nothing in it to lift.
  1. opencodeyoutighten the deadline guard in the broker and run the suite
  2. claude{"type":"assistant", … {"type":"tool_use","name":"mcp__opencode_proxy__edit","input":{"filePath":"src/proxy-broker.ts", …}}}
  3. plugintool-calledit → opencode. Runs here, under your permission rules; the request is held open while it does.
  4. opencodeyou/btw why a guard instead of a longer deadline? · typed while the turn is still running
  5. pluginside_question{"type":"control_request","request":{"subtype":"side_question", …}} → the same live process, same model and account, concurrent with the turn. The aside never enters Claude's transcript.
  6. opencodereceipt▌ btw: why a guard instead of a longer deadline? ▌ sent to Claude on the side
  7. claude{"type":"control_response","response":{"response":{"response":"A fixed deadline would count the operator's time on a permission prompt …"}}}
  8. opencodereply▌ btw: a deadline would count your time on a permission prompt. The guard keeps the call while opencode still reports it busy, re-checking on an interval, and lets the deadline end it only once it does not. · written into the reply you are watching; the turn goes on below it

Project numbers

  • 85GitHub starsapi.github.com
  • 8,268npm downloads, last 30 daysapi.npmjs.org
  • 25,212npm downloads since 2026-04-25api.npmjs.org
  • 1,083tests in the suitenpm test, this build
  • 109tagged releasesapi.github.com
  • 16contributorsapi.github.com
  • 25forksapi.github.com
  • 18Claude models registeredsrc/models.ts

Read at build time from the GitHub REST API and api.npmjs.org; nothing is requested from your browser. Rebuilt daily. This build: .

01how it works

Two processes. One of them is the official client.

opencode spawns the real claude binary headless and talks to it over stream-json. The tools that touch your machine come back to opencode over a loopback MCP server the plugin runs in-process. Nothing in between holds a credential.

process 1opencode

Your terminal. Its permission prompts, its audit log, its MCP servers, its skills. The tools that touch your machine run here: bash, edit, write, webfetch,task.

in-processthe plugin

  • One claude child per conversation, keyed on cwd, model, tool scope and session.
  • opencode_proxy: an MCP server on loopback. Bearer token, written into a 0600--mcp-config, never logged.
  • One provider per account, each with its own CLAUDE_CONFIG_DIR.
  • Reads no credential. There is nothing here to lift.
  1. your prompt, as stream-json on stdin
  2. frames on stdout: text, thinking, tool_use, result
  3. a proxied tool call over loopback HTTP, held open until it ends
  4. its result, once opencode has run it

process 2claude --print

The official client, headless. It authenticates itself, talks to Anthropic itself, and bills as its own login bills.

  • Its own tools stay its own: Read, Grep, Glob, WebSearch.
  • Your opencode MCP servers, bridged in through --mcp-config.
  • Your opencode skills, staged for its Skill tool with --plugin-dir.
  • Your login, which the plugin never reads.

Anthropic. A subscription, an API key, Bedrock or Vertex: whatever the CLI holds. The plugin never talks to it.

How a turn worksHow a proxied call endsScratch files and security

02what it does

One claude process per conversation, with opencode in charge of the machine.

The plugin streams the CLI's output into opencode as it arrives, routes the tools that touch your files and shell back to opencode, and keeps the conversation's own claude process alive between turns so the model keeps its context.

  1. 01auth

    Your CLI's login, untouched

    The official claude binary authenticates: a subscription login, an API key, Bedrock or Vertex. The plugin never reads, stores or replays a token, so there is nothing here to lift.

    Which login bills what
  2. 02tools

    opencode runs the tools

    Bash, Edit, Write, WebFetch and Task are proxied by default. Claude calls an in-process MCP tool and opencode executes it, behind its own permission prompts and audit log.

    "proxyTools": ["Bash", "Edit", "Write", "WebFetch", "Task"]Read more
  3. 03claude

    Claude's own tools, MCP servers and skills

    Read, Grep, Glob and WebSearch run inside Claude Code. opencode's MCP servers are bridged into the spawn, and opencode's skills can be staged for Claude's native Skill tool.

    Read more
  4. 04accounts

    Several accounts, with failover

    Declare accounts once and each becomes its own provider with its own CLAUDE_CONFIG_DIR. When one runs out of usage mid-task, opencode's question form offers the others. Nothing moves until you pick.

    "accounts": ["personal", "work"]Read more
  5. 05subagents

    Your account, their model

    An agent file can pin forceModel, reasoningEffort and cacheTtl while inheriting the caller's account. task_batch dispatches several subagents at once, because the CLI serialises MCP calls.

    forceModel: claude-haiku-4-5Read more
  6. 06hosts

    One package, opencode 1.x and 2.x

    The default export carries both entrypoints and the same config works on both majors. opencode 2's tool vocabulary (shell, subagent) is translated per model, never process-wide.

    Read more
  7. 07skill

    Ships the skill that configures it

    Ask Claude to set it up. The package bundles a claude-code-plugin skill that knows every option, env var, model id and troubleshooting rule, staged into Claude Code on every spawn and kept in step with the code by tests.

    use the claude-code-plugin skill to add a work accountRead more
  8. 08doctor

    A health report safe to paste

    /claude-code-doctor reports versions, live processes, pending calls and what the CLI skipped. Its bundle form redacts by allowlist: nothing survives unless the plugin can name it, so a bug report never carries a prompt or a key.

    /claude-code-doctor bundleRead more
  9. 09cache

    Forks keep the cache warm

    forkSessions forks the Claude session instead of replaying the transcript. Measured on a fork's first turn: 814 prompt-cache writes against 22,355, 27x fewer, and the parent untouched.

    "forkSessions": trueRead more

Also in the box: /btw side questions on the live process, a read-only permission preset, 18 registered models with reasoning variants and fast mode, background subagents with status and cancel, and a fallback model chain.

03why the CLI and not the API

The three objections, answered with what is measured.

Just use the API.

The API is pay as you go on a Platform key. This plugin inherits whatever the claude CLI already holds, so a subscription login runs on the plan's usage limits, and an API key, Bedrock or Vertex login bills exactly as that CLI would. The CLI reports which one is in effect on every session (apiKeySource), and the plugin warns when a stray ANTHROPIC_API_KEY would move the bill.

Billing: what a turn draws from
Is this allowed? How is it billed?

The official client does the authenticating, and driving claude is what claude is for. Proxy and token-reuse plugins lift the OAuth session out of the client, which Anthropic disallowed for third-party use in February 2026; this plugin cannot do that, structurally. Headless --print usage on a subscription draws from the plan's ordinary limits, per Anthropic's own page, which the docs link and date rather than paraphrase.

How this compares, with every claim sourced
A CLI wrapper must be flaky.

It is engineered like a transport, not a shell-out. An abort sends the CLI an interrupt. A proxied call ends on an event, never on a clock. Two watchdogs cover a child that is alive but wedged, and a child that dies without a result is an error, never a silent stop. The suite is 1,083 tests, a dozen of whose files drive a fake CLI through real turns, and every rule in AGENTS.md cites the measurement that produced it.

Internals: how a turn works

04quickstart

Three steps. The second one is a single line.

  1. Install and log in the Claude Code CLI. The plugin drives an existing claude; it does not bundle one.

    Terminal window
    claude --version # e.g. 2.1.284 (Claude Code)
    claude auth status # which account you are signed in as
    claude auth login # only if you are not signed in yet
  2. Add the package to opencode’s global config. That spec is the whole install: opencode resolves and caches plugin packages itself, so do not npm install it.

    ~/.config/opencode/opencode.json
    {
    "plugin": ["@khalilgharbaoui/opencode-claude-code-plugin"]
    }
  3. Quit opencode fully and relaunch. Plugins load once, at process start. The model picker now has a Claude Code (Default) provider with entries such as Claude Sonnet 5.5 (2×) and Claude Opus 5 (5×); the suffix is each model’s list price relative to Haiku.

Something missing from the picker? Troubleshooting is keyed on the first thing you see, and /claude-code-doctor in any session prints what the plugin thinks is happening without calling a model.

05built from measurements

Every rule was learned from a measurement, and says so.

The project's engineering file does not contain opinions. Each rule names the probe, the version and the number that produced it, and the test that keeps it true.

1,083tests, across 63 files

A dozen of those files drive a fake claude through a real turn: the stream parser, the proxy broker, the watchdogs, abort, respawn, account failover and the model fallback chain are exercised end to end, not mocked at the edge. Two runtime dependencies in total.

How the suite is built

measuredevery rule in AGENTS.md cites the evidence that produced it

A finish's usage is context occupancy to opencode, so its input side is the turn's LAST real API call, never result.usage, which sums every call: a 14-call turn at 180K real context reported 2,050,806 cache read and opencode auto-compacted.

AGENTS.md, Tools and streaming (h #g169). Kept true by test-context-usage.ts.

27×fewer prompt-cache writes on a forked claude session than on the replay it replaces: 814 against 22,355, one measured thread (h #g187)

Read the rulebook

16contributors, with authorship preserved

  • @khalilgharbaouimaintainer: built and runs the plugin, reviews and credits every contribution
  • @unixfoxthe first version, March 2026, and the idea it still runs on
  • @broskeestask_batch, the skill bridge, the usage fix that stopped early auto-compaction
  • @jknlsnper-tool proxy timeouts, subagent dispatch steering, the question proxy
  • @galvaniper-session working directory for opencode serve
  • @willmcginnisauthentication on the proxy MCP endpoint
  • @acastro2the opencode 2 tool-result name fix
  • @bangnh1opencode 2's MCP config layout and Code Mode proxying
Everyone, with what they built

06how this compares

Three ways to reach Claude from opencode. They are not interchangeable.

Where a cell names what another project does, the full comparison page quotes that project's own README.

opencode’s native anthropic provider This plugin Proxy and token-reuse plugins
Authentication An Anthropic Platform API key in opencode’s auth store. Whatever the official claude CLI holds: a subscription login, an API key, Bedrock or Vertex. No token is read, stored or replayed. The Claude OAuth session, lifted out of the official client and refreshed by the plugin itself.
What is billed Pay as you go on the key’s Platform account. Whatever the CLI’s own login bills: plan usage limits on a subscription, pay as you go on a key. The CLI’s apiKeySource says which, on every session. The subscription the reused session belongs to.
Terms of service The ordinary API route. Nothing unusual about it. Sanctioned: the official client does the authenticating, and driving claude is what claude is for. Disallowed. Anthropic disallowed reusing subscription authentication for third-party Claude use in February 2026, and each of those projects carries its own disclaimer.
Who runs Bash, Edit, Write opencode, behind its permission prompts. opencode, behind its permission prompts: those tools are proxied by default. Read, Grep and Glob run inside Claude Code. opencode.
Claude Code’s tools, MCP servers, skills Not involved: opencode’s own tools only. Claude’s built-ins run in Claude Code, opencode’s MCP servers are bridged in, opencode’s skills can be staged for Claude’s Skill tool. Not involved: the model call is an ordinary API call.
What it costs you Baseline. A claude child per conversation (about 250 MB idle) under a cap of 16, a local keyword title instead of a model-written one, and Claude Code’s own compaction happening behind opencode’s back. One more moving part between you and Anthropic, plus the account risk in the terms row.

The full comparison has nine rows, names the projects in the third column, and links the policy sources with the date they were last read.

07add it

One line in opencode.json.

~/.config/opencode/opencode.json
{
"plugin": ["@khalilgharbaoui/opencode-claude-code-plugin"]
}

08the work, and the ask

Built in the open, one measurement at a time.

These are the numbers behind the plugin, read from the repository and the registries when this page was built. People support effort they can see.

  • 201days since the first commit, 2026-03-16git log, this build
  • 458commitsgit rev-list, this build
  • 109tagged releasesapi.github.com
  • 55merged pull requestsapi.github.com
  • 1,083tests in the suitenpm test, this build
  • 27,200lines of test code, in 63 filestest-*.ts, this build
  • 16contributors, authorship preservedapi.github.com
  • 25,212npm downloads since 2026-04-25api.npmjs.org

Free, MIT, and built in the open since 2026-03-16. Every rule in its engineering file names the measurement that produced it. If the plugin saves you time, buy its maintainer a coffee, or leave a star so the next person finds it.

Free and MIT-licensed, made by @khalilgharbaoui. If the plugin saves you time, you can buy its maintainer a coffee.

Buy me a coffee