deepclaude
// repo overview

Claude Code CLI, swapped to a cheaper backend.

Wraps the CLI. Redirects model calls. Same agent loop.

Backends
DeepSeek · OpenRouter · Fireworks
Mechanism
env vars + optional proxy
Footprint
~440 LoC
Output cost
$0.87 vs. $15 / Mtok

01 / How it works

cmd = deepclaude proxy = none anthropic = 0 requests
Terminal $ deepclaude Claude Code CLI tool loop · edits · bash DeepSeek / OpenRouter / Fireworks Anthropic-compatible /v1/messages
env vars exported, then exec claude. no proxy. no anthropic traffic.
cmd = deepclaude + /deepseek · /anthropic proxy = 127.0.0.1:3200 switch = mid-session, no restart
Claude Code CLI /deepseek · /anthropic Local proxy 127.0.0.1:3200 POST /_proxy/mode GET /_proxy/status model remap · usage fix DeepSeek when mode=deepseek api.anthropic.com when mode=anthropic
proxy holds active backend; POST /_proxy/mode swaps it instantly.
cmd = deepclaude --remote proxy = required anthropic = yes (bridge transport)
Browser / phone claude.ai/code/… Anthropic bridge wss://bridge.claudeusercontent.com claude remote-control user's machine Local splitter proxy /v1/messages → DeepSeek DeepSeek inference WebSocket model calls
bridge stays on anthropic (OAuth); proxy diverts model calls. see ToS.

02 / Trade-offs

+ Gains

  • +
    Per-token cost

    $0.44 / $0.87 per Mtok vs. Anthropic's $3 / $15. Live ledger at /_proxy/cost.

  • +
    Same agent loop

    CLI binary unchanged. Tool loop, edits, bash, subagents — only the model endpoint moves.

  • +
    Mid-session backend switch

    One curl to /_proxy/mode flips backend without restart.

  • +
    No CLI patching

    Built on Anthropic's documented env vars. No binary modification, no reverse engineering.

− Considerations

  • Feature gaps

    No image input, no MCP server tools, no Anthropic cache_control.

  • Maintenance surface

    Proxy patches missing usage fields, thinking-block mismatches, OpenRouter path overlaps. Works today; tracks backend drift.

  • Data handling

    Code sent to third-party backends is governed by their terms. DeepSeek's API runs in mainland China.

  • Reasoning ceiling

    README: Opus still stronger on complex reasoning. --backend anthropic is the escape hatch.

03 / Terms-of-service alignment

Per-mode read against Anthropic's published docs · May 2026.

verdict

Direct and live-toggle modes are not addressed by Anthropic's docs in either direction. The ANTHROPIC_BASE_URL mechanism is documented only for gateways fronting Anthropic / Bedrock / Vertex / Foundry — all of which serve Claude.

Remote control with a non-Anthropic backend matches a configuration Anthropic's docs describe as not permitted (see quotes below).

ModeHits AnthropicReading
Direct, non-Anthropic backend No Not addressed by Anthropic's docs. "Third-party providers" in their docs means Bedrock / Vertex / Foundry — all serving Claude.
Direct, Anthropic backend Yes Ordinary Claude Code use.
Live toggle (mixed session) Yes, in Anthropic turns Anthropic turns are ordinary use; non-Anthropic turns inherit the row above.
Remote control + non-Anthropic backend Yes (bridge) Outside the documented permitted use. See quotes.

OAuth authentication is intended exclusively for purchasers of Claude Free, Pro, Max, Team, and Enterprise subscription plans and is designed to support ordinary use of Claude Code and other native Anthropic applications… Anthropic does not permit third-party developers to offer Claude.ai login or to route requests through Free, Pro, or Max plan credentials on behalf of their users. code.claude.com/docs/en/legal-and-compliance

"Remote Control is not yet enabled for your account" — The eligibility check can fail with certain environment variables present: CLAUDE_CODE_USE_BEDROCK, CLAUDE_CODE_USE_VERTEX, or CLAUDE_CODE_USE_FOUNDRY: Remote Control requires claude.ai authentication and does not work with third-party providers. code.claude.com/docs/en/remote-control

Anthropic blocks the analogous case for Bedrock / Vertex / Foundry at the eligibility check. deepclaude --remote uses a different env var so isn't caught, but the structural arrangement — claude.ai-OAuth bridge fronting a third-party model — matches what the docs describe as not permitted.

On the direct path: the third-party-model ecosystem (vLLM, Ollama, LM Studio, OpenRouter, Poe) routinely uses ANTHROPIC_BASE_URL this way, and Anthropic has not publicly objected as of May 2026. The use is unaddressed rather than approved. Anything past personal use warrants a direct read by counsel.

04 / Technical deep dive

Source: proxy/model-proxy.js · deepclaude.sh

Model-name remappingMODEL_REMAP

Claude Code can still emit literal strings like claude-opus-4-7. The proxy JSON-parses the outbound body and rewrites parsed.model per a backend table before forwarding.

Thinking-block scrubbingstripAll / stripUnsigned

Backends disagree on echoed type: "thinking" blocks. Three rules:

Non-Anthropic backend — strip all (foreign blocks rejected).
Anthropic after a foreign turn — strip all (signed-but-invalid blocks cause 400s).
Anthropic, never switched — strip only unsigned.

Fix landed in commit 70518b6.

Usage-field normalizationUsageNormalizer

Claude Code crashes if usage.input_tokens / output_tokens are missing. The SSE transform injects zeros into message_start / message_delta when absent, and samples real values for the cost ledger. Same fix for JSON responses.

Path-overlap fix for OpenRouterlines 285–288

Base /api/v1 + request /v1/messages would naively concat to /api/v1/v1/messages. The proxy strips the common overlap.

Auth-header rewritingx-api-key vs. Bearer

Inbound auth headers stripped, re-added per backend: x-api-key for DeepSeek/Anthropic, Bearer for OpenRouter/Fireworks.

Control plane /_proxy/*status · cost · mode

GET /status — mode, uptime, count.
GET /cost — per-backend tokens, actual cost, Anthropic-equivalent.
POST /mode — flip backend. Origin-locked to 127.0.0.1; body ≤ 1 KB.

Remote-control traffic splitproxy/README.md

Bridge stays on Anthropic OAuth; the proxy only diverts the HTTP model channel. Setting ANTHROPIC_AUTH_TOKEN to a non-Anthropic key would break the bridge.

Port-huntingtryListen

Tries 3200, walks up to 3219 on EADDRINUSE, prints the chosen port.