5.5 KiB
Claude Code CLI provider
OpenHuman can route any chat workload through Anthropic's claude CLI instead of calling the Anthropic HTTP API directly. The CLI handles model selection, auth, and prompt-cache management; OpenHuman drives it as a child process per turn, parses its stream-json output, and re-exposes its own read-only tools back into the CLI over MCP so the model can reach native OpenHuman state (memory, threads, channels, people).
Locked decisions live in
.planning/claude-code-provider/PLAN.md§13.
Requirements
- Claude Code CLI ≥ 2.0.0 on
PATH(orOPENHUMAN_CLAUDE_CLI=/abs/path/to/claude). - An Anthropic API key in
ANTHROPIC_API_KEY, or a pre-existing~/.claude/.credentials.jsonfromclaude login. - The
openhuman-corebinary on disk — OpenHuman spawnsopenhuman-core mcpas a stdio MCP server so the CLI can call OpenHuman tools. The path is discovered viastd::env::current_exe().
Routing a workload through the CLI
The factory grammar accepts a new prefix: claude-code:<model>[@<temperature>]. Apply it via the standard inference settings (per-role, locked decision #3):
# Through the JSON-RPC update endpoint:
openhuman-core rpc openhuman.inference_update_model_settings \
--json '{"chat_provider":"claude-code:claude-sonnet-4-5"}'
| Role string | Field updated |
|---|---|
chat_provider |
foreground chat replies |
reasoning_provider |
long-context reasoning workloads |
agentic_provider |
multi-step agentic loops |
A workload set to claude-code:<model> always spawns a fresh claude child per turn; concurrency is capped at MAX_CONCURRENT_TURNS = 4 per ClaudeCodeProvider instance.
Verifying the install
The status RPC is on the existing inference namespace:
openhuman-core rpc openhuman.inference_claude_code_status
Returns one of (CliStatus in src/openhuman/inference/provider/claude_code/types.rs):
{"status":"ok","version":"2.0.4","path":"/usr/local/bin/claude"}— ready{"status":"not_installed"}—claudenot onPATH{"status":"outdated","version":"1.9.0","min_required":"2.0.0","path":"…"}— bump CLI{"status":"unusable","path":"…","reason":"…"}— binary present but the version probe failed
The same status is rendered in the settings panel via ClaudeCodeStatusCard (app/src/components/settings/panels/ai/ClaudeCodeStatusCard.tsx).
Per-turn behavior
Each chat turn:
- Resolve a per-thread CC session UUID from
<workspace>/claude-code-sessions.json. New threads get a fresh RFC-4122 v4 UUID; the CLI requires v4 specifically for--resume. - Write
mcp-config.jsonto a tempdir pointing atopenhuman-core mcp(stdio MCP server, no extra credentials). - Spawn the CLI with:
-p --input-format stream-json --output-format stream-json --verbose --include-partial-messages--mcp-config <tmp> --strict-mcp-configso only the configured MCP servers are visible--disallowedTools Bash,Read,Write,Edit,Glob,Grep,WebFetch,WebSearch,TodoWrite,Task,BashOutput,KillShell— CC's own builtins stay off so OpenHuman tools (mcp__openhuman__*) are authoritative--session-id <uuid>on first turn,--resume <uuid>thereafter--model <model>(the suffix afterclaude-code:)--append-system-prompt <…>if the conversation carries a system message
- Pipe stdin: full conversation history on a new session, just the last user turn on
--resume(the CLI already holds its own prior-turn context server-side). - Stream stdout through the JSONL parser → event mapper →
ProviderDeltas on the request'sstreamsink.
On exit non-zero the driver bubbles stderr (capped at 16 KiB) up as the error message.
Auth resolution order
ANTHROPIC_API_KEYenv var (highest precedence — set on the spawned child).- Per-thread / per-agent key from
ChatRequestconfig (future, not yet wired). ~/.claude/.credentials.json— the CLI's own OAuth tokens fromclaude login(Pro / Max subscription). We never read or round-trip the access token; auth detection probes this file for non-secret metadata only.- None — the CLI will fail with an auth error.
The openhuman.inference_claude_code_auth_status RPC probes sources 1 and 3 without spawning the CLI and surfaces the result in the Settings → AI panel.
Tool surface exposed to the CLI
The CLI sees these tools as mcp__openhuman__<name> (delivered by the existing stdio MCP server in src/openhuman/mcp_server/):
core.list_tools,core.tool_instructionsmemory.search,memory.recalltree.read_chunk,tree.browse,tree.top_entities,tree.list_sourcesagent.list_subagents,agent.run_subagent(write — flaggeddestructiveHintper MCP spec)searxng_search
The MCP server enforces SecurityPolicy::ToolOperation checks; all tools except agent.run_subagent are read-only.
Limitations (v1)
- Vision input is not forwarded — set the
vision_providerto a different provider when you need images. agenticruns share the sameSemaphore(4); under load a CC turn waits in queue rather than failing fast.- Cost accounting from the CLI's
result.total_cost_usdis captured in the mapper but not yet wired into OpenHuman's billing layer (src/openhuman/cost/).