Skip to content

soon-format/soon

Repository files navigation

SOON — Shape-Oriented Object Notation

The token-efficient replacement for JSON in LLM prompts. Cut ~60% of the characters you spend on nested JSON payloads. Lossless. Human-readable. Zero runtime dependencies. Ships for Python and TypeScript.

PyPI npm CI MIT Spec v0.1


Why this exists

LLM tokens are money. A single call to GPT-5 or Claude Sonnet 4.6 with a nested JSON tool response can burn thousands of tokens repeating the same keys on every object in a list:

[{"id":1,"customer":{"name":"Ada","city":"Boulder"}},
 {"id":2,"customer":{"name":"Linus","city":"Helsinki"}},
 {"id":3,"customer":{"name":"Grace","city":"Baltimore"}}, ...]

Every "id", "customer", "name", "city" is billed on every row. Multiply by 100 rows and half your context window is punctuation and duplicated keys.

SOON declares the shape once, then streams positional values. Same data, same information, smaller bill:

SHAPE customers = {id,customer:{name,city}}
customers[3]<customers>:
(1,(Ada,Boulder))
(2,(Linus,Helsinki))
(3,(Grace,Baltimore))

That's the whole idea. Everything else in this repo — the spec, the two implementations, the benchmarks, the conformance suite — is scaffolding to make it safe to swap SOON in for JSON in production.


Measured savings

Nine datasets, from trivially flat to adversarially irregular. All numbers are characters vs compact JSON (positive = smaller); generated by benchmarks/run.py.

Dataset Compact JSON YAML TOON SOON
L1 flat config (6 keys) 113 +11.5% +12.4% +12.4%
L2 flat table (100 rows) 6,900 +1.5% +59.0% +58.6%
L3 primitive arrays 3,057 -25.7% +6.4% +6.4%
L4 nested small (10 orders) 2,497 -9.3% -8.3% +56.6%
L5 nested large (100 orders) 24,254 -9.2% -9.7% +60.6%
L6 deeply nested (depth 5) 5,660 -36.3% -198.6% +56.2%
L7 event log (semi-uniform) 9,801 -1.5% -22.3% +44.0%
L8 mixed-kind fields 2,950 -6.5% -25.2% +39.5%
L9 adversarial (irregular) 1,412 -42.1% +12.3% +0.1%

Reading of the table:

  • SOON wins every nested dataset (L4–L8) by 39–61%. This is the entire point — real API payloads look like L4–L7.
  • TOON is excellent for flat tables (L2) — use it there. SOON is essentially tied.
  • On L9 (adversarially irregular data), SOON's never-worse guarantee kicks in and returns compact JSON. TOON has a YAML-style unquoted-literal trick that beats JSON here; we're closing that gap in v0.2.

The never-worse guarantee

auto mode compares SOON against compact JSON at encode time and returns whichever is smaller. SOON output is never larger than JSON. You can drop it in blind — the worst case is "you saved nothing on this specific payload."

from soon_format import encode
encode({"tiny": 1})     # returns '{"tiny":1}' — compact JSON, because SOON wasn't smaller
encode(big_nested_doc)  # returns SOON — because SOON was smaller

Quickstart

Python

pip install soon-format
from soon_format import encode, decode, stats

doc = encode(data)                        # auto mode, never-worse guarantee
data == decode(doc)                       # True — lossless
stats(data)                               # {"json_chars": …, "soon_chars": …, "saving": 0.604}

# Real-token cost decisions (requires: pip install "soon-format[tokens]")
# The o200k_base vocab ships inside the wheel — works offline, no network.
encode(data, tokenizer="o200k_base")
stats(data, tokenizer="o200k_base")       # adds json_tokens / soon_tokens

TypeScript / JavaScript

npm install @soon-format/soon
# Optional: real-token cost decisions (adds ~2 MB of BPE ranks)
npm install js-tiktoken
import { encode, decode, stats } from "@soon-format/soon";

const doc = encode(data);                 // same semantics, byte-identical to Python
const original = decode(doc);

// With js-tiktoken installed, encoding and stats agree with the Python side:
encode(data, { tokenizer: "o200k_base" });
stats(data, { tokenizer: "o200k_base" }); // adds jsonTokens / soonTokens

CLI (either ecosystem)

# Node
npx @soon-format/cli encode data.json --stats
npx @soon-format/cli decode doc.soon --pretty

# Python
uvx soon-format encode data.json --stats
soon decode doc.soon --pretty
soon check data.json                      # round-trip verification, exit code 0/1

Real-world use cases

SOON is designed for anywhere you hand nested structured data to an LLM:

  • Agent tool outputs. Wrap tool responses before they hit the model. Same information reaches the LLM; 40–60% fewer tokens.
  • RAG context. Encode retrieved records (orders, tickets, users, invoices) that go into the prompt.
  • Log/event summarization. Compress semi-uniform event streams before asking the model to reason over them.
  • Structured extraction outputs. Ask the model to emit SOON when returning tabular results; parse it back with decode().
  • MCP servers / model middleware. A single transform on the way in, another on the way out.

Prompting the model. Add a short header to your system prompt once:

Data is in SOON format. SHAPE name = {…} declares field names in order. Each row is a tuple (v1,v2,…) matching the shape. _ means the field is absent. [N] gives the row count.

That's it. Current-generation models (GPT-4o, Claude Sonnet/Opus 4.x, Gemini 2.x) read SOON reliably.


When SOON is not the right choice

  • Flat tabular data with no nesting. CSV is smaller. TOON is great here. SOON is essentially tied — use whichever fits your stack.
  • Retrieval-accuracy-critical tasks where positional values may hurt. Positional tuples are denser than key-value pairs; models occasionally miss which slot is which on very long rows. An accuracy benchmark harness is planned for v0.2 — until then, evaluate on your task.
  • Tiny payloads. auto mode already hands you compact JSON in this case (that's the never-worse guarantee working as intended). No action needed.

How it works, in three moves

  1. Shape inference. For every array of ≥ 2 uniform objects, the encoder infers a shape (field names + types) and declares it once at the top: SHAPE customers = {id,name,city}.
  2. Positional tuples. Each row of the array becomes (v1,v2,v3) — no keys, no quotes on values that don't need them.
  3. Cost gating. For every candidate table, encoder compares the tabular cost against compact JSON. If tabular isn't smaller, it falls back. That's the never-worse guarantee.

Nesting works because the shape mechanism is recursive: nested objects become nested tuples, nested arrays of objects become lists of tuples. Optional fields use ? (in the shape) and _ (in rows). Irregular values escape via !<json>.

The normative spec is 200 lines. The conformance suite has 41 fixtures that every implementation must pass byte-for-byte.


Comparison at a glance

JSON YAML CSV TOON SOON
Lossless yes yes no yes yes
Handles nested data yes yes no degrades yes
Handles flat tables well ok ok yes yes ok
LLM-readable without training yes yes yes yes yes
Zero runtime deps yes no yes yes yes
Never-larger-than-JSON guarantee no no no yes
Multi-language byte-identical parity no no limited yes (Py + TS)
Nested-payload token savings vs JSON 0% negative n/a negative ~60%

Repository layout

Path What
SPEC.md Normative format specification (v0.1)
conformance/ Language-agnostic fixture suite — the contract every implementation must pass
python/ soon-format on PyPI — reference implementation
ts/packages/soon @soon-format/soon on npm
ts/packages/cli @soon-format/cli on npm (npx-runnable)
benchmarks/ Reproducible size + speed benchmarks (nine datasets, three baselines)
tools/ Fixture generator, cross-implementation differential test

Both implementations pass the same 41 conformance fixtures byte-for-byte, plus property-based round-trip tests (decode(encode(x)) == x, Hypothesis / seeded fuzzing) and a differential CI job that byte-compares encoder outputs across languages.


Roadmap

We're actively working on making SOON the smallest and fastest way to send JSON to any LLM. Highlights:

See the roadmap tracker or ROADMAP.md for details, evidence, and definition-of-done for each item.


FAQ

Is SOON just YAML with a schema? No. YAML is a general human-serialization format; SOON is a specialized encoding tuned exclusively to minimize LLM token cost on nested JSON. YAML expands nested data (see L4–L8 benchmarks); SOON contracts it. YAML has known ambiguity in scalar parsing; SOON has a strict, unambiguous scalar grammar (SPEC §5).

How is this different from TOON? TOON pioneered token-oriented encoding and wins on flat tabular data. On nested data (L4–L8) TOON's list form expands beyond compact JSON — sometimes dramatically (L6 = -199%). SOON's shape/tuple mechanism is recursive by design, so nesting saves tokens instead of costing them.

Is the encoding lossless? Yes. decode(encode(x)) == x on every JSON-representable input, verified in CI by property-based tests and by 41 conformance fixtures. If you find a counter-example, open a bug — we freeze failures into the conformance suite.

What about model accuracy? Size is proven and reproducible. Accuracy on retrieval-style tasks is what a v0.2 harness will measure across current LLMs. Until it lands, treat SOON as size-proven and evaluate accuracy on your task — same discipline you'd apply to any prompt-engineering change.

Which LLMs support SOON? All of them. SOON is text; there's no model-side integration to install. Current-generation models (GPT-4o, Claude Sonnet/Opus 4.x, Gemini 2.x, Llama 3.x) read it reliably given a one-sentence prompt header. Older / smaller models benefit from a fuller instruction.

Do I have to change my producer code? No. Encode at the LLM boundary; the rest of your system keeps producing normal JSON.

Will there be a Rust / Go / … port? Yes — the conformance suite makes new ports verifiable from day one. See issue #7 for the Rust core we're planning to back Python via PyO3.


Contributing

We'd love your help. See CONTRIBUTING.md.

  • Spec first, fixtures are the contract. No mechanism lands in code before it lands in SPEC.md and conformance/.
  • Zero runtime dependencies in core libraries — tokenizer support stays behind optional extras.
  • Conventional Commits with scopes python, ts, spec, conformance.

Good first issues are labelled here. Ports to new languages are especially welcome.


License

MIT © Yasin Ughur. If SOON saves you tokens, star the repo — it helps others find it.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors