The Punctuation Tax

Every tool call, RAG lookup, and database result your agent gets back mid-loop ships as JSON: a brace and two quotes per key, repeated on every single row. TOON, a JSON-compatible format that's picked up five independent language ports since it shipped in 2025, drops that punctuation and encodes uniform arrays as a declared header plus a CSV-style table instead. Its own published benchmark: 42.6% fewer tokens than JSON with retrieval accuracy holding at 72.2% versus 71.4%, tested across Claude, Gemini, and Grok. We ran our own test on a 50-row order-lookup payload: 2,732 tokens as minified JSON, 1,886 as TOON, a 31% cut with the exact same data. It also has a real ceiling: on deeply nested, non-uniform objects the saving all but disappears. Here's the mechanic, our own numbers, where it stops working, and the five-line change that gets it into a request today.

Published 2026-07-26 by Dor Amir on the Nadir blog.

Filed under Context & Compression.

A format tax nobody put on the invoice

Open the payload your agent gets back from a tool call, a RAG lookup, or a database query mid-loop, and it is almost always JSON: a brace to open the object, a quote around every key, a colon, a quote around every string value, a comma, repeated identically on every single row of the array. None of that punctuation carries information the model needs to understand the data. All of it gets tokenized and billed at the same input rate as the data itself.

TOON, short for Token-Oriented Object Notation, is a small, MIT-licensed, JSON-compatible format built specifically to strip that repetition out. Source: GitHub, toon-format/toon It shipped in 2025, and within months five independent language ports appeared: TypeScript, Python, Go, Rust, and .NET, each aiming for spec compliance with the original. Source: Analytics Vidhya, "TOON: Save 60% on Tokens," November 2025 That pace of independent adoption, for a plain-text format with no vendor behind it, is the tell that it is solving a cost every team already has, not a problem someone invented to sell a library.

What TOON actually does to a JSON payload

TOON keeps JSON's full data model, objects, arrays, strings, numbers, booleans, null, so it round-trips losslessly back to identical JSON. What changes is the encoding. A uniform array of objects, the shape a paginated API response, a RAG chunk list, or a SQL query result almost always takes, gets a field header declared once, followed by CSV-style rows:

orders[50]{order_id,customer,status,carrier,total_usd,items,created_at}:
  ORD-10000,customer_0@example.com,shipped,UPS,19.99,1,"2026-07-01T14:00:00Z"
  ORD-10001,customer_1@example.com,processing,FedEx,23.36,2,"2026-07-02T14:01:00Z"
  ORD-10002,customer_2@example.com,delayed,USPS,26.73,3,"2026-07-03T14:02:00Z"

Compare that to the equivalent JSON, which repeats "order_id":, "customer":, "status": and every other key on every one of the 50 rows, plus a brace and a comma per row:

