DeepSeek Everywhere: Wiring a Cheap Cloud Brain Into Claude Code and a Local Agent Stack
- Category
- AI & Local LLM
- Posted
- July 11, 2026
- By
- Jacob Lloyd β written with AI assistance, post-project
- Read time
- 8 min read
In plain terms: A guide to plugging DeepSeek β a very cheap cloud AI service β into your existing AI tools instead of paying for pricier options. It shows three ready-to-copy setups, including one that keeps your secret access key safely hidden. You get capable AI assistance for fractions of a cent per message.
DeepSeek now backs three different things in my house: 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.
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. I run OpenClaw, an agent gateway, with eight named agents behind a chat UI, plus the Claude Code CLI those agents spawn for real coding work. DeepSeek backs both.
| Pattern | What it does | Cost |
|---|---|---|
| 1. Agent brain | DeepSeek 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 backend | A systemd drop-in re-points the CLI at DeepSeek's Anthropic-compatible endpoint, no reinstall | same per-token pricing |
| 3. Fallback ladder | A 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:
My actual roster. Most agents lead with DeepSeek and fall back to local; Doxy runs the inverse on purpose:
| Agent | Primary | Fallbacks |
|---|---|---|
| Bits (main chat) | DeepSeek flash | DeepSeek pro β local gemma-4-31b |
| Brains | DeepSeek pro | local gemma-4-31b |
| Flash | DeepSeek flash | DeepSeek pro β local |
| Hermes (deploy agent) | DeepSeek pro | DeepSeek flash β local |
| Alpha (family-safe) | DeepSeek flash | DeepSeek pro β local |
| Doxy (local workhorse) | local 120B | DeepSeek flash (inverse β local leads) |
| beta | local | DeepSeek flash β DeepSeek pro |
| Charley (vision) | local gemma-31b | DeepSeek pro β DeepSeek flash |
Charley 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": trueis mandatory for reasoning models. They streamreasoning_contentbefore 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. Mine is 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 (~/.openclaw/gateway.systemd.env, 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.
More gotchas from actually running this:
- Set both auth vars. Different CLI versions read
ANTHROPIC_AUTH_TOKENorANTHROPIC_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
ExecStartmeans regenerating the drop-in. My generator reads the canonical command from the unit'sFragmentPathand 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):
| Option | Input | Output | Notes |
|---|---|---|---|
| DeepSeek flash | $0.14 | $0.28 | cache read $0.0028 β chat-agent duty costs pennies a day |
| DeepSeek pro | $0.435 | $0.87 | the "thinking" tier, still 7β17x cheaper than Sonnet |
| Local (same box) | $0 | $0 | electricity 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.
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.allownever 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.