Skip to content

TOON Format

TOON — Token-Oriented Object Notation — is a compact, human-readable encoding for structured data destined for an LLM. It carries the same information as JSON in noticeably fewer tokens by hoisting repeated object keys into a single header row.

JSON:

{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}

The same value in TOON:

users[2]{id,name}:
1,Alice
2,Bob

The array length and the field names are declared once; each row is just the values.

TOON is an external specification, not a Crucible invention. Crucible encodes it through the oq crate, which wraps toon-format — the reference Rust implementation of TOON v3.0.

Where Crucible uses it

Lua tool results served over cru mcp. The MCP server (cru mcp, and the daemon-managed server it mirrors) discovers Lua and Fennel tools from the plugin directories by their spec-table declarations, and encodes their object or array results as TOON before returning them to the connected client (crates/crucible-daemon/src/tools/toon_response.rs, called from tools/extended_mcp_server.rs). Scalar results (strings, numbers, booleans) pass through as plain text.

That is the only path that encodes TOON. A tool declared in a plugin’s tools spec table and called from a Crucible chat session is dispatched by PluginToolExecutor (crates/crucible-daemon/src/plugin_tools.rs), which returns the Lua value converted straight to JSON. Built-in Rust tools return JSON too.

The formatter is content-aware: long fields such as a file’s contents or a command’s stdout are lifted out into readable blocks rather than being packed into a row, and the strategy is chosen from the tool’s name (a name containing search/find/grep is formatted as search results, and so on). If encoding fails for any reason, the value falls back to pretty-printed JSON — a tool result is never lost to a formatting error.

Producing TOON from Lua

The cru.oq module exposes the encoder directly, alongside the other formats it handles:

local rows = {
{ id = 1, name = "Alice" },
{ id = 2, name = "Bob" },
}
print(cru.oq.toon({ users = rows })) -- TOON string
print(cru.oq.convert(rows, "yaml")) -- any supported format by name
print(cru.oq.format({ users = rows })) -- smart TOON, long fields extracted
print(cru.oq.format(result, { tool = "search_notes" })) -- tool-aware formatting

cru.oq also parses (parse, parse_as, detect), re-encodes (cru.json.encode, with { pretty = true } for indented output, yaml, toml), and runs jq-style queries (query). See Lua Runtime API for the wider cru.* surface.

See Also