{"orders": [{"order_id": "ORD-10000", "customer": "customer_0@example.com", "status": "shipped", "carrier": "UPS", "total_usd": 19.99, "items": 1, "created_at": "2026-07-01T14:00:00Z"}, {"order_id": "ORD-10001", "customer": "customer_1@example.com", ...

The array length in orders[50] and the declared field list also give the model an explicit row count and schema up front, which the format's authors report helps rather than hurts retrieval accuracy on long arrays, not just a smaller byte count. For data that is not uniform, deeply nested objects, mixed types, optional fields that vary row to row, TOON falls back to YAML-style indentation. That fallback is honest rather than a stretch goal: nested data is exactly where the savings mostly disappear, covered below.

The concrete number

The format's own published benchmark, run across Claude Haiku, Gemini, and Grok on 244 questions, reports TOON holding retrieval accuracy at 72.2% against JSON's 71.4%, essentially even, while using 42.6% fewer tokens to encode the same data. Source: GitHub, toon-format/toon, benchmark results Reported savings range from about 30% on mixed-structure datasets up to nearly 59% on flat, fully uniform ones.

We ran an independent test rather than take the headline number on faith: a 50-row order-lookup result, the kind of payload a tool call returns mid-agent-loop, encoded three ways and counted with tiktoken's o200k_base tokenizer.

EncodingTokensvs. typical JSON
JSON, as typically sent (indented, spaced)3,431baseline
JSON, minified (no whitespace)2,732-20%
TOON1,886-45%
Same 50-row order-lookup payload encoded three ways: 3,431 tokens as typically-formatted JSON, 2,732 minified, 1,886 as TOON, counted with the o200k_base tokenizer.
Same 50-row order-lookup payload encoded three ways: 3,431 tokens as typically-formatted JSON, 2,732 minified, 1,886 as TOON, counted with the o200k_base tokenizer.

That last row is a 31% cut against minified JSON specifically, the fair comparison, since most teams that care about tokens are already minifying. It lines up with the format's own reported 30-59% range for exactly the uniform-array case this test used.

Where the savings disappear

The honest version of this post also runs the case where TOON is not the right tool. We encoded a small, deeply nested config object, feature flags with mixed sub-fields, an array of incident records with a free-text note field, a list of owner emails, no two branches of the object shaped alike. Minified JSON: 124 tokens. TOON: 125 tokens. A wash, and technically TOON came out a hair worse.

That is not a bug in our test; it matches the format's own numbers. Its published benchmark shows only a 1.6% edge over compact JSON on non-tabular, mixed data, because the entire mechanic TOON relies on, declare the field header once, skip repeating it per row, requires a uniform array to declare a header for. A one-off nested object has nothing to tabularize. It is also worth being precise that raw CSV, with zero structural markup at all, still beats TOON by about 6% on purely flat, single-level tables; TOON's overhead there buys back the explicit row count, nesting support, and typed values CSV cannot represent, which matters once a model has to reason about the data rather than just echo it back. The honest read: reach for TOON specifically when a payload is a list of same-shaped records, and don't expect it to rescue a bill dominated by irregular JSON blobs.

A different lever than the ones already on this bill

Most of what inflates a token bill is a question of what gets sent: RAG pipelines that fetch 20 chunks and use 3, structured-output schemas repeated on every call, tool-call schemas resent on every turn, MCP servers loading their full tool catalog before any work happens. We already tested the obvious character-level compression tricks for prose, dropping letters, gzip, base64, and every one of them made text more expensive, not less, because a mangled word usually costs the tokenizer more sub-word tokens than the intact one did. TOON is not that. It is not compressing text, and it is not deciding what data survives; it is changing how whatever data you've already decided to send gets serialized once it's structured and uniform, which is a genuinely different axis from all of the above and stacks with each of them rather than competing.

It also stacks with what Nadir already does automatically. Context Optimize measured a 61% cut in input tokens on Claude Opus by deduplicating repeated tool schemas and boilerplate before a request goes out; that's a context-level trim. TOON is a serialization-level change you make in your own code, to your own payloads, before they ever reach a router. Trim what you send, encode what survives efficiently, then route the request to the cheapest model that can still handle it. Three independent levers, three separate savings, none of which requires touching the others.

Five lines to try it

The reference implementation is TypeScript; a community-maintained Python port exists and is explicitly labeled beta, working toward full spec compliance:

# pip install git+https://github.com/toon-format/toon-python.git
from toon_format import encode

def tool_result_for_prompt(rows: list[dict]) -> str:
    # rows is whatever your tool call, RAG retriever, or DB query already
    # returns as a list of same-shaped dicts. Nothing upstream changes.
    return encode({"results": rows})

messages = [
    {"role": "system", "content": "Answer using only the data below."},
    {"role": "user", "content": tool_result_for_prompt(order_rows)},
]

Nothing about the application's data layer changes. The only new step is the encode() call immediately before the payload becomes prompt text, and decode() on the way back in if the model returns TOON itself.

That request still goes wherever it was going to go. Routing it through Nadir prices whatever the request actually costs after the format change, not a number computed against JSON:

import openai

client = openai.OpenAI(
    base_url="https://api.getnadir.com/v1",
    api_key="YOUR_NADIR_KEY",
)

response = client.chat.completions.create(
    model="auto",  # Nadir routes and prices the request as it actually
                    # arrives; a TOON-encoded tool result is fewer input
                    # tokens than the JSON version, and the cost header
                    # reflects that immediately, no separate config
    messages=messages,
)

print(response.model)
print(response.model_extra["nadir_metadata"]["cost"]["total_cost_usd"])

What to actually do this week

Conclusion

The format savings here are real and independently reproducible, we measured 31% on our own payload against minified JSON, close to the format's own reported range, and the cost is close to zero: one encode call before the prompt goes out, one decode call if the model hands data back. What makes it worth a specific mention rather than a footnote is how narrow and honest its actual scope is. It does nothing for prose, nothing for irregular nested objects, and it loses to raw CSV on purely flat data with no type or nesting needs. It wins, specifically and considerably, on the exact shape of payload that tool calls, RAG lookups, and database results return dozens of times inside a single agent session. That's a common enough shape that a 30-45% cut on it is worth the five lines, and small enough a scope that it earns a place alongside context trimming and routing rather than a claim to replace either.


Sources: [GitHub, toon-format/toon, format spec and benchmark results](https://github.com/toon-format/toon). [GitHub, toon-format/toon-python](https://github.com/toon-format/toon-python). [Analytics Vidhya, "TOON: Save 60% on Tokens," November 2025](https://www.analyticsvidhya.com/blog/2025/11/toon-token-oriented-object-notation/).

More on context & compression

What Nadir is

Nadir is an LLM router. Nadir sends each prompt to the cheapest model that can handle it. A small decision model reads each prompt against your model menu and picks the lowest-cost model it expects to handle it. When the decision model is uncertain or unavailable, the request goes to the strongest model on the menu. The routing step makes no call to your model provider.

Nadir runs two ways. The decision API returns a model, reasoning-effort, cache, context, and policy recommendation without calling a model provider, beside the gateway you already run. That is how a shadow-mode evaluation works, and its projected savings stay advisory. The OpenAI compatible managed proxy executes the route, and migration is a two-line change: point the base URL at api.getnadir.com and set model to auto. On that path an optional verifier can score a complete non-streaming answer and escalate to a stronger model when it misses the configured bar. Streaming bypasses post-generation verification. BYOK is supported on every tier.

For coding agents, Nadir Auto is a terminal launcher for Claude Code or Codex that asks Nadir for the main-session model before each turn, with your configured model as the fallback and cost ceiling. Delegation integrations for Claude Code, Codex, or Cursor instead recommend a model tier for subagent work, and the agent decides; the Claude plugin can also move a main-thread turn to Haiku when Nadir's cache check prices it cheaper, unless its switch_main_model option is off. Either way inference runs on your own provider account, so Nadir holds no provider keys on that path.

What the numbers are, and what they are not

Nadir publishes each evaluation with its scope. On checkable code, run-check-escalate solved 392 of 395 common HumanEval and MBPP problems (99.2%), graded by running the canonical tests; that applies only to tasks with runnable deterministic tests. Nadir-Tumbler posts an arena_score of 72.3 on RouterArena's public scorer, 5th of 23 routers, which measures the routing decision on RouterArena's own model pool. A reference-assisted RouterBench evaluation over 11,420 held-out triples produced a 60% lower projected cost than always-Opus with about 98% retained quality and a 1.7% catastrophic-route rate. That experiment gave the verifier the expensive-model reference answer, which production does not have, so it is a research ceiling and not the deployed path.

None of these is a production guarantee, a universal savings rate, or a forecast for any particular workload. Customer savings are reported from measured execution against a declared baseline, and customer quality only from outcome-labelled traffic. Projected savings and realized savings are separate artifacts and are never blended.

Design-partner program

Three rungs, picked by risk appetite. Rung 0 Shadow runs advisory decision calls alongside live traffic and returns a projected receipt, with nothing in the request path changed. Rung 1 Hosted is the two-line swap on a production slice and returns a realized receipt. Rung 2 On-prem is a supervised six-week proof of concept inside the partner's VPC, where no prompt, response, or usage reaches Nadir. The commitments are the same at every rung. Apply for a rung directly: Rung 0 Shadow, Rung 1 Hosted, or Rung 2 On-prem. Not sure which fits? Start at getnadir.com/contact/?reason=design-partner.

Licensing

NadirClaw is the self-hosted core, source-available under the PolyForm Noncommercial License. Source-available is the correct label; NadirClaw is not open source. Nadir Route's hosted plan has no base fee and charges a variable fee only on measured savings from requests Nadir executed.

Pages on this site

Machine-readable summaries of this site: llms.txt and llms-full.txt.