ANTHROPIC_API_KEY in the encrypted vault, and reports its connection state. This page covers the bits specific to Claude Code; for the shared install/connect/disconnect lifecycle see Connecting runtimes.
Prerequisites
Node 22+ and
npm (bundled with Node); Claude Code installs via npm install -g. An Anthropic API key, or an existing local claude login (the SDK falls back to the logged-in CLI’s own auth when no key is in the vault). On an install from npm you also need @anthropic-ai/claude-agent-sdk installed alongside Clawboo — see step 3.- The Clawboo dashboard running (
clawboo). - A board task to run on, created via the board (you can also drive it directly with
POST /api/runtimes/claude-code/run).
Capabilities
The adapter declares itscapabilities() so the host routes the run by construction (it never branches on the runtime id). Claude Code’s are:
Because
runtimeClass is wrapped-oneshot and there is no nativeHome claim, the host provisions no persistent home for Claude Code. The SDK runs against your real HOME / Keychain auth; nothing native accrues per identity. (Contrast Hermes, which keeps a persistent home that compounds skills and memory across runs.)
Steps
1. Install the CLI
From the Runtimes panel, click Install on the Claude Code card. The card opens an SSE install stream that runs:@2) so a future major-incompatible publish is never auto-installed. The health binary the panel probes for is claude. If npm is missing the stream emits an error with code NPM_MISSING.
2. Connect your key
Click Connect on the card (from theneeds-auth state) and paste an Anthropic API key. The key is stored in the encrypted vault under ANTHROPIC_API_KEY and the card flips to ready. The connect response never echoes the key.
The equivalent REST call:
3. Install the Agent SDK (published installs)
Clawboo drives Claude Code through the Claude Agent SDK, which is a separate package from theclaude CLI installed in step 1. If you are running Clawboo from source (the monorepo), it is already there and you can skip this. If you installed Clawboo from npm, it is not: the published tarball deliberately does not declare it, because the SDK’s per-platform optional dependency is a ~210 MB claude binary that every install would otherwise download for a runtime most users never touch.
Install it alongside Clawboo so Node can resolve it from the server bundle:
ready (that reflects the claude binary plus your key), but a run fails immediately with a message naming the missing package and the command above.
4. Run a board task on it
With the runtimeready, dispatch a board task:
repoPath, spawns the Claude Agent SDK with the connected key injected into the child env, drives the SDK’s message stream as a normalized event stream, then writes the report-up summary and AGENT_HANDOFF.json. See the /api/runtimes/:id/run reference for the full request/response shape.
How the driver works
The pure adapter lives in@clawboo/adapter-claude-code; the real driver that talks to the SDK lives server-side in claudeCodeDriver.ts. They are split deliberately so the adapter stays dependency-light (its only dependency is @clawboo/executor) and contract-testable against an in-memory fake.
The SDK is lazy-imported, and optional
@anthropic-ai/claude-agent-sdk is not bundled into the shipped server and not required at boot. The driver imports it lazily, inside the run, through a helper that turns a resolution failure into the remediation above rather than a raw resolver error:
clawboo package, so an install from npm does not ship it — see Install the Agent SDK above. The reason is size: the SDK’s per-platform optional dependency is a ~210 MB claude binary, and npm installs optional dependencies by default, so declaring it would add that to every install for a runtime most users never touch. The clean-install gate treats it as a documented optional external for the same reason (OPTIONAL_EXTERNALS in scripts/lib/bundle-externals.mjs), and the driver turns Node’s bare Cannot find package into the instruction that fixes it rather than surfacing a resolver error as the run’s failure summary.
Message translation
For each run the driver builds the SDKquery() options from the run context: cwd (the worktree), model, resume, the MCP server config built from mcpBaseUrl, disallowedTools (the child tool blocklist), and a scrubbed child env with the provider key merged on top. It then translates each SDK message into the adapter’s ClaudeNativeEvent union, which the pure mapClaudeEvent maps into the normalized RuntimeEvent stream:
The system/init message carries the native session id and model; assistant content blocks become text (and thinking blocks become reasoning-channel text); tool_use blocks become tool-call; tool results become tool-result; and the terminal result message becomes a cost event plus a done (or error) event.
Real USD cost, passed through
Claude Code reports a realtotal_cost_usd per run. The mapper passes it straight through as a concrete costUsd on the cost and done events, not an estimate. (Contrast Codex, which emits no USD and is estimated.)
max_turns is a clean terminal, not an error
When a run hits its turn ceiling the SDK signals result.subtype === 'error_max_turns'. The driver surfaces this as a distinct maxTurns flag, and the mapper emits a done event with reason: 'max_turns', not an error. This is a clean “ran out of room” terminal. The host treats it as a rotation signal: it spins up a fresh successor session carrying a handoff note (not the heavy transcript) and continues, rather than failing the task. The 200k-token contextWindowTokens also drives a proactive watermark so the host can rotate before the window fills, bounded by maxRotations.
Session resume across runs
The adapter’ssessionCodec serializes the native Claude session id (captured from the init/result frames). On a later same-runtime run, the executor runner threads that id back into the run context, and the driver sets the SDK’s resume option, a genuine continuation of the prior session. A cross-runtime pickup (a different runtime resuming the task) rides the prose handoff in AGENT_HANDOFF.json instead.
Headless permissions
The run is a headless worker, so the driver setspermissionMode: 'bypassPermissions' and allowDangerouslySkipPermissions: true. This is safe because Clawboo gates risky tools externally (the board, approvals) and the run is confined to an isolated per-task worktree; the SDK requires the explicit opt-in alongside bypassPermissions. The driver also strips Clawboo’s own server secrets (gateway token, access-gate token, vault master key) from the child env before merging the provider key, so the spawned agent does not inherit them.
Verify it worked
- The Runtimes card reads
readyandGET /api/runtimesreports the Claude Code entry withconnectionState: "ready"andhealth.ok: true. For a CLI runtime,healthreflects whether theclaudebinary resolves on PATH or a known user-install dir. - After a
POST /api/runtimes/claude-code/run, the task advances on the board, the worktree carries the file changes plus anAGENT_HANDOFF.json, and the run’s report-up summary lands as a board comment.
Troubleshooting
POST /api/runtimes/claude-code/run returns 409. The task could not be atomically claimed; another worker won it. Per the board’s atomic-claim contract, a 409 is data, not a transient error: do not retry it. See the board.See also
- Connecting runtimes: install/connect/disconnect, the encrypted vault, healthchecks
- Runtimes overview: the full capability matrix across all five runtimes
/api/runtimesreference: request/response shapes for run, connect, install- Codex · Hermes · Clawboo Native: the other non-OpenClaw runtimes
- OpenClaw: the connected-substrate runtime (different model)
- The board:
taskId, atomic claim, the 409-no-retry contract