Files
claude-max-bridge/README.md
T

5.2 KiB

claude-max-bridge

A small FastAPI server that exposes an OpenAI-compatible /v1/chat/completions endpoint and translates each request into a claude CLI subprocess call. This lets LiteLLM (or any OpenAI-compatible client) consume a Claude Max subscription through the locally-installed claude binary without needing an Anthropic API key.

How it works

  1. Client sends an OpenAI chat-completions request (streaming or non-streaming).
  2. The bridge extracts the system prompt and conversation turns.
  3. It spawns claude --print --output-format stream-json --input-format stream-json ... and pipes the conversation as NDJSON to stdin.
  4. It parses the NDJSON stdout, computes text deltas from partial assistant messages, and re-emits them as OpenAI SSE chunks (or buffers for non-streaming).
  5. Usage totals and cost from the result event are forwarded in the response.

Authentication is handled entirely by the claude binary; the bridge bind-mounts the existing ~/.claude credentials directory (rw, so the CLI can refresh expired OAuth tokens automatically).

Environment variables

Variable Default Description
CLAUDE_BIN /usr/local/bin/claude Path to the claude CLI binary
CLAUDE_HOME /root/.claude Path to the Claude config / credentials directory
LOG_LEVEL INFO Python logging level
REQUEST_TIMEOUT_S 120 Per-request subprocess timeout in seconds

Running with Docker

docker build -t claude-max-bridge .

docker run -d \
  --name claude-max-bridge \
  -p 8000:8000 \
  -v /usr/local/bin/claude:/usr/local/bin/claude:ro \
  -v /root/.claude:/root/.claude:rw \
  -v /root/.claude.json:/root/.claude.json:rw \
  claude-max-bridge

Supported models

  • claude-sonnet-4-6 (default fallback)
  • claude-opus-4-7
  • claude-haiku-4-5
  • claude-opus-4-5
  • claude-opus-4-0
  • claude-sonnet-3-7
  • claude-haiku-3-5
  • Short aliases: sonnet, opus, haiku

Unknown model names fall back to claude-sonnet-4-6.

Extended parameters (extra_body)

The bridge maps several CLI flags via the extra_body field:

extra_body key CLI flag Notes
effort --effort <level> low/medium/high/xhigh/max. Overrides temperature mapping.
fallback_model --fallback-model <model> Model used when primary hits rate limit
system_prompt_mode --system-prompt / --append-system-prompt "replace" (default) or "append"
max_turns --max-turns <n> Cap agentic turns (non-interactive)
max_budget_usd --max-budget-usd <amount> Per-request cost cap
json_schema --json-schema <schema> Structured JSON output
exclude_dynamic_system_prompt_sections --exclude-dynamic-system-prompt-sections Better cache reuse for multi-user

temperature is also mapped to --effort when no explicit effort is set: <0.2→low, <0.4→medium, <0.7→high, <0.9→xhigh, ≥0.9→max.

response_format.json_schema (OpenAI standard) is also recognised and forwarded to --json-schema automatically.

Response extensions

Non-streaming responses and streaming done-chunks include:

Field Description
x_claude_cost_usd Actual cost as reported by CLI (total_cost_usd). $0 for Max subscription.
x_claude_rate_limit Rate-limit info: utilization, resetsAt, rateLimitType

LiteLLM configuration

model_list:
  - model_name: claude-sonnet-4-6
    litellm_params:
      model: openai/claude-sonnet-4-6
      api_base: http://claude-max-bridge:8000/v1
      api_key: "unused"
      stream_timeout: 120
      timeout: 120
      input_cost_per_token: 0.000003    # for dashboard visibility; actual cost $0
      output_cost_per_token: 0.000015

Endpoints

Method Path Description
GET /health Liveness check, always returns 200 OK
GET /v1/models Lists supported models
POST /v1/chat/completions OpenAI-compatible chat completions

Notes

  • Rate-limit responses from the CLI are translated to HTTP 429.
  • Auth errors are translated to HTTP 401.
  • The subprocess is killed on client disconnect or timeout.
  • top_p, frequency_penalty, presence_penalty, seed, stop, n are ignored.
  • MCP servers are explicitly disabled (--mcp-config '{"mcpServers":{}}' --strict-mcp-config) to prevent credential leakage and side-effects.