Skip to main content

TOON Format

TOON (Tabular Object-Oriented Notation) is SochDB's native, schema-aware data format. It is compact and optimized for LLM consumption — "the native format for SochDB, like JSON is for MongoDB."

TOON is the native query-result / output format: SochQL results, the MCP tools (sochdb_query, sochdb_context_query), and the context-query / token-budget pipeline all emit TOON by default.

Token efficiency

TOON typically uses 40-66% fewer tokens than equivalent JSON for tabular data. This is a measured range across real workloads, not a code-level guarantee — the savings depend on field names, value sizes, and the tokenizer.


Format

The text format is a one-line header followed by rows:

name[count]{field1,field2,...}:
row1
row2
...
  • name — table / collection name (identifier)
  • [count] — number of rows
  • {field1,field2,...} — comma-separated field names
  • : — terminates the header; rows follow

The header is parsed in the core engine (SochTable::parse_header in sochdb-core/src/soch.rs) by locating [, ], {, }, and the trailing :. The core SochTable::format() emits the header and then one row per line, separated by newlines.

Row separator differs by layer

The core engine (SochTable::format()) writes one row per line (newline-separated). The Python SDK helper (Database.to_toon, see below) packs the rows onto a single line, separated by ;. Both are valid TOON; the header grammar is identical. The examples below note which convention they use.

Examples

Simple table (core / newline rows):

users[3]{id,name,email}:
1,Alice,alice@example.com
2,Bob,bob@example.com
3,Charlie,charlie@example.com

With explicit field types — append :type to a field name:

orders[2]{id:uint,amount:float,status:text}:
1001,99.99,pending
1002,149.50,shipped

Python SDK helper (;-separated rows on one line):

users[2]{name,email}:Alice,alice@ex.com;Bob,bob@ex.com

Type system

Field types are optional. When omitted, fields default to text. The core SochType enum (sochdb-core/src/soch.rs) and its parse function recognize the following type strings:

Type stringSochType variantNotes
nullNullNull value
boolBoolBoolean
int / i64IntSigned 64-bit integer
uint / u64UIntUnsigned 64-bit integer
float / f64Float64-bit floating point
text / stringTextUTF-8 string (default)
binary / bytesBinaryBinary data
array(T)Array(T)Homogeneous array of T
ref(table)Ref(table)Reference to another table
T?Optional(T)Nullable T

Composite forms compose: array(int), int?, ref(users). There is no dedicated vector type tag in SochType — vectors are represented as arrays of floats.

Optional / nullable fields

Append ? to make a field nullable:

users[2]{id:uint,email:text,phone:text?}:
1,alice@ex.com,555-0100
2,bob@ex.com,null

Codec API (Rust)

The core text and binary codecs live in sochdb-core/src/soch_codec.rs. The text codec wraps the official toon-format crate; the binary codec is hand-rolled.

use sochdb_core::soch::SochTable;
use sochdb_core::soch_codec::{
SochDocument, SochTextEncoder, SochTextParser, SochDbBinaryCodec,
};

// --- Simple table helper (soch.rs) ---
let text = "users[2]{id,name}:\n1,Alice\n2,Bob";
let table = SochTable::parse(text)?; // -> SochTable
let out = table.format(); // -> String (TOON text)

// --- Document codec (soch_codec.rs) ---
let doc: SochDocument = SochTextParser::parse(text)?;
let text_out: String = SochTextEncoder::encode(&doc);

// --- Binary codec ---
let bytes: Vec<u8> = SochDbBinaryCodec::encode(&doc);
let doc2: SochDocument = SochDbBinaryCodec::decode(&bytes)?;
note

There is no SochCodec facade type. Use SochTable::format() / SochTable::parse() for the simple table representation, or SochTextEncoder / SochTextParser / SochDbBinaryCodec for the SochDocument representation.


Binary format

For internal storage and high-performance scenarios, SochDbBinaryCodec encodes a SochDocument to bytes. The layout is not a fixed-size header — it is the magic bytes, a varint schema version, then the value tree:

