A Clojure/ClojureScript implementation of Token-Oriented Object Notation – a compact, human-readable serialization format designed for passing structured data to Large Language Models with significantly reduced token usage.
TOON achieves 49% fewer tokens than formatted JSON (28% vs compact JSON) while maintaining explicit structure that helps LLMs parse and validate data reliably. It's intended for LLM input as a lossless, drop-in representation of JSON data.
Specification: This library implements TOON v1.3 specification Reference Implementation: TypeScript/JavaScript
When working with Large Language Models, token efficiency directly impacts cost, context window usage, and processing speed. LLM tokens still cost money – and standard JSON is verbose and token-expensive.
TOON's sweet spot is uniform arrays of objects – multiple fields per row, same structure across items. It borrows YAML's indentation-based structure for nested objects and CSV's tabular format for uniform data rows, then optimizes both for token efficiency in LLM contexts.
Based on benchmarks using the GPT-5 o200k_base tokenizer:
Real-world examples:
TOON excels at:
JSON is better for:
CSV is more compact for:
com.vadelabs/toon {:mvn/version "2025.11.05-43"}
[com.vadelabs/toon "2025.11.05-43"]
(require '[com.vadelabs.toon.interface :as toon])
;; Encode Clojure data to TOON
(toon/encode {:name "Alice" :age 30 :tags ["dev" "rust"]})
;=> "name: Alice\nage: 30\ntags[2]: dev,rust"
;; Decode TOON to Clojure data
(toon/decode "name: Alice\nage: 30\ntags[2]: dev,rust")
;=> {"name" "Alice", "age" 30.0, "tags" ["dev" "rust"]}
JSON:
{
"name": "Alice",
"age": 30,
"active": true
}
TOON:
name: Alice
age: 30
active: true
JSON:
{
"user": {
"name": "Alice",
"email": "alice@example.com"
}
}
TOON:
user:
name: Alice
email: alice@example.com
JSON:
{
"tags": ["reading", "gaming", "coding"]
}
TOON:
tags[3]: reading,gaming,coding
This is TOON's sweet spot – uniform arrays of objects with consistent fields:
JSON:
{
"users": [
{"id": 1, "name": "Alice", "role": "admin"},
{"id": 2, "name": "Bob", "role": "user"}
]
}
TOON:
users[2]{id,name,role}:
1,Alice,admin
2,Bob,user
The tabular format eliminates repeated keys, providing significant token savings for large datasets.
For non-uniform data, TOON uses list format:
TOON:
items[3]:
- name: Laptop
price: 999
- name: Mouse
price: 29
- name: Keyboard
price: 79
encodeEncodes Clojure data structures to TOON format.
(encode input)
(encode input options)
Parameters:
input - Any Clojure value (normalized to JSON-compatible types)options - Optional map:
:indent - Spaces per indentation level (default: 2):delimiter - Array value delimiter: "," (default), "\t", or "|":length-marker - Array length marker: "#" or false (default: false)Returns: String in TOON format
Examples:
;; Basic encoding
(encode {:name "Ada" :tags ["reading" "gaming"]})
;=> "name: Ada\ntags[2]: reading,gaming"
;; Custom delimiter
(encode {:tags ["a" "b" "c"]} {:delimiter "\t"})
;=> "tags[3\t]: a\tb\tc"
;; Length marker prefix
(encode {:items [1 2 3]} {:length-marker "#"})
;=> "items[#3]: 1,2,3"
;; Tabular array format
(encode [{:id 1 :name "Alice"}
{:id 2 :name "Bob"}])
;=> "[2]{id,name}:\n 1,Alice\n 2,Bob"
decodeDecodes TOON format to Clojure data structures.
(decode input)
(decode input options)
Parameters:
input - String in TOON formatoptions - Optional map:
:indent - Spaces per indentation level (default: 2):strict - Enable strict validation (default: true)Returns: Clojure data structure (maps, vectors, primitives)
Examples:
;; Basic decoding
(decode "name: Ada\ntags[2]: reading,gaming")
;=> {"name" "Ada", "tags" ["reading" "gaming"]}
;; Tabular array
(decode "[2]{id,name}:\n 1,Alice\n 2,Bob")
;=> [{"id" 1.0, "name" "Alice"} {"id" 2.0, "name" "Bob"}]
;; Inline array
(decode "[3]: 1,2,3")
;=> [1.0 2.0 3.0]
;; Relaxed mode (allows tabs, inconsistent indentation)
(decode "name: Ada" {:strict false})
;=> {"name" "Ada"}
string: Hello World
number: 42
float: 3.14
boolean: true
nil: null
Strings are quoted when they contain special characters:
comma: "a,b"
colon: "key:value"
reserved: "true"
newline: "line1\nline2"
Key-value pairs separated by colons:
name: Alice
age: 30
Nested objects use indentation:
user:
name: Alice
email: alice@example.com
Inline format (primitives):
tags[3]: reading,gaming,coding
Tabular format (objects with same keys):
[3]{id,name}:
1,Alice
2,Bob
3,Carol
List format (mixed items):
items[2]:
- name: Laptop
price: 999
- name: Mouse
price: 29
Custom delimiter:
tags[3|]: a|b|c
tags[3\t]: a\tb\tc
Length marker:
items[#3]: 1,2,3
TOON normalizes Clojure types to JSON-compatible values:
:name → "name"#{3 1 2} → [1 2 3]42 → 42.0{:a 1} → {"a" 1.0}# Run all Clojure tests
bb test
# Run all tests (Clojure + Babashka)
bb test:all
# Run CI pipeline with tests
bb ci
# Generate test coverage report
bb coverage
The library includes:
Coverage reports are generated in target/coverage/ including:
target/coverage/index.htmltarget/coverage/codecov.jsonWe welcome contributions! Please see CONTRIBUTING.md for:
git checkout -b feature/my-featurebb testgit commit -m "add feature X"This implementation follows the TOON v1.3 specification (2025-10-31).
For detailed format rules, edge cases, and conformance requirements, see:
Detailed benchmarks comparing TOON against JSON, YAML, XML, and CSV across multiple datasets and LLM models are available in the reference implementation repository.
Key findings:
Token counts are measured using the GPT-5 o200k_base tokenizer. Actual savings vary by model and tokenizer.
Note: When implementing TOON in other languages, follow the specification to ensure compatibility. The conformance tests provide language-agnostic validation.
Copyright © 2025 Vade Labs Pvt. Ltd.
Distributed under the MIT License. See LICENSE for details.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |