Every token an agent spends reading CLI output is a token it can’t spend reasoning. incur defaults to TOON (Terse Object Oriented Notation)—a format that’s as readable as YAML but with no quoting, no braces, and no redundant syntax.
What is TOON?
TOON is a data serialization format designed for LLMs and humans. It uses up to 60% fewer tokens compared to JSON while remaining easy to parse.
Comparison
JSON output (verbose)
$ my-cli hikes --location Boulder --season spring_2025
{
"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
}
]
}
TOON output (concise)
$ my-cli hikes --location Boulder --season spring_2025
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,true
Token Savings
The TOON format eliminates:
- Quotation marks around keys and strings
- Braces
{} for objects
- Brackets
[] around arrays (replaced with inline headers)
- Redundant commas between object properties
Result: 40-60% fewer tokens for typical CLI output.
incur supports multiple output formats. Switch between them using global options.
| Format | Description | Use Case |
|---|
toon | Terse Object Oriented Notation (default) | Agent consumption, human readability |
json | Standard JSON with 2-space indentation | Programmatic parsing, debugging |
yaml | YAML format | Human editing, config files |
md | Markdown tables | Documentation, reports |
jsonl | JSON Lines (streaming) | Log aggregation, streaming data |
Using --format
$ my-cli status --format json
{
"clean": true
}
$ my-cli status --format yaml
clean: true
$ my-cli status --format md
| Key | Value |
|-------|-------|
| clean | true |
Using --json shorthand
$ my-cli status --json
{
"clean": true
}
Implementation
TOON output is automatic. Just return data from your command:
import { Cli, z } from 'incur'
Cli.create('my-cli', { description: 'My CLI' })
.command('status', {
description: 'Show repo status',
run() {
return { clean: true, branch: 'main', ahead: 0 }
},
})
.serve()
Default output (TOON)
$ my-cli status
clean: true
branch: main
ahead: 0
JSON output
$ my-cli status --json
{
"clean": true,
"branch": "main",
"ahead": 0
}
Markdown Tables
The md format automatically renders objects as tables:
Key-Value Tables
Cli.create('my-cli', { description: 'My CLI' })
.command('config', {
run() {
return { name: 'my-app', version: '1.0.0', author: 'Alice' }
},
})
.serve()
$ my-cli config --format md
| Key | Value |
|---------|--------|
| name | my-app |
| version | 1.0.0 |
| author | Alice |
Columnar Tables
Arrays of objects become columnar tables:
Cli.create('my-cli', { description: 'My CLI' })
.command('users', {
run() {
return {
users: [
{ id: 1, name: 'Alice', role: 'admin' },
{ id: 2, name: 'Bob', role: 'user' },
],
}
},
})
.serve()
$ my-cli users --format md
## users
| id | name | role |
|----|-------|-------|
| 1 | Alice | admin |
| 2 | Bob | user |
JSONL for Streaming
When streaming data, use --format jsonl for line-delimited JSON:
Cli.create('my-cli', { description: 'My CLI' })
.command('logs', {
async *run() {
yield { timestamp: Date.now(), level: 'info', message: 'Starting' }
yield { timestamp: Date.now(), level: 'info', message: 'Processing' }
yield { timestamp: Date.now(), level: 'info', message: 'Done' }
},
})
.serve()
$ my-cli logs --format jsonl
{"type":"chunk","data":{"timestamp":1709856000000,"level":"info","message":"Starting"}}
{"type":"chunk","data":{"timestamp":1709856001000,"level":"info","message":"Processing"}}
{"type":"chunk","data":{"timestamp":1709856002000,"level":"info","message":"Done"}}
Set a default format for your CLI:
import { Cli, z } from 'incur'
Cli.create('my-cli', {
description: 'My CLI',
format: 'json', // Default to JSON instead of TOON
})
.command('status', {
run() {
return { clean: true }
},
})
.serve()
$ my-cli status
{
"clean": true
}
Users can still override with --format or --json.
The formatter implementation is in src/Formatter.ts:
import { format } from 'incur/Formatter'
const data = { name: 'Alice', role: 'admin' }
format(data, 'toon') // → "name: Alice\nrole: admin"
format(data, 'json') // → "{\n \"name\": \"Alice\",\n \"role\": \"admin\"\n}"
format(data, 'yaml') // → "name: Alice\nrole: admin\n"
format(data, 'md') // → "| Key | Value |..."
Use TOON (the default) for the best token efficiency and agent experience.