[ "TOON" magic : 4 bytes ] [ schema version : varint ] [ value tree ... ]
  • Magic: TOON_MAGIC = [0x54, 0x4F, 0x4F, 0x4E] (ASCII "TOON").
  • Schema version: a varint (current version is 1).
  • Value tree: type-tagged values; integers, string lengths, array/object/ binary lengths, and ref ids are all varint-encoded.

Type tags (SochTypeTag, #[repr(u8)])

enum SochTypeTag {
Null = 0x00,
False = 0x01,
True = 0x02,
PosFixint = 0x10, // 0-15 embedded in 0x10-0x1F
NegFixint = 0x20, // -16 to -1 embedded in 0x20-0x2F
Int8 = 0x30,
Int16 = 0x31,
Int32 = 0x32,
Int64 = 0x33,
Float32 = 0x40,
Float64 = 0x41,
FixStr = 0x50, // 0-15 length embedded in lower nibble
Str8 = 0x60, // 1-byte varint length prefix
Str16 = 0x61,
Str32 = 0x62,
Array = 0x70,
Ref = 0x80,
Object = 0x90,
Binary = 0xA0,
UInt = 0xB0, // unsigned integer (varint)
}

Varint encoding

Lengths and large integers use LEB128-style variable-length encoding (write_varint / read_varint): 7 payload bits per byte, high bit as the continuation flag.

Value rangeBytes
0 – 1271
128 – 163832
16384 – 20971513
......

Using TOON from the SDKs

The pure-Python SDK (pip install sochdb) exposes Database.to_toon / Database.from_toon static helpers, and selects the wire/context format via the WireFormat and ContextFormat enums. These helpers use the ;-separated-rows convention.

from sochdb import Database, WireFormat, ContextFormat

records = [
{"id": 1, "name": "Alice", "email": "alice@ex.com"},
{"id": 2, "name": "Bob", "email": "bob@ex.com"},
]

# Encode to TOON (optionally project a subset of fields)
toon = Database.to_toon("users", records, ["name", "email"])
# -> "users[2]{name,email}:Alice,alice@ex.com;Bob,bob@ex.com"

# Parse TOON back to structured data
name, fields, parsed = Database.from_toon(toon)
# name == "users"; fields == ["name", "email"]
# parsed == [{"name": "Alice", "email": "alice@ex.com"}, ...]

# Select the output format for queries / context packaging
fmt = WireFormat.TOON # default; also JSON, COLUMNAR
ctx = ContextFormat.TOON # default; also JSON, MARKDOWN

WireFormat values are TOON (default), JSON, COLUMNAR. ContextFormat values are TOON (default), JSON, MARKDOWN.


Where TOON is used

  • SochQL query results are returned in TOON (soch_ql.rs: "Query result in TOON format").
  • MCP tools emit TOON by default. sochdb_query returns results in TOON, and sochdb_context_query defaults to TOON output (both also accept json and markdown via the format argument). MCP tool names use underscores.
  • Context-query / token-budget paths in sochdb-query (context_query.rs, token_budget.rs, streaming_context.rs) assemble LLM context in TOON. The context-query OutputFormat is Soch (TOON, default), Json, or Markdown.
  • Storage uses TOON for columnar emission via SochCursor ("Cursor for iterating over columnar data and emitting TOON format").

Best practices

For LLM context

  1. Prefer TOON for tabular data in prompts — it is the default and the most token-efficient of the available formats.
  2. Short field names reduce tokens further.
  3. Omit types when they are inferable; they default to text.

For storage

  1. Use the binary codec (SochDbBinaryCodec) for internal storage.
  2. Use the text codec for debugging and logging.

Token optimization

# More tokens (explicit types)
users[2]{id:uint,name:text,email:text}:
1,Alice,alice@ex.com
2,Bob,bob@ex.com

# Fewer tokens (inferred types)
users[2]{id,name,email}:
1,Alice,alice@ex.com
2,Bob,bob@ex.com

# Even fewer (short names)
u[2]{i,n,e}:
1,Alice,alice@ex.com
2,Bob,bob@ex.com

See Also