local-first · private-first · exact

Your coding agent is spending money.Right now.

Every message, every tool call, every model — silently adding up on someone else's server.TokenOps tracks exact usage, enforces budgets, and keeps every byte on your machine.

$0/mo · no cloudexact tokens, not guesses4-state budget guardprivate by design

the problem, in real time

Watch a rogue agent burn $5.00

scenario: rogue coding agent

agent · claude-sonnet-4 · session 04b250b5● tracking
calls
0
tokens
0
cost
$0.0000
waiting for LLM calls…
daily budget$5.00
allow$5.00 left

↑ real session data format — budget guard stops it at the limit, every time.

pick a scenario · click to replay

how it works

Three tiers. One rule: know the exact cost before it's too late.

Tier 2aexact · automatic

Plugin

OpenCode

A native plugin hooks the runtime. Every message.updated carries real cost + tokens — zero effort, zero config.

  • Exact tokens from SDK
  • Auto track_usage per message
  • Budget guard before every call
Tier 2bexact · automatic

Gateway

Claude Code · Cursor · Windsurf

A local HTTP proxy reads the usage field in every provider response. No binary touched, no license risk.

  • OpenAI + Anthropic protocols
  • 429 on block · max_tokens cap on degrade
  • Provider key never leaves your machine
Tier 1estimate · instructed

Steering

Kiro · Copilot · managed

For managed backends with no configurable endpoint: the agent calls the MCP tools itself.

  • Exact-enough estimates
  • Zero network changes
  • Works on any MCP host

the guard

Not just a block. A circuit breaker.

Four states, like a real circuit breaker. It doesn't kill your workflow at the limit — it warns you first, downgrades gracefully, and only stops when there's no other choice.

allow
$0.00–79%

Requests pass through untouched.

warn
80%

Passes, logged — you see it coming.

degrade
95%

Model capped / swapped for a cheaper one.

block
100%

HTTP 429 — the agent never reaches the provider.

which agent? which tier?

Every agent. Covered.

agenttierhowtokensneeds steering?
OpenCode2aNative plugin · in-process · automaticexactno
Claude Code2bAnthropic protocol via local gatewayexactno
Cursor2bOpenAI-compatible base URLexactno
Windsurf2bPoint base URL at localhost:8787exactno
Kiro1AWS-managed LLM · can’t interceptestimateyes

start now

Running in 30 seconds. Locally.

~ terminal
# 1 — install (one package, two tools)
npm i -g @finoptix/tokenops-mcp

# 2 — point any agent at the gateway
tokenops-gateway
→ serving on http://localhost:8787

# 3 — or let OpenCode track itself (native plugin)
opencode plugin -g path/to/tokenops.ts

# 4 — check the ledger
sqlite3 ~/.tokenops/usage.db "SELECT model, cost_usd FROM usage_events;"
→ 8 rows · exact cost, per call, yours only

inside the mcp server

Six tools. One SQLite ledger.

Everything the MCP server exposes. Your agent can call these itself — that's how the steering tier works on managed backends.

track_usageledger

Log a single LLM call — model, tokens, cost, metadata. Cost auto-computed from tokens when you skip it.

→ autonomous
get_budgetbudget

Remaining allowance for daily, monthly or session periods — limits, used, and left.

→ autonomous
set_budgetbudget

Dollar limit per period plus the over-limit action: allow, warn, degrade, block.

→ needs a guard
route_llmrouter

Cheapest model that can handle a task. Auto-classifies complexity and checks budget before routing.

→ needs steering
session_reportledger

Per-session cost summary — duration, calls, tokens, breakdown by model.

→ autonomous
run_auditledger

Monthly report: cost breakdown, top models, complexity mix, savings opportunities.

→ autonomous

read this before assuming anything:

track_usage · get_budget · session_report · run_audit — autonomous. Pure data, no guard, no steering.

set_budget — writes config, doesn't apply it. Enforcement happens at the call site: gateway (tier 2b), Sayay runtime guardrails, or the agent following instructions (tier 1). Without one of those, a budget protects nothing.

route_llm — recommends, doesn't impose. Someone must follow it: the agent calls it and uses the result (steering), or the gateway uses it internally.

none of these is the guard. Sayay sits at the call site — reads get_budget, respects set_budget, and decides allow / warn / degrade / block before the request ever reaches the provider.

what's next

Already past six phases. Not stopping.

Dogfood weeknow

A week of real usage tracked across OpenCode, Claude Code, Cursor and Windsurf — the data decides what ships next.

Sayay runtime guardrailsnext

In-process budget guards for Bedrock AgentCore, Lambda, K8s, Cloudflare Workers, Strands, LangChain, Vertex — same breaker, no HTTP proxy.

Control planelater

Optional centralized dashboard: multi-agent budgets, team view, alerting. Local-first stays the default.

More native hookslater

First-party plugins for more agent runtimes, so exact tracking spreads beyond OpenCode.