Claude Code
Anthropic's terminal coding agent. It speaks the Messages API, and runs its own tools.
Plugboard options
One app for Claude Code, and aliases for the tiers it uses:
"options": {
"keys": { "claude-code": "{env:PLUGBOARD_KEY_CLAUDE_CODE}" },
"models": ["anthropic/claude-haiku-4-5", "anthropic/claude-sonnet-4-6"],
"aliases": {
"fast": "anthropic/claude-haiku-4-5",
"smart": "anthropic/claude-sonnet-4-6"
}
}Any model works, not only Claude: point the aliases at whatever your OpenCode server is signed in to.
Connect
export ANTHROPIC_BASE_URL="http://127.0.0.1:4010"
export ANTHROPIC_AUTH_TOKEN="$PLUGBOARD_KEY_CLAUDE_CODE"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="fast"
export ANTHROPIC_DEFAULT_SONNET_MODEL="smart"
export ANTHROPIC_DEFAULT_OPUS_MODEL="smart"
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1Then run claude.
- The base URL has no
/v1; Claude Code adds/v1/messages. - Set all three
ANTHROPIC_DEFAULT_*_MODELvariables. The haiku tier also runs background calls (titles, summaries), and a name plugboard doesn't serve fails them with 404.
To keep the settings, put the same variables under env in ~/.claude/settings.json and chmod 600 the file, since it then holds the key :
{
"env": {
"ANTHROPIC_BASE_URL": "http://127.0.0.1:4010",
"ANTHROPIC_AUTH_TOKEN": "<your app key>",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "fast",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "smart",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "smart",
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1"
}
}For a script or CI, run Claude Code headless with claude -p. This is the call the example's runner makes:
/**
* The variables a plugboard setup needs, plus the ones that keep a scripted run quiet: no telemetry, error reports, updates or
* other traffic that is not a model call. ANTHROPIC_BASE_URL has no /v1, because Claude Code adds `/v1/messages`.
*/
const connect = (baseUrl: string, key: string) => ({
ANTHROPIC_BASE_URL: baseUrl,
ANTHROPIC_AUTH_TOKEN: key,
ANTHROPIC_DEFAULT_HAIKU_MODEL: "fast",
ANTHROPIC_DEFAULT_SONNET_MODEL: "fast",
ANTHROPIC_DEFAULT_OPUS_MODEL: "fast",
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: "1",
DISABLE_TELEMETRY: "1",
DISABLE_ERROR_REPORTING: "1",
DISABLE_AUTOUPDATER: "1",
})
/** `claude -p`: one prompt, no questions. `--allowedTools` answers the permission prompts a headless run cannot. */
const headless = (prompt: string, model = "fast") => ["-p", prompt, "--model", model, "--allowedTools", "Write,Read,Agent", "--output-format", "stream-json", "--verbose"]--allowedToolsapproves the tools a headless run cannot ask about. Add the ones your prompt needs.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC,DISABLE_TELEMETRY,DISABLE_ERROR_REPORTINGandDISABLE_AUTOUPDATERturn off the calls that are not model calls: telemetry, error reports and update checks.- Give the script its own
HOMEandCLAUDE_CONFIG_DIR, so it reads no~/.claudesettings and writes no session there.
All three files are in examples/claude-code/.
What works
Streaming, Claude Code's tools (returned to it as tool_use blocks, several in a row), sub-agents (each sub-agent makes its own /v1/messages call), compaction (/compact and auto-compaction ask the model for a summary and continue from it), extended thinking on models with a matching variant, structured outputs and token counting.
Limits
- Claude Code sends its built-in tools plus every tool of each MCP server. Requests over
maxTools(default 64) are refused with 400; raisemaxToolsif you add MCP servers. - For a non-Claude model, Claude Code prints
claude-code:unrecognized_modeland assumes a 200k context. SetCLAUDE_CODE_MAX_CONTEXT_TOKENSto the real window. - Anthropic server tools (
web_search,code_execution) are refused with 400. - WebFetch checks each domain with
api.anthropic.com; turn that off withskipWebFetchPreflight: true.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1turns off Claude Code's other calls to Anthropic. Chat through plugboard works either way.