Docs
Get started
One binary, one base-URL swap, five minutes to your first costed request. Routing is opt-in and earned — you start by simply seeing your bill.
Install
TokenTriage is a single Apache-2.0 Go binary — no CGO, no sidecar runtime. Build it from source (a prebuilt release binary works too):
git clone https://github.com/imankamyabi/tokentriage.git
cd tokentriage
# One static binary; the pricing table is compiled in via go:embed.
CGO_ENABLED=0 go build -o dist/tokentriage ./cmd/tokentriageQuickstart
The fastest start is a zero-config ledger proxy. It observes and costs every request and changes nothing about the response:
# Zero-config ledger proxy for Claude Code — pure observation, no routing.
tokentriage run --anthropic
# Listens on 127.0.0.1:8787 (data plane)
# and 127.0.0.1:9090 (admin: /health, /metrics, /tt/api/status)TokenTriage speaks the OpenAI (/v1/chat/completions) and Anthropic (/v1/messages) dialects, and the proxied bytes are identical to going direct — streaming included.
See your bill
Point your app’s base URL at the proxy. Nothing else in your code changes:
from openai import OpenAI
# The only change to your app: point the base URL at TokenTriage.
client = OpenAI(base_url="http://localhost:8787/v1")
resp = client.chat.completions.create(
model="gpt-5",
messages=[{"role": "user", "content": "Summarize this ticket."}],
)Or straight over HTTP:
curl http://localhost:8787/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"model": "gpt-5",
"messages": [{"role": "user", "content": "Hello"}]
}'For Claude Code specifically, wrap sets ANTHROPIC_BASE_URL and injects a fresh trace id for you:
# Exec a Claude Code session pointed at the proxy, with a trace id injected
# so every request in the session groups into one trace.
tokentriage wrap --agent claude -- claudeNow explore the dashboard on http://localhost:9090/ui, or runtokentriage top for terminal rollups. Every dollar is attributed by model, token type, trace, agent, and tool.
Turn on routing
Routing is opt-in. The honest path is to run in shadow first, read the savings report, and only then enforce. You can start routing with no config file at all:
# Turn on routing with no config file: a cheap tier and a complex tier.
tokentriage run \
--simple ollama/llama3.1:8b \
--complex anthropic/claude-sonnet-4-6Configuration
For anything real, use a YAML config. Upstreams are named; tiers are ordered cheapest to most capable; secrets are always environment-variable names, never values:
# tokentriage.yaml — secrets are always env-var NAMES, never literals.
upstreams:
together:
provider: together_ai
base_url: https://api.together.xyz/v1
api_key_env: TOGETHER_API_KEY
# Ordered tiers, cheapest → most capable.
tiers:
- name: cheap
upstream: together
model: meta-llama/Llama-3.1-8B-Instruct-Turbo
- name: capable
upstream: anthropic
model: claude-sonnet-4-6
# Start in 'ledger'. Climb to 'shadow', then 'route', as the evidence allows.
mode: ledgerValidate it strictly before you run — an unknown field is an error, not a silent ignore:
tokentriage validate --config configs/tokentriage.example.yamlThe trust ladder
The mode setting is the whole safety story. You climb one rung at a time:
ledger— observe and cost every request. Zero request mutation. No client impact.shadow— also compute the would-route decision and its counterfactual cost, soreportshows the savings you’d get — without touching a response.route— enforce decisions: rewrite the model, pick the cheaper upstream, honor cache pins.
Preview the whole thing safely first:
# Boot the whole dashboard against a watermarked synthetic ledger.
tokentriage demoProviders
Four wire dialects are compiled into the binary — OpenAI, Anthropic, Bedrock, and Gemini. Every OpenAI-compatible upstream (Groq, Together, Fireworks, OpenRouter, a self-hosted vLLM / Ollama / llama.cpp server, and your own) rides the OpenAI driver with zero new code: adding one is N+1-by-config.
Deploy
Container image is FROM scratch, ≈11 MB (estimated), non-root:
docker run --rm \
-p 8787:8787 -p 9090:9090 \
-e ANTHROPIC_API_KEY \
-v "$HOME/.tokentriage:/data" \
tokentriage:latestThe canonical Kubernetes path is the Helm chart (one StatefulSet, per-pod PVC):
helm install tt deploy/helm/tokentriage \
--namespace tokentriage --create-namespace \
-f my-values.yamlKustomize, Docker Compose (with a fully self-contained air-gap profile), and a single-VM Terraform module all live under deploy/. The chart renders zero Secret objects — configuration carries references, never values.
CLI reference
| Command | What it does |
|---|---|
run | Start the proxy (ledger / shadow / route). |
wrap | Exec an agent pointed at the proxy, with a trace id injected. |
top | Ledger rollups as terminal tables. |
report | Shadow would-route savings report. |
eval | The honesty verdict vs. the zero-router baseline. |
calibrate | Fit routing thresholds from your own logs. |
prices | Inspect the embedded pricing snapshot. |
validate | Strictly validate a config file. |
demo | Boot the dashboard on a synthetic ledger. |
keys mint | Mint a virtual key (governance). |
This is the essential path. The full reference — the policy language, calibration, response caching, governance, and the OpenAPI contract — lives in the repository and theAPI reference.