Skip to main content

tokenledger

Measure where the tokens actually go in a multi-agent / multi-model LLM system.

Most teams reason about LLM cost as if it scales with prompt size. In a multi-step agent it doesn't — it scales with (context size × number of requests), because almost all input is a cache re-read of a growing prefix, and it is superlinear in step count, because each step's priming and its tool result get re-carried into every later step. tokenledger reads your request logs and shows you exactly that, so you optimize the right thing.

Status: v0.2 — beta, feedback very welcome. Author: Pallav Pokhriyal. Zero dependencies, zero telemetry. It reads logs you already have.

Install

pip install tokenledger-llm     # on PyPI; the import name and CLI are both `tokenledger`
# or from source:
pip install -e .

Quickstart

tokenledger report examples/sample_logs/sample.jsonl
# or JSON:
tokenledger report examples/sample_logs/sample.jsonl --json

Example output:

tokenledger — cost structure report
==========================================
requests (steps): 4
turns:            2
steps per turn:   {1: 3, 2: 1}

total input tokens:  89,532
total output tokens: 505

cache-read:               88,432 (98.8% of input)
priming re-sent:          80,464 (89.9% of input)
re-carried conversation:  7,968 (8.9% of input)

mean prefix / request: 22,383    max prefix: 24,000
prefix re-read cost:   88,432 tokens

takeaway: cost tracks (prefix size x requests), dominated by cache re-reads —
not prompt size. Cut steps and reset context to move the bill.

Log format

JSONL, one request (one step within a turn) per line. Required: turn, step, input_tokens. Everything else is optional and defaults to 0:

field meaning
turn / step which turn, and the step index within it
input_tokens total input sent on this request (the context)
cache_read_tokens input served from cache (the re-read prefix)
priming_tokens fixed re-sent block: system prompt, tool schemas
conversation_tokens re-carried prior messages + tool results
tool_result_tokens tokens this step emitted as tool output (carried forward)
output_tokens completion tokens

Every count (and turn / step) must be a non-negative JSON integer: floats (1.0, 1e3), booleans, strings and negative numbers fail with TL_E_BAD_VALUE (exit 1), NaN/Infinity with TL_E_BAD_JSON, and non-UTF-8 files with TL_E_BAD_ENCODING. A UTF-8 BOM, CRLF and lone-CR line endings are accepted, and totals stay exact beyond 2^53 (Python ints; the JavaScript library API instead throws TL_E_OVERFLOW above 2^53-1, while its CLI stays exact). The full rules, shared with the JavaScript port, are in docs/SPEC.md; behaviour changes since 0.1.1 are in CHANGELOG.md.

Have a different log shape? Map it:

from tokenledger import load_requests, account
reqs = load_requests("mylog.jsonl", mapping={"input_tokens": "prompt_tok", "turn": "iteration"})
print(account(reqs).cache_read_pct)

Provider usage logs (no reshaping)

Point it straight at Anthropic or OpenAI usage records:

tokenledger report anthropic_usage.jsonl --format anthropic --turn-key turn --step-key step
tokenledger report openai_usage.jsonl   --format openai   --turn-key turn --step-key step

Each line is one request whose token counts live at top level or under a usage key. One correctness detail the adapters handle for you:

  • Anthropic reports usage.input_tokens as the fresh (uncached) input only; cached context is reported separately in cache_read_input_tokens / cache_creation_input_tokens. The adapter sums all three so input_tokens is the true per-request context — taking input_tokens alone silently undercounts the prefix, which is the whole thing being measured.
  • OpenAI reports usage.prompt_tokens as the total input already, with the cached portion in prompt_tokens_details.cached_tokens.

If your records don't carry turn/step, omit the keys — each line becomes its own step in a single turn (totals and percentages stay correct; the per-turn step structure just goes flat). In Python:

from tokenledger import load_provider, account
reqs = load_provider("anthropic_usage.jsonl", "anthropic", turn_key="turn", step_key="step")
print(account(reqs).cache_read_pct)

What-if: which step to cut

from tokenledger import load_requests, what_if_remove_step
reqs = load_requests("examples/sample_logs/sample.jsonl")
print(what_if_remove_step(reqs, turn=1, step=0))  # tokens saved by removing an early step

Removing an early step saves more than a late one — it drops that step's own cost and its tool result from every later step. That's the superlinearity, made concrete.

For AI agents

AGENTS.md and llms.txt ship in the package. tokenledger describe --json prints tool definitions (Anthropic, OpenAI, MCP), tokenledger mcp runs an MCP server on stdio, --json / --quiet work on every command, and errors are {code, message, hint} objects. JSON Schemas for every output are in schemas/.

Why it exists

See docs/METHODOLOGY.md for the measured findings this operationalizes.

Contributing

Issues and PRs welcome — especially log-format adapters for different providers/harnesses. Keep contributions genuinely useful; no telemetry, no secrets in sample data (synthetic only).

License

MIT — see LICENSE.

Metadata

Release files for tokenledger-llm 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for tokenledger-llm 0.2.0
File Size Uploaded Provenance Actions
tokenledger_llm-0.2.0.tar.gz 32.2 kB Without provenance Details for tokenledger_llm-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for tokenledger-llm 0.2.0
File Interpreter ABI Platform Actions
tokenledger_llm-0.2.0-py3-none-any.whl Python 3 none any Details for tokenledger_llm-0.2.0-py3-none-any.whl

Total release size: 60.8 kB

Release files / tokenledger_llm-0.2.0.tar.gz

Download URL tokenledger_llm-0.2.0.tar.gz
Size 32.2 kB
Tags Source
SHA-256 checksum
How to use checksums
d32e01085942ed5eda1e74b33fea8308e9e4a9bc3e20a2f61a199445348b4796
BLAKE2b-256 checksum
How to use checksums
e721b1a2b78b9fae9a1ef36a2b5becfe0caa1fe9491860c3631a7f8bc57385dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.6

Release files / tokenledger_llm-0.2.0-py3-none-any.whl

Download URL tokenledger_llm-0.2.0-py3-none-any.whl
Size 28.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
003cd1f1dd619029e81057b26fee405f6fd314fab7249d025b8b3c4da750317c
BLAKE2b-256 checksum
How to use checksums
99bd29200c3e6dd8e0f250abe05b7c8c17c68087c769443c377c3672c8a75084
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.6

Security for tokenledger-llm 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page