The Self-Hoster's Guide to Zero-Cost AI
A practical framework for eliminating per-token AI costs: audit your spend, classify your LLM calls, map subscriptions to workloads, route with fallback, and monitor the results.
If you're running AI agents, dashboards, or LLM-powered tools on a homelab, you're probably paying per-token API costs that you don't need to. I cut my AI infrastructure spend from ~$230/month to effectively zero in a weekend. This post is the framework: not the story of how I did it (that's here), but the step-by-step for doing it yourself.
Step 1: Audit Your Spend
Most people running LLM-powered tools don't actually know what they're spending. The first step is finding out.
If you use OpenRouter: The dashboard at openrouter.ai/activity shows daily spend, per-model breakdown, and per-request costs. Sort by cost descending. The top 2-3 entries are probably 80% of your bill.
If you use Anthropic directly: Check console.anthropic.com/settings/usage. It shows cumulative spend by day.
If you built usage tracking: Query it. Life Hub tracks every LLM call in an LLMUsage table: feature name, model, input/output tokens. A simple GROUP BY feature query told me that two features (conflict refresh and council review) accounted for 88% of my spend. Everything else was noise.
The key question: which features make the most calls, and which calls cost the most per-token? High-frequency calls to cheap models (Haiku) add up slowly. Low-frequency calls to expensive models (Opus, Sonnet) add up fast. You need to know which you're dealing with.
Step 2: Classify Your LLM Calls
Every LLM call in your system falls into one of three categories. Each has a different optimization path.
Pre-computable (periodic synthesis). Daily briefs, weekly summaries, news briefings, pillar narratives, correlation insights. These synthesize data that changes slowly: hourly or daily, not per-request. They can be generated on a schedule, cached, and served without a live API call. This is your biggest optimization opportunity.
Event-driven (reactive). Trigger commentary, sentiment analysis, thought classification, topic extraction. These fire in response to user actions: a journal entry, a mood log, a threshold breach. They can't be pre-computed because the input doesn't exist until the event happens. But they CAN be routed through subscription providers instead of per-token APIs.
Interactive (real-time). Chat, live council sessions, on-demand analysis. A human is waiting for the response. These need low latency and can't be cached. Hardest to optimize, but also the easiest to route through subscription OAuth.
The split matters because pre-computable work can use a desktop scheduler (zero marginal cost, better model), while event-driven and interactive work needs a real-time API, which is where OAuth subscription routing comes in.
Step 3: Map Subscriptions to Workloads
Here's the current landscape of AI subscriptions that can be used for self-hosted workloads:
| Subscription | Cost | What You Get | Best For |
|---|---|---|---|
| Claude Pro | $20/mo | Opus via Claude Desktop | Scheduled pre-computation via MCP |
| ChatGPT Plus | $20/mo | Codex models via OAuth (PKCE) | Real-time agent routing |
| GitHub Copilot | $10/mo | Copilot models | Code-specific tasks |
The key insight: these subscriptions include the same models you'd pay $3-15 per million tokens for via API. The subscription is a fixed cost you're probably already paying for other reasons.
Not every subscription works for every workload:
- Claude Desktop can only pre-compute on a schedule (it has a built-in task scheduler). There's no real-time API. Good for periodic synthesis, useless for interactive.
- ChatGPT Plus via Codex OAuth works as a real-time API substitute: your agent framework sends requests through it exactly like it would an API key. Good for agent routing and interactive work.
- You need the right subscription for the right workload category. Pre-computable → Claude Desktop. Everything else → Codex OAuth.
Step 4: The Architecture Pattern
The routing logic is the same regardless of what you're building:
Request arrives
→ Check pre-computed cache (if this is a pre-computable scope)
→ Fresh? Return cached content. Done.
→ Stale? Fall through.
→ Route to subscription provider (primary)
→ Success? Return response. Done.
→ Rate limited / error? Fall through.
→ Route to per-token API (fallback)
→ Success? Return response. Done.
→ Budget exceeded? Skip / return error.
Why the fallback matters:
- Subscriptions have rate limits and outages
- OAuth tokens expire (10-day access token, 30-90 day refresh token)
- Your Mac sleeps, reboots, loses network (killing the pre-compute scheduler)
- The per-token API is your safety net: you pay for it only when the subscription can't handle the request
In practice, the fallback fires about 5% of the time. That's a 95% cost reduction with zero reliability risk.
Step 5: Implementation Patterns
Pattern A: Pre-Compute Cache
For periodic synthesis work. The idea: a desktop application (Claude Desktop, or any scheduler with MCP access) generates content on a schedule and writes it to your app's database. Your app checks for fresh cached content before making its own API call.
What you need:
- A cache table:
scope(unique),content,generated_at,model - A freshness check function: return cached content if younger than threshold, else None
- A write endpoint (MCP tool or API): the scheduler calls this to store pre-computed content
- A staleness check at the top of every LLM generator function
# Before every LLM call
precomputed = await get_precomputed("daily_brief")
if precomputed:
return precomputed # Opus quality, zero cost
# ... existing Haiku/Sonnet call as fallback ...My setup: 11 pre-computable scopes, 2-hour refresh cycle via Claude Desktop scheduler, 6-hour staleness threshold (configurable). The threshold covers Mac sleep and reboots: if the scheduler misses a cycle, the app falls back to its own API calls automatically.
Pattern B: OAuth Subscription Routing
For event-driven and interactive work. The idea: configure your agent framework to authenticate with the subscription provider via OAuth, routing all requests through your fixed-cost subscription instead of per-token API keys.
For OpenClaw (or similar agent frameworks):
{
"model": {
"primary": "openai-codex/gpt-5.3-codex",
"fallbacks": [
"openrouter/anthropic/claude-sonnet-4-6",
"openrouter/anthropic/claude-haiku-4-5"
]
}
}The OAuth setup is a one-time interactive flow (browser-based PKCE). After that, tokens refresh automatically. Full re-authentication is needed every 30-90 days when the refresh token expires.
If you're running in Kubernetes (headless, no browser), you'll need kubectl port-forward to route the OAuth callback into the pod during setup. It's annoying but only happens once every few months.
Pattern C: Budget Controls
For event-driven work that can't use Pattern A or B yet. The idea: set a daily spending cap in your LLM layer and skip non-critical AI calls when you're over budget.
async def call_llm(system_prompt, user_message, *, feature, model="haiku"):
# Budget gate — skip non-critical AI when over daily limit
if settings.LLM_BUDGET_DAILY_CENTS > 0 and not await check_daily_budget():
return None # Caller handles gracefully (rule-based fallback)
# ... actual API call ...This doesn't eliminate costs, but it caps them. Combined with Patterns A and B handling 95% of your traffic, the remaining event-driven calls that hit the budget gate are minimal.
Step 6: Monitor the Results
After implementing, verify it's actually working:
- Cache hit rates: How often does pre-computed content serve vs. falling back to an API call? If your staleness threshold is too aggressive, you're making unnecessary API calls.
- Provider split: How often does the subscription handle requests vs. the per-token fallback? Check your OpenRouter dashboard: daily spend should drop dramatically.
- Quality comparison: Is the subscription model's output as good as the API model's? For Opus vs. Haiku, the subscription output is actually better. For Codex vs. Sonnet, monitor and compare.
- Token expiry alerts: Set a reminder or automated check for OAuth token refresh. You don't want to discover it expired when your agents stop working.
Step 7: The Numbers
Here's what this looked like for my setup, a 7-agent AI system (OpenClaw) and a personal dashboard with 10+ AI features (Life Hub):
| System | Before | After | How |
|---|---|---|---|
| OpenClaw (7 agents) | $150-300/mo | $0 | ChatGPT Plus OAuth |
| Life Hub (pre-computable) | $2-5/mo | ~$0 | Claude Desktop pre-compute |
| Life Hub (event-driven) | $1-2/mo | $1-2/mo | Still API (Phase 3) |
| Total variable | $153-307/mo | ~$1-2/mo | |
| Subscriptions (fixed) | $40/mo | $40/mo | Already paying |
Your numbers will vary, but the pattern scales. The more LLM calls you make, the bigger the savings.
Gotchas
OAuth in headless environments. Kubernetes pods, Docker containers, remote servers. None of them have browsers. The initial OAuth flow needs an interactive TTY and a browser redirect. For K8s: kubectl port-forward routes the callback, kubectl exec -it gives you the TTY. For Docker: docker exec -it plus exposing the callback port. For remote servers: SSH with -L 1455:localhost:1455 for port forwarding.
Token sink problem. If you authenticate with the same provider from multiple tools (e.g., OpenClaw AND the Codex CLI), one of them may get logged out. Some OAuth providers invalidate older refresh tokens when new ones are issued. Pick one auth source per provider and stick with it.
Node.js version hell. If you use mcp-remote to bridge stdio and HTTP MCP transports, check which Node version it's actually running under. Claude Desktop's PATH may find an old system Node before your Homebrew Node. The undici library needs Node 20+ for the File global. Fix: set env.PATH in your MCP server config.
Ephemeral container filesystems. Config changes inside pods get wiped on restart. If your agent framework edits its config file at runtime, those edits won't survive a pod restart. Use Kubernetes ConfigMaps for anything that needs to persist, and PersistentVolumeClaims for state like OAuth tokens.
Model quality differences. Opus is better than Haiku for synthesis. You'll notice the quality improvement in pre-computed content. But for simple classification tasks (sentiment analysis, topic extraction), Haiku is perfectly adequate and much cheaper as a fallback. Don't over-optimize by routing everything through the most powerful model.
Anthropic setup-token. The OpenClaw docs support openclaw models auth setup-token --provider anthropic for routing through a Claude Pro subscription. But Anthropic has blocked subscription usage outside Claude Code for some users in the past. Treat this as a policy risk and verify current terms before relying on it.
The Framework, Summarized
- Audit: find out what you're actually spending and where
- Classify: pre-computable, event-driven, or interactive
- Map: match each category to the right subscription
- Route: subscription as primary, API as fallback
- Monitor: verify savings and watch for quality drift
The tools exist today. The subscription model creates an arbitrage opportunity between fixed-cost and per-token pricing. The only question is whether you're exploiting it.