Toon Format
Expert skill for Token-Oriented Object Notation (TOON) — compact, schema-aware JSON encoding for LLM prompts that reduces tokens by ~40%.
- Skill ID
- reason-machines/trending-skills/toon-format
- Publisher
- reason-machines
- Repository
- trending-skills
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
reason-machines/trending-skills/toon-formatInstalls these files- SKILL.md
What this skill tells the agent
Token-Oriented Object Notation (TOON)
Skill by ara.so — Daily 2026 Skills collection.
TOON is a compact, human-readable encoding of the JSON data model that minimizes tokens for LLM input. It combines YAML-style indentation for nested objects with CSV-style tabular layout for uniform arrays, achieving ~40% token reduction while maintaining or improving LLM comprehension accuracy.
Installation
# npm
npm install @toon-format/toon
# pnpm
pnpm add @toon-format/toon
# yarn
yarn add @toon-format/toonCLI
# Install globally
npm install -g @toon-format/toon
# Convert JSON file to TOON
toon encode input.json
toon encode input.json -o output.toon
# Convert TOON back to JSON
toon decode input.toon
toon decode input.toon -o output.json
# Pipe support
cat data.json | toon encode
cat data.toon | toon decode
# Pretty-print JSON output
toon decode input.toon --pretty
# Show token count comparison
toon encode input.json --statsCore API
encode / stringify
import { encode, decode } from '@toon-format/toon';
// Basic encoding (JSON → TOON string)
const data = {
context: {
task: 'Our favorite hikes together',
location: 'Boulder',
season: 'spring_2025',
},
friends: ['ana', 'luis', 'sam'],
hikes: [
{ id: 1, name: 'Blue Lake Trail', distanceKm: 7.5, elevationGain: 320, companion: 'ana', wasSunny: true },
{ id: 2, name: 'Ridge Overlook', distanceKm: 9.2, elevationGain: 540, companion: 'luis', wasSunny: false },
{ id: 3, name: 'Wildflower Loop', distanceKm: 5.1, elevationGain: 180, companion: 'sam', wasSunny: true },
],
};
const toon = encode(data);
console.log(toon);
// context:
// task: Our favorite hikes together
// location: Boulder
// season: spring_2025
// friends[3]: ana,luis,sam
// hikes[3]{id,name,distanceKm,elevationGain,companion,wasSunny}:
// 1,Blue Lake Trail,7.5,320,ana,true
// 2,Ridge Overlook,9.2,540,luis,false
// 3,Wildflower Loop,5.1,180,sam,truedecode / parse
import { decode } from '@toon-format/toon';
const toonString = `
context:
task: Our favorite hikes together
location: Boulder
friends[2]: ana,luis
hikes[2]{id,name,distanceKm}:
1,Blue Lake Trail,7.5
2,Ridge Overlook,9.2
`;
const parsed = decode(toonString);
// Returns the original JavaScript object
console.log(parsed.hikes[0].name); // 'Blue Lake Trail'Encoding options
import { encode } from '@toon-format/toon';
const toon = encode(data, {
// Force all arrays to tabular format (default: auto-detect uniform arrays)
tabular: 'always',
// Never use tabular format
// tabular: 'never',
// Indent size for nested objects (default: 2)
indent: 2,
// Quote strings that contain special characters (default: auto)
quoting: 'auto',
});Format Overview
Primitive scalars
TOON encodes scalars the same way as YAML — unquoted when unambiguous:
name: Alice
age: 30
active: true
score: 98.6
nothing: nullNested objects (YAML-style indentation)
user:
name: Alice
address:
city: Boulder
zip: 80301Flat arrays (scalar items)
Square brackets declare the array length, values are comma-separated:
tags[3]: typescript,llm,serialization
scores[4]: 10,20,30,40Uniform object arrays (tabular format)
Curly braces declare the field headers; each subsequent indented line is a row:
employees[3]{id,name,department,salary}:
1,Alice,Engineering,95000
2,Bob,Marketing,72000
3,Carol,Engineering,102000Quoting rules
Values containing commas, colons, or newlines are quoted:
notes[2]: "hello, world","line1\nline2"
messages[1]{from,text}:
alice,"See you at 3:00, okay?"Mixed nesting
company:
name: Acme Corp
founded: 1987
offices[2]: NYC,SF
teams[2]{name,headcount}:
Engineering,45
Marketing,20Using TOON with LLMs
Direct prompt injection
import { encode } from '@toon-format/toon';
import OpenAI from 'openai';
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
async function queryWithToon(data: unknown, question: string) {
const toon = encode(data);
const response = await client.chat.completions.create({
model: 'gpt-4o-mini',
messages: [
{
role: 'system',
content: [
'You are a data analyst. The user will provide data in TOON format.',
'TOON is a compact encoding of JSON: indentation = nesting,',
'key[N]: v1,v2 = array of N scalars,',
'key[N]{f1,f2}: rows = array of N objects with fields f1, f2.',
].join(' '),
},
{
role: 'user',
content: `Data:\n\`\`\`\n${toon}\n\`\`\`\n\nQuestion: ${question}`,
},
],
});
return response.choices[0].message.content;
}
// Usage
const employees = [
{ id: 1, name: 'Alice', dept: 'Eng', salary: 95000 },
{ id: 2, name: 'Bob', dept: 'Marketing', salary: 72000 },
];
const answer = await queryWithToon(
{ employees },
'Who has the highest salary?'
);Anthropic / Claude
import { encode } from '@toon-format/toon';
import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
async function analyzeWithClaude(data: unknown, prompt: string) {
const toon = encode(data);
const message = await client.messages.create({
model: 'claude-haiku-4-5-20251001',
max_tokens: 1024,
system:
'Data is in TOON format: indented = nested objects, key[N]: vals = scalar array, key[N]{fields}: rows = object array.',
messages: [
{
role: 'user',
content: `\`\`\`toon\n${toon}\n\`\`\`\n\n${prompt}`,
},
],
});
return message.content[0].type === 'text' ? message.content[0].text : null;
}Token count comparison utility
import { encode } from '@toon-format/toon';
import { encode as gptEncode } from 'gpt-tokenizer';
function compareTokens(data: unknown) {
const jsonStr = JSON.stringify(data);
const toonStr = encode(data);
const jsonTokens = gptEncode(jsonStr).length;
const toonTokens = gptEncode(toonStr).length;
const savings = (((jsonTokens - toonTokens) / jsonTokens) * 100).toFixed(1);
console.log(`JSON: ${jsonTokens} tokens`);
console.log(`TOON: ${toonTokens} tokens`);
console.log(`Saved: ${savings}%`);
return { jsonTokens, toonTokens, savings: parseFloat(savings) };
}Common Patterns
Batch API calls with TOON
import { encode } from '@toon-format/toon';
// Encode each record separately for independent LLM calls
function encodeRecords<T>(records: T[]): string[] {
return records.map((r) => encode(r));
}
// Encode all records as one TOON document (most efficient for bulk)
function encodeAll<T>(records: T[], key = 'records'): string {
return encode({ [key]: records });
}RAG / retrieval context injection
import { encode } from '@toon-format/toon';
interface SearchResult {
id: string;
title: string;
snippet: string;
score: number;
url: string;
}
function buildRagContext(results: SearchResult[]): string {
// TOON is ideal here — uniform objects collapse into a compact table
return encode({ results });
}
// Output:
// results[5]{id,title,snippet,score,url}:
// doc1,Introduction to TOON,...,0.95,https://...
// doc2,TOON vs JSON,...,0.87,https://...Streaming encode for large datasets
import { encode } from '@toon-format/toon';
import { createReadStream, createWriteStream } from 'fs';
// For large JSON files: read → parse → encode → write
async function convertFile(inputPath: string, outputPath: string) {
const raw = await fs.promises.readFile(inputPath, 'utf-8');
const data = JSON.parse(raw);
const toon = encode(data);
await fs.promises.writeFile(outputPath, toon, 'utf-8');
const jsonBytes = Buffer.byteLength(raw);More from reason-machines
Use this skill in a project
Open any RiverX project, search the Skills panel for reason-machines/trending-skills/toon-format, and install it in one click.
