Search

↑↓ to move↵ to openesc to closetop 6 documentation results

Book a demoTry TokenTriage

In development · Explore the product preview. Join the launch list or book a walkthrough.

Browse docs

Architecture and components

How TokenTriage fits into your system: one process, two ports, one ledger file, and the state added by optional features.

ExplanationLast updated

On this page

Before you put anything in front of production traffic, you want to know what it adds to your system and what you’re responsible for operating. In the default setup, you run one TokenTriage process. It listens on two network ports and appends request records to one file called the decision ledger.

You don’t need to run a database, message broker, or helper on every application host. TokenTriage is one static Go binary of about 10.7 MB, and its container image is about 11 MB. The price table is compiled into the binary, so a host without outbound internet access can still calculate dollar figures. Some optional features add state; those exceptions are called out below.

Two things stay outside, and they’re the ones you already run: your provider accounts, and your application.

You can read this page on its own. If you prefer to start with a running process, use the Quickstart. How it works follows one request end to end, while Core concepts collects the product vocabulary in one place.

The map

Start with the picture. The rest of the page walks through it.

TokenTriage components at a glanceOne TokenTriage process sits between your applications and providers. Application requests pass through port 8787, and provider responses return along the same path. Separately, TokenTriage records one JSON object per request in a local ledger. It serves the dashboard, metrics, and management API on port 9090. The config file, CLI, SDKs, and optional governance store sit outside the live request path.Config — tokentriage.yamlvalidated on startupTokenTriage — one Go binaryData plane127.0.0.1:8787forwards requests · routing optionalDecision ledger~/.tokentriage/decisions.jsonlone JSON row per request · written separatelyAdmin plane127.0.0.1:9090health · metrics · statusdashboard + management APIrecord resultbuild viewsYour agents / appsbase-URL swapOpenAI / Anthropic formatUpstream providersopenai · anthropicbedrock · gemini · …traffictrafficSDKspython · typescriptCLItop · report · eval · keysadd headersreadsGovernance storeSQLite (opt-in)You (operator)dashboard + admin APIinspect · manageRequests cross one binary; storage and operator tools stay off the live request path

Read it left to right: your application sends a request through the TokenTriage process to a provider, and the provider’s response returns along the same solid path.

Dashed lines mark work outside that live request path: recording the ledger row, building dashboard views, reading data with the CLI, and using the optional governance store. The main takeaway is that provider traffic crosses one TokenTriage process. It doesn’t wait for the operator tools or the ledger index.

Two ports, and what each one is for

A listener is a TCP port where a process accepts connections. TokenTriage opens two and keeps them separate. Both use 127.0.0.1 by default, which means only applications on the same machine can connect until you change the address.

Port 8787 handles application requests. TokenTriage calls this the data plane. It accepts OpenAI requests at /v1/chat/completions and Anthropic requests at /v1/messages, forwards them to the provider endpoint in your config, and returns the provider’s response unchanged, including streamed responses. Elsewhere in the docs, these request formats are called dialects, and a configured provider endpoint is an upstream.

Port 9090 serves operator-facing endpoints. TokenTriage calls this the admin plane; your application doesn’t call it. GET /health reports that the process is running, /metrics exposes metrics in Prometheus format, and /tt/api/status reports whether each provider can be reached. The same port serves the management API and, when enabled, the dashboard at /ui/.

Keeping the listeners separate has three benefits:

  • You can expose the data plane to your applications while keeping the admin plane on the same machine, or apply different firewall rules to each port.
  • An operator pulling a heavy report doesn’t compete with proxy traffic.
  • If port 9090 is already in use, the data plane still starts and serves traffic. The startup message identifies the failed admin port and omits the dashboard address.

tokentriage validate prints both addresses before you start anything. Other details are trimmed from this example:

$ tokentriage validate --config configs/tokentriage.example.yaml
mode:      ledger
listen:    127.0.0.1:8787   admin: 127.0.0.1:9090
upstreams: 3
tiers:     4 (cheapest -> most capable)
rules:     3
OK: configuration is valid

listen is the data-plane address, while admin is the operator-facing address. A tier is a named model target ordered from cheapest to most capable. It is defined with the rest of the vocabulary in Core concepts.

The file you need to preserve

For every provider response, TokenTriage appends one JSON record to the decision ledger at ~/.tokentriage/decisions.jsonl. The .jsonl suffix means JSON Lines: a text file with one JSON object per line.

The request doesn’t wait for the ledger write. A slow or full disk won’t delay the provider response, although the ledger row can be missing if the write fails.

The dashboard builds a SQLite index from the ledger. That index can be rebuilt; the ledger is the file you preserve. Governance is the exception: enabling it adds a separate store for keys and limits, described in the following section.

What a ledger row holds, including the hash stored in place of prompt text, is introduced under the decision ledger and listed field by field in the ledger field reference.

What runs by default and what is optional

The components are easier to reason about when they’re grouped by role. This table shows what is available in the default setup and what changes only when you opt in.

Group Part Default What it does
request path data plane on forwards requests and calculates their cost; routing and guardrails stay off until you enable them
operator path admin plane on unless its port is unavailable serves health, metrics, status, and management endpoints without sharing the request port
recorded state decision ledger on appends one JSON record per proxied request
configuration flags or tokentriage.yaml file optional names providers and controls optional routing, caching, guardrails, and governance
optional interface dashboard on in zero-config quickstarts; otherwise off shows the same ledger data that the CLI reads; --no-dashboard turns it off
optional state governance store off holds virtual keys and per-tenant limits in embedded SQLite
developer tools CLI and SDKs CLI included; SDKs optional inspect data or add attribution headers and typed cost receipts to your application

Guardrails can inspect request and response text

Guardrails run on the data plane only after you enable them. Built-in detectors stay inside the TokenTriage process. Sending text to another model for scoring or to a classifier you run yourself requires the explicit setting external: allow. The same rule applies when that classifier runs on the same machine. See Air-gap and known limits.

Governance adds stored state

A virtual key is a token you give to a team or tenant so its spending and limits can be tracked separately from your provider key. On one TokenTriage process, those keys and limits live in embedded SQLite. Multiple replicas require shared Redis or Postgres state so every replica counts against the same limits. See Governance and Scale out.

The SDKs are conveniences rather than dependencies. A base-URL change is enough to use TokenTriage without adding a library. See SDK overview.

What stays outside the binary

Your providers. TokenTriage forwards to accounts you already hold at OpenAI, Anthropic, Bedrock, Gemini, or any OpenAI-compatible endpoint. Your config names the environment variable that holds each credential; it doesn’t contain the credential itself. If you don’t name one, TokenTriage forwards the request’s Authorization header unchanged. There’s no billing or settlement code in the binary, so you continue buying tokens directly from your providers.

Your application. The integration is a base-URL change. Your prompts, your framework, and your deployment stay where they are.

Latency and failure behavior

TokenTriage adds under 0.15 ms of overhead in the published benchmark run, whose pinned versions, equal-core budget, and confidence interval are in Benchmarks.

Where it can surprise you

  • The dashboard default flips with how you start the process. A config-file run leaves it off; the zero-config quickstarts turn it on.
  • Governance as a whole is off, but a limit you write defaults to mode: on, meaning enforcing. Introduce a new limit in mode: shadow first.
  • Both ports accept connections only from the same machine by default. Opening either one to another host is a deployment decision you make yourself. This is beta software.

This page doesn’t cover how a routing decision gets made, which is How it works, or how to run several replicas, which is Scale out.