# DeepSeek Everywhere: Claude Code and a Local Agent Stack URL: https://www.laserlloyd.com/projects/deepseek-everywhere-claude-code-openclaw/ Published: 2026-07-11 Updated: 2026-09-16 Description: Three ways to wire DeepSeek's cloud API into a local agent stack and Claude Code CLI, plus the systemd trick that keeps API keys out of argv. Reuse: free for personal use — full policy at https://www.laserlloyd.com/llms.txt DeepSeek backed three different things in my house as of July 2026: the brains of my agent stack, the Claude Code CLI, and the cloud rung of a fallback ladder. Total wiring effort was some JSON, a few environment variables, and one systemd escaping bug that ate an evening. Update 2026-09-16: my agent stack has since been consolidated to six agents, and since late August 2026 the lead agent runs on MiniMax M3, with DeepSeek as the metered fallback. The eight-agent roster below describes the setup as it stood when this was written. The wiring is unchanged and is still how DeepSeek is plugged in. tl;dr What it is: DeepSeek's paid cloud API as the brain behind a multi-agent home stack and as a drop-in backend for the Claude Code CLI — not another "run it on your own GPU" guide. What it costs: fractions of a cent per message on the cheap tier. No subscription, just an API key. What you need: a DeepSeek API key, anything that speaks OpenAI-style chat completions, and systemd if you want the Claude Code trick. What you end up with: three copy-pasteable configs, a cloud-vs-local decision list, and a secret-handling trick that keeps the key out of ps, systemctl show, and your logs. What you end up with Before the how-to, the shape of the thing as I wired it in July. I ran OpenClaw, an agent gateway, with eight named agents behind a chat UI, plus the Claude Code CLI those agents spawned for real coding work. DeepSeek backed both. PatternWhat it doesCost 1. Agent brainDeepSeek as a provider in the gateway config; any agent can pick it as primary or fallback$0.14–$0.87 / million tokens 2. Claude Code backendA systemd drop-in re-points the CLI at DeepSeek's Anthropic-compatible endpoint, no reinstallsame per-token pricing 3. Fallback ladderA decision list for when a job goes to DeepSeek vs a local model$0 when it stays local The one line that makes all of it possible: DeepSeek ships an Anthropic-compatible endpoint at https://api.deepseek.com/anthropic. Anything built to talk to Claude — the Claude Code CLI included — can be pointed at it with nothing but environment variables. No wrapper script, no fork. Pattern 1: DeepSeek as an agent brain One provider block in the gateway config. Real thing, key redacted: "deepseek": { "baseUrl": "https://api.deepseek.com/v1", "api": "openai-completions", "apiKey": "CHANGE_ME", "timeoutSeconds": 450, "models": [ { "id": "deepseek-v4-pro", "name": "deepseek-v4-pro", "reasoning": true, "input": ["text"], "cost": { "input": 0.435, "output": 0.87, "cacheRead": 0.003625, "cacheWrite": 0.435 }, "contextWindow": 1000000, "maxTokens": 384000 }, { "id": "deepseek-v4-flash", "name": "deepseek-v4-flash", "reasoning": true, "input": ["text"], "cost": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0.14 }, "contextWindow": 1000000, "maxTokens": 384000 } ] } Each agent then picks a primary model and a fallback chain: "model": { "primary": "deepseek/deepseek-v4-flash", "fallbacks": ["deepseek/deepseek-v4-pro", "vllm/google/gemma-4-31b"] } Here's what happens when a message comes in on that routing: Chat UI user types a message Gateway localhost:18789, resolves agent DeepSeek flash agent's model.primary DeepSeek pro fallback #1, on error/timeout Local model fallback #2, LM Studio, $0 Answer streams back reasoning, then the reply HTTPS POST error/timeout still failing streamed reply My roster as of August 2026, by role. Most agents led with DeepSeek and fell back to local; the local workhorse ran the inverse on purpose: AgentPrimaryFallbacks Lead chat agentDeepSeek flashDeepSeek pro → local gemma-4-31b Reasoning agentDeepSeek prolocal gemma-4-31b Fast workerDeepSeek flashDeepSeek pro → local Deploy agentDeepSeek proDeepSeek flash → local Family-safe agentDeepSeek flashDeepSeek pro → local Local workhorselocal 120BDeepSeek flash (inverse — local leads) Second family-safe agentlocalDeepSeek flash → DeepSeek pro Vision agentlocal gemma-31bDeepSeek pro → DeepSeek flash The vision agent matters here: these DeepSeek entries are text-only ("input": ["text"]), so image work stays local no matter what the chain says. Aliases (ds-flash, ds-brain) let me swap models mid-conversation instead of editing config. Two settings will bite you if you skip them: "reasoning": true is mandatory for reasoning models. They stream reasoning_content before the actual answer; with the flag off, the gateway hears silence, decides the model stalled, and kills the turn around 390 seconds in. Ask me how I know. Raise timeoutSeconds. The default request timeout was 120 seconds; long reasoning runs blow past that and "fail" at random. 450 fixed it here, and provider settings hot-reload — no gateway restart. Pattern 2: Claude Code CLI on DeepSeek The Claude Code CLI reads ANTHROPIC_BASE_URL, ANTHROPIC_MODEL, and ANTHROPIC_AUTH_TOKEN/ANTHROPIC_API_KEY from its environment, and DeepSeek's /anthropic endpoint speaks the same wire format Claude does. So rerouting the CLI is just changing the environment the gateway hands each Claude Code subprocess it spawns — the CLI stays a stock install. The file is a systemd user drop-in. In July, mine was generated by a small GTK app I built that flips between four modes (Local LM Studio / DeepSeek / Anthropic Cloud / Off), but it's short enough to write by hand: # ~/.config/systemd/user/openclaw-gateway.service.d/60-subagent-routing.conf [Service] # Routes Claude Code CLI sub-processes to DeepSeek's Anthropic-compatible # endpoint. The key is NOT copied here: $$DEEPSEEK_API_KEY is systemd's escape # for a literal $DEEPSEEK_API_KEY, which bash expands at runtime from the # gateway EnvironmentFile -- the secret never enters the unit or the argv. Environment="ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic" Environment="ANTHROPIC_MODEL=deepseek-v4-pro" ExecStart= ExecStart=/usr/bin/bash -c 'export ANTHROPIC_AUTH_TOKEN="$$DEEPSEEK_API_KEY"; export ANTHROPIC_API_KEY="$$DEEPSEEK_API_KEY"; exec node /path/to/openclaw/dist/index.js gateway --port 18789' The key itself lives in exactly one place: the service's EnvironmentFile (a gateway-owned env file, chmod 600), which just contains DEEPSEEK_API_KEY=CHANGE_ME. The $$ gotcha (the whole reason this post exists) My first attempt used a single $. It did not go well. Inside a unit file, $VAR gets expanded by systemd itself at spawn time, which bakes the key straight into the command line — visible in ps, in /proc/<pid>/cmdline, and in systemctl show. Not exactly where you want a secret sitting. $$VAR is systemd's escape for a literal $VAR: systemd passes the string through untouched and bash expands it at runtime, from the environment the EnvironmentFile already populated. Net effect: the secret exists in one chmod-600 file and nowhere else — it never appears in the unit file, in systemctl show, or in any argv. A poor-man's secrets manager built out of systemd and bash, and it works. EnvironmentFile chmod 600, key lives here only bash ExecStart expands $$ → $DEEPSEEK_API_KEY HTTPS header x-api-key / ANTHROPIC_AUTH_TOKEN exec bypassed on purpose: unit file text, systemctl show, ps / proc argv, logs DeepSeek's /anthropic endpoint answers in Anthropic wire format → Claude Code CLI More gotchas from actually running this: Set both auth vars. Different CLI versions read ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY; setting only one is a coin flip. Pin ANTHROPIC_MODEL, or the CLI's usual sonnet/opus aliases get sent to DeepSeek's endpoint and 404. The drop-in shadows any real Anthropic key. One environment owns the whole CLI — I found out when it silently broke my "route to real Claude" aliases. Blank ExecStart= first — the empty line before the override — or systemd appends your command instead of replacing the original. Package updates can orphan the wrapper. It hard-codes the launch command, so an update that changes the real ExecStart means regenerating the drop-in. My generator reads the canonical command from the unit's FragmentPath and refuses to wrap anything already containing $$DEEPSEEK_API_KEY. Then reload: systemctl --user daemon-reload && systemctl --user restart <service>. To prove the whole path end to end, skip the CLI and curl it: curl https://api.deepseek.com/anthropic/v1/messages \ -H "x-api-key: $DEEPSEEK_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model":"deepseek-v4-pro","max_tokens":16,"messages":[{"role":"user","content":"ping"}]}' A "type":"message" response back means the whole Anthropic-compat path genuinely works. Pattern 3: when to actually use DeepSeek vs local Having both doesn't mean every job goes to the cloud. Per million tokens, with Claude's list prices for scale (Opus $5/$25, Sonnet $3/$15, Haiku $1/$5): OptionInputOutputNotes DeepSeek flash$0.14$0.28cache read $0.0028 — chat-agent duty costs pennies a day DeepSeek pro$0.435$0.87the "thinking" tier, still 7–17x cheaper than Sonnet Local (same box)$0$0electricity only Speed was the bigger surprise. Local 100B-class models forced me to raise turn timeouts to 20–30 minutes, and two agents sharing one GPU box stall each other. DeepSeek answers in seconds; the 450-second ceiling only ever mattered for worst-case reasoning runs. Context is the other gap — a 1M-token window against roughly 128k for the local models — so long agentic sessions and big-codebase coding jobs default to DeepSeek. Vision goes the opposite way: my DeepSeek entries are text-only, so "look at this picture" stays on a local vision model. The privacy rule of thumb I actually use: don't send the cloud anything you wouldn't put in an email. Personal or private data? yes → LOCAL Needs vision? yes → LOCAL vision model Internet or API down? yes → LOCAL fallback Long context / hard reasoning? yes → DeepSeek pro Everyday chat or agent glue? yes → DeepSeek flash Otherwise: free-tier busywork LOCAL workhorse, DeepSeek flash as backstop no no no no no to all of the above Fallback chains cut both ways, which is my favorite part. Cloud-primary agents drop to a local model when the internet or the API dies; the local-primary workhorse falls back to DeepSeek flash when the local server is busy or dead. Nobody goes fully dark. Gotchas, the short list The reasoning: true flag, the 120-second timeout, the $$ escape, and the drop-in shadowing your real Anthropic key are all covered inline in Patterns 1 and 2. Two more: A non-empty plugin allowlist is strict. In OpenClaw, an enabled provider entry that's missing from plugins.allow never loads. No error, no warning, just silence. DeepSeek here is text-only. Check "input" in the model entry before routing vision jobs at it. Want it fully local instead — no API key, no cloud bill? I wrote that one up too: DeepSeek: Running Locally — a 4-Step Guide, DeepSeek distills on your own GPU with Ollama, Docker, and Open WebUI. That's the beginner path; this one's for when the hard jobs outgrow your GPU but the private stuff still stays home. Related: the local AI agent stack this wiring runs inside, OpenClaw Model Manager (the GUI that writes the Claude Code drop-in), running DeepSeek fully locally, and setting up an LLM assistant.