Automatically converts JSON in your Claude Code prompts to TOON format for 30-60% token savings.
TOON (Token-Oriented Object Notation) is a compact data format optimized for LLMs. Instead of repeating field names in every object, TOON declares them once and streams values as rows.
Example:
JSON (117 tokens):
{
"products": [
{"sku": "A123", "name": "Widget", "price": 9.99},
{"sku": "B456", "name": "Gadget", "price": 19.99}
]
}TOON (49 tokens - 58% reduction):
products[2]{sku,name,price}:
A123,Widget,9.99
B456,Gadget,19.99
- ✅ Automatically detects and converts JSON in prompts
- ✅ Handles JSON code blocks (
```json) - ✅ Handles inline JSON objects/arrays
- ✅ Smart detection: preserves JavaScript/TypeScript code
- ✅ Safe: fails gracefully, never breaks prompts
- ✅ Zero configuration after setup
- Claude Code
- Node.js (any recent version)
mkdir -p ~/.claude/hookscurl -sL https://esm.sh/@byjohann/toon@latest/es2015/toon.mjs -o ~/.claude/hooks/toon.mjscurl -sL https://gist.githubusercontent.com/maman/de31d48cd960366ce9caec32b569d32a/raw/json-to-toon.mjs -o ~/.claude/hooks/json-to-toon.mjs
chmod +x ~/.claude/hooks/json-to-toon.mjsAdd the following to your ~/.claude/settings.json:
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node ~/.claude/hooks/json-to-toon.mjs"
}
]
}
]
}
}If your settings.json already has a hooks section, merge the UserPromptSubmit configuration into it.
The hook runs automatically before each prompt is sent to Claude:
-
Detects JSON in your prompt:
- JSON code blocks with
```jsonidentifier - Plain code blocks containing valid JSON
- Inline JSON objects/arrays (30+ characters)
- JSON code blocks with
-
Converts to TOON format using the toon library
-
Preserves non-JSON content:
- JavaScript/TypeScript code (detected via keywords)
- Plain text
- Other code blocks
-
Sends modified prompt to Claude with reduced token count
You type:
Analyze this data:
\```json
{
"users": [
{"id": 1, "name": "Alice", "active": true},
{"id": 2, "name": "Bob", "active": false}
]
}
\```
Claude receives:
Analyze this data:
\```
users[2]{id,name,active}:
1,Alice,true
2,Bob,false
\```
You type:
Process this: {"products": [{"sku": "A123", "name": "Widget", "price": 9.99}], "total": 1}
Claude receives:
Process this: products[1]{sku,name,price}:
A123,Widget,9.99
total: 1
You type:
function getData() {
return { users: [] };
}Claude receives: (unchanged)
function getData() {
return { users: [] };
}- Verify Node.js is installed:
node --version - Check script exists:
ls -lh ~/.claude/hooks/json-to-toon.mjs - Check script is executable:
chmod +x ~/.claude/hooks/json-to-toon.mjs - Verify settings.json syntax is valid JSON
echo '{"prompt": "Test: {\"key\": \"value\", \"items\": [{\"a\": 1}, {\"a\": 2}]}"}' | node ~/.claude/hooks/json-to-toon.mjsExpected output:
Test: key: value
items[2]{a}:
1
2
- Hook implementation: This gist
- TOON format: @johannschopplich/toon
- Claude Code: Anthropic
MIT - Use freely, no attribution required.