Zero-Cost Opus: Running Claude Code on a Max Subscription Inside Kubernetes
Claude Opus 4.6 is $15/$75 per million tokens via API. Or $0 via my Max subscription. Here's how I wired it into my AI agent team.
Claude Opus 4.6 costs $15 per million input tokens and $75 per million output tokens via the Anthropic API. Through OpenRouter, it's roughly the same with a markup. Or it costs $0, if you route it through a Max subscription and Claude Code CLI running inside a Kubernetes pod. Here's how I wired it into my AI agent team.
The Problem: Reasoning Costs Money
I run a team of seven AI agents on OpenClaw in my homelab, a two-node Talos Linux cluster managed via Flux GitOps. The agents handle everything from research and writing to code reviews and security assessments. Most of their work runs through a model routing chain that defaults to Codex (GPT-5.3) via my ChatGPT Plus subscription. Zero marginal cost, good enough for 80% of tasks.
But "good enough" falls apart on complex coding work. Multi-file refactors across a Kubernetes repo. Architectural decisions that need to hold context across 20 files. Deep debugging where the model needs to reason about interactions between Cilium network policies, Flux reconciliation, and Longhorn volume affinity, all at once. For that, you need Opus-level reasoning.
I learned this the expensive way. I left the agents running overnight with OpenRouter as the fallback provider, Opus as the model. Woke up to a $100 bill. One night. The agents were doing good work. They'd refactored an entire subsystem, written tests, updated documentation. But at API rates, "good work" and "expensive work" are the same thing.
The Insight: You Already Have Unlimited Opus
Claude Max subscription: $200/month for unlimited Opus 4.6 usage. I was already paying for it. Claude Code CLI authenticates via OAuth against the subscription: no API key needed, no per-token billing. If Claude Code runs inside the container, any agent can shell out to it and get Opus responses at zero marginal cost.
The subscription has rate limits (concurrency, not volume), but for a homelab agent team doing serial coding tasks, that's irrelevant.
Installation
OpenClaw runs as a Node.js process inside a container, with a 5 Gi Longhorn PVC mounted at /home/node/.openclaw. Anything installed there persists across pod restarts. No need to bake it into the image.
# Exec into the pod
kubectl exec -it -n openclaw deploy/openclaw -c openclaw -- bash
# Install Claude Code globally on the PVC
cd /home/node/.openclaw
npm install @anthropic-ai/claude-code
# Verify
./node_modules/.bin/claude --versionAfter installation, the binary lives at /home/node/.openclaw/node_modules/.bin/claude and node_modules at /home/node/.openclaw/node_modules/@anthropic-ai/claude-code/. Both on persistent storage. The pod can restart without losing the installation.
I also symlinked the binary into a bin/ directory on the PVC for cleaner paths:
mkdir -p /home/node/.openclaw/bin
ln -s /home/node/.openclaw/node_modules/.bin/claude /home/node/.openclaw/bin/claudeAuthentication: OAuth Credentials from macOS Keychain
Claude Code authenticates via OAuth when backed by a subscription (not an API key). On macOS, it stores the credentials in the system Keychain. I needed to extract them and copy them into the pod.
# On macOS — extract the OAuth credentials
security find-generic-password -s "Claude Code-credentials" -w | python3 -c "
import sys, json
creds = json.loads(sys.stdin.read())
print(json.dumps(creds, indent=2))
" > /tmp/claude-credentials.jsonThen copy them to the PVC:
# Create a config directory on the PVC
kubectl exec -n openclaw deploy/openclaw -c openclaw -- \
mkdir -p /home/node/.openclaw/claude-config
# Copy credentials into the pod
kubectl cp /tmp/claude-credentials.json \
openclaw/$(kubectl get pod -n openclaw -l app=openclaw -o jsonpath='{.items[0].metadata.name}'):/home/node/.openclaw/claude-config/.credentials.json \
-c openclaw
# Clean up local copy
rm /tmp/claude-credentials.jsonThe credentials file contains an OAuth refresh token tied to the Max subscription. Claude Code uses it to obtain short-lived access tokens, same flow as when you run claude on your laptop.
Set the config directory via environment variable so Claude Code knows where to find them:
export CLAUDE_CONFIG_DIR=/home/node/.openclaw/claude-configThe ANTHROPIC_API_KEY Trap
This one cost me an hour. Claude Code checks for credentials in a specific order:
ANTHROPIC_API_KEYenvironment variable- OAuth credentials in
CLAUDE_CONFIG_DIR - Interactive OAuth login flow
My pod already had ANTHROPIC_API_KEY set. It was in the SOPS-encrypted secret, injected as an env var for direct Anthropic API calls (used by the agents' regular model routing). Claude Code found it first, used it for authentication, and burned through API credits instead of the subscription.
The fix: when spawning Claude Code, explicitly unset the API key or override the config directory so it falls through to OAuth:
# Option A: Unset the key for the subprocess
env -u ANTHROPIC_API_KEY CLAUDE_CONFIG_DIR=/home/node/.openclaw/claude-config \
/home/node/.openclaw/bin/claude -p "your prompt here"
# Option B: In the agent's spawn command
CLAUDE_CONFIG_DIR=/home/node/.openclaw/claude-config \
ANTHROPIC_API_KEY="" \
/home/node/.openclaw/bin/claude -p --model opus "your prompt here"Setting ANTHROPIC_API_KEY="" (empty string) also works: Claude Code treats it as unset and falls through to OAuth. I went with the explicit env -u approach because it's clearer about intent.
Integrating into the Agent Stack
OpenClaw agents delegate work to each other via sessions_spawn, a built-in mechanism that creates a new agent session and routes it through the configured model provider. That's how research tasks go to Petra (the researcher), writing goes to Margaux (the writer), and so on. All of those use the regular model routing chain: Codex by default, with fallbacks.
For Claude Code, I added a second delegation method: direct shell execution. The orchestrator agent (Henry) can spawn a Claude Code process, pass it a prompt, and get structured output back. No sessions, no model routing. Just a subprocess running against the Max subscription.
The key flags:
CLAUDE_CONFIG_DIR=/home/node/.openclaw/claude-config \
ANTHROPIC_API_KEY="" \
/home/node/.openclaw/bin/claude \
-p \ # Print mode (non-interactive)
--permission-mode bypassPermissions \ # No permission prompts
--model opus \ # Explicit model selection
"Refactor the network policy manifests to use a shared template"-pruns in print mode: no interactive TUI, just stdin/stdout--permission-mode bypassPermissionsprevents Claude Code from prompting for file access permissions (there's no terminal to answer them)--model opusexplicitly selects Opus 4.6
The Routing Table
I updated the orchestrator's routing logic with clear decision criteria:
| Task Type | Method | Model | Cost |
|---|---|---|---|
| Simple code changes | sessions_spawn (Kit) | Codex (GPT-5.3) | $0 (ChatGPT Plus) |
| Complex code / architecture | Claude Code (bash) | Opus 4.6 | $0 (Claude Max) |
| Research / investigation | sessions_spawn (Petra) | Codex | $0 |
| Writing / content | sessions_spawn (Margaux) | Codex | $0 |
| Security review | sessions_spawn (Thane) | Codex | $0 |
| Social media | sessions_spawn (Ivy) | Codex | $0 |
| Direct API fallback | OpenRouter | Cheapest available | $$$ |
The heuristic is straightforward: if the task involves multi-file reasoning, architectural decisions, or deep debugging (anything where you'd notice the difference between a good model and a great model), it goes to Claude Code. Everything else goes through the regular chain.
Cost Economics
Before this setup:
- Codex via ChatGPT Plus: $20/month, unlimited for most tasks
- Opus via OpenRouter: $15/$75 per million tokens. Unpredictable. That $100 overnight was not the first surprise bill, just the worst one
- Direct Anthropic API: Same pricing, slightly better reliability
After:
- Codex via ChatGPT Plus: $20/month (unchanged)
- Opus via Claude Max: $200/month, unlimited
- OpenRouter: Last resort only, cheapest model available, hard spend cap
Two flat-rate subscriptions now cover roughly 95% of agent work. The remaining 5% (edge cases where neither provider is available or the task needs a specific model) hits the API at minimal cost because it's always routed to the cheapest viable option.
The math: $220/month flat vs. $20/month plus $300-500/month in unpredictable API costs. More predictable, cheaper on average, and no more waking up to surprise bills.
Credential Refresh
One operational consideration: OAuth tokens expire. The Max subscription handles refresh automatically when Claude Code runs. It uses the refresh token to obtain new access tokens transparently. But if the refresh token itself expires or gets revoked (subscription change, password reset, etc.), you need to re-authenticate.
My current process:
- Run
claudeon my Mac. It re-authenticates via browser OAuth if needed - Extract fresh credentials from Keychain
- Copy to the PVC via
kubectl cp
This happens rarely (refresh tokens are long-lived), but it's manual when it does. A future improvement would be a CronJob that health-checks the credentials and alerts via ntfy if they're expired. For now, the agents will fail loudly (Claude Code exits non-zero on auth failure), and I'll notice in the logs.
What I'd Do Differently
Install Claude Code in the container image, not the PVC. I installed on the PVC for speed: no image rebuild needed. But it means the installation is mutable state that could get corrupted or lost if the PVC has issues. A proper approach would bake @anthropic-ai/claude-code into the Docker image. I haven't done this yet because OpenClaw uses an upstream image and I'm not ready to maintain a fork.
Automate credential rotation. The manual Keychain extraction works but doesn't scale. An ideal setup would have the Mac periodically push fresh credentials to a Kubernetes Secret (SOPS-encrypted), which the pod mounts as a volume. I'll probably build this when the first refresh token expires and I'm annoyed enough.
Add structured output parsing. Right now the orchestrator reads Claude Code's stdout as plain text. Claude Code supports --output-format json for structured responses. I should use that for programmatic integration instead of parsing prose.
The Bigger Picture
The insight here isn't really about Claude Code or Kubernetes. It's about the economics of AI agents. Per-token pricing makes sense for occasional use, but agents aren't occasional users. They run autonomously, generate context windows worth of output on every task, and they don't self-regulate spend. Flat-rate subscriptions turn a variable cost into a fixed one, and that changes what's economically viable.
A team of agents that can reach for Opus-level reasoning on hard problems (without anyone worrying about the bill) works differently than one that's always penny-pinching on model selection. The quality ceiling goes up. The agents stop routing around expensive models and start routing toward the best model for the job.
$220/month for unlimited access to both GPT-5.3 and Opus 4.6, running inside Kubernetes, fully integrated into a seven-agent team. That's the setup. The hardest part was the ANTHROPIC_API_KEY env var shadowing the OAuth credentials. Everything else was just plumbing.