@otto-assistant/opencode-claudeClaude Code in OpenCode — subscription OAuth, Agent SDK harness, effort variants, tools/MCP, images & compact.
0
1,499
213 in 7 days
39.5
Multi-signal model
7 days ago
2026-08-12
Install and configure
opencode.jsonWrites to this project's opencode.json — applies to this repository only.
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@otto-assistant/opencode-claude@0.10.0"]
}Writes to ~/.config/opencode/opencode.json — applies to every project.
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@otto-assistant/opencode-claude@0.10.0"]
}If you want to modify the plugin locally, install it into the project and reference the local path.
shell
pnpm add -D @otto-assistant/opencode-claudeopencode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.
Claude Code inside OpenCode — Pro/Max subscription OAuth,
Agent SDK harness, effort variants, tools, images, and compact.
Install · Authenticate · Why this plugin · Architecture · Changelog
Run Claude Code from your Claude Pro/Max subscription inside OpenCode: Fable, Opus, Sonnet, Haiku — with thinking effort low→max, streaming, OpenCode tool calls that park and resume, MCP, image/PDF attachments, and auto-compact.
Uses the same Agent SDK + claude CLI stack as the OpenChamber Claude harness. Plugin shape mirrors @otto-assistant/opencode-cursor.
Install
claude-code is not a built-in OpenCode provider. Install the plugin first, or
opencode auth login --provider claude-code fails with Unknown provider "claude-code".
# global (recommended)
opencode plugin @otto-assistant/opencode-claude -g
# or project-local (writes .opencode/opencode.json)
opencode plugin @otto-assistant/opencode-claude
Optional provider naming (also seeded when the plugin loads):
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@otto-assistant/opencode-claude"],
"provider": {
"claude-code": { "name": "Claude Code" }
}
}
Or build from source:
git clone https://github.com/otto-assistant/opencode-claude.git
cd opencode-claude
bun install && bun run build
opencode plugin file://$PWD
Authenticate
Requires the plugin to be installed (see above).
# Option A — sync from Claude Code CLI (recommended)
claude auth login
opencode auth login --provider claude-code
# pick "Use Claude Code CLI login"
# Option B — browser OAuth (Pro/Max)
opencode auth login --provider claude-code
# pick "Login with Claude Pro/Max"
Then start OpenCode, pick provider claude-code, choose a model, and set the
effort variant (low / medium / high / xhigh / max) when you want
deeper thinking.
opencode run "Summarise this repository in five bullets." --model claude-code/sonnet
Why this plugin
| Agent SDK harness | Runs Claude through @anthropic-ai/claude-agent-sdk + the local claude CLI — same stack as OpenChamber. |
| Subscription auth | Claude Pro/Max OAuth (CLI sync or browser). API keys are stripped from the child env so billing stays on the subscription. |
| Effort / thinking | Native OpenCode variants low→max map to Claude --effort + adaptive thinking. |
| Agent-grade tools | OpenCode tools bridge as in-process MCP; calls park and resume instead of deadlocking or inventing output. |
| Attachments | Images and PDFs from OpenCode reach Claude (data URLs + remote URLs). |
| Auto-compact | Long sessions compact like Claude Code; boundary events are surfaced in the stream. |
| Session resume | Sticky foreign Claude session IDs so follow-ups continue the same Agent SDK turn. |
| History transfer | When no Claude session can be resumed (first claude-code turn of a chat, model switch mid-conversation, pruned transcript), the full prior conversation is serialized into the prompt — Claude never starts blind. |
| Rate-limit counter | Subscription limit state is tracked with its reset time; GET /v1/rate-limit answers "when are limits back", and doomed turns fail fast with 429 + Retry-After. |
Architecture
OpenCode
└─ /v1/chat/completions
└─ Bun.serve proxy (ephemeral port; published via auth loader)
└─ Claude Agent SDK query()
└─ claude CLI (subscription OAuth)
Model catalog: aliases fable / opus / sonnet / haiku plus pinned ids.
Effort selection is encoded in x-opencode-claude-effort so the proxy passes the
exact effort (+ adaptive thinking) into the Agent SDK.
Rate-limit counter
The proxy records Agent SDK rate_limit_event telemetry and hard session-limit
errors (including the parsed reset time) to
~/.local/share/opencode-claude/rate-limit.json.
GET /v1/rate-limit→{ limited, status, rateLimitType, utilization, resetsAt, resetsAtISO, resetInSeconds, message, updatedAt }— poll this for a "limits reset in …" countdown.utilizationis only present when the latest SDK event reported it — it is never carried over from an earlier limit window, so a freshly reset window never shows a stale percentage.GET /healthincludes a compactrateLimitsummary.- While a confirmed hard limit is active, new chat turns return HTTP 429
with
Retry-After+x-claude-rate-limit-resetheaders and anerror.type = "rate_limit_error"body (title/summary meta requests are never gated). The block lifts automatically at reset time; the next turn then resumes the same Claude session (sticky session store is untouched). OPENCODE_CLAUDE_RATE_LIMIT_FAST_FAIL=0disables the 429 gate (turns are attempted and error normally).
Requirements
- OpenCode
- Claude Code CLI on
PATH - Claude Pro/Max subscription (or CLI OAuth credentials)
- Bun (plugin runtime) · Node.js ≥ 18
Development
bun install
bun run build
bun run test
Debug logging: OPENCODE_CLAUDE_DEBUG=1.
Optional knobs:
OPENCODE_CLAUDE_PROXY_PORT— optional pinned proxy port (default: ephemeral / OS-assigned; live URL is published to OpenCode via config + auth loader)OPENCODE_CLAUDE_CWD— working directory passed to the Agent SDKCLAUDE_CODE_OAUTH_TOKEN— inject a subscription token (CI / headless)OPENCODE_CLAUDE_RATE_LIMIT_FAST_FAIL—0disables the 429 rate-limit gateOPENCODE_CLAUDE_RATE_LIMIT_STORE— override the rate-limit store path (tests)OPENCODE_CLAUDE_HISTORY_MAX_CHARS— budget for transferred conversation history when a Claude session cannot be resumed (default400000; newest messages are kept,0disables transfer)
Release
Publish via GitHub Actions → Actions → Release → Run workflow:
| Input | Purpose |
|---|---|
version |
Explicit semver (0.6.0). Empty → use bump |
bump |
minor (default) / patch / major |
dry_run |
Skip npm publish; create a draft GitHub release |
Requires repo secrets: NPM_TOKEN, optional DISCORD_WEBHOOK_URL.
Local pin refresh after a release:
./scripts/update-plugin.sh --dry-run
./scripts/update-plugin.sh