---
name: toon-format
source: https://app.decimal.ai/s/toon-format@1/SKILL.md
source_sha256: 3998f9a5e3bd
---

# TOON serialization format

## Contract

When asked to serialize, encode, or represent structured data as text, emit **TOON**
(Token-Oriented Object Notation), not JSON and not YAML. TOON declares each uniform array's
fields once in a header and streams rows of comma-separated values, uses explicit `[N]`
length markers, and nests by 2-space indentation. Apply this whenever a data structure must
be written out as structured text (records, config, lists, agent payloads).

## Rules (the exact TOON form)

1. **Scalars — `key: value` with a single space after the colon.**
   `name: Alice`, `age: 30`, `active: true`. Types are inferred: bare `30` is a number,
   bare `true` a boolean, bare `null` is null.

2. **Nesting — 2-space indentation, no braces.** A key that owns a nested object is written
   as `parentKey:` on its own line (nothing after the colon), and its child fields are
   indented exactly 2 more spaces. Never wrap a nested object in `{ }`.

3. **Uniform array of objects — the tabular header.** Write ONE header line:
   `key[N]{field1,field2,...}:` — the array key, the element count `N` in square brackets,
   then the ordered field names once inside curly braces, then a colon. Each element is one
   indented row of comma-separated values in the SAME order as the braces field list. The
   field keys are declared once in the header and are NEVER repeated on the rows.

4. **Length marker is required and exact.** The number inside the square brackets is the
   real element count. Three rows → `[3]`. It is not optional and not a guess.

5. **Default delimiter is a comma — no marker after the count.** With the default comma
   delimiter the brackets hold only the number: write `items[4]{...}`, never `items[4,]{...}`.
   (A non-comma delimiter such as tab or pipe is declared right after the count, e.g. a pipe
   array is `items[4|]{a|b}:` — but prefer the default comma form.)

6. **Simple array of scalars — inline.** A list of scalar values is `key[N]: v1,v2,v3` — the
   key, the count in square brackets, a colon and single space, then the values comma-separated
   on the SAME line. Do not expand a scalar list to one-item-per-line or a JSON `[ ]` array.

7. **Quoting — quote ONLY when a bare value would be misread.** Wrap a string in double
   quotes when it is empty (`""`), has leading/trailing whitespace, equals `true`/`false`/`null`,
   looks numeric (all digits, or a decimal like `1.0`), contains the delimiter comma, or
   contains a `:` `"` `\`. Genuine numbers and booleans stay UNquoted.

8. **Code block tag.** When wrapping the output in a fenced block, tag it ```` ```toon ````.

## Worked examples (JSON default → TOON)

**Tabular array — declare fields once, stream rows:**
```
// base default (JSON — keys repeated every object)
{"users":[{"id":1,"name":"Alice","role":"admin"},{"id":2,"name":"Bob","role":"user"}]}
```
```toon
users[2]{id,name,role}:
  1,Alice,admin
  2,Bob,user
```

**Length marker + no trailing comma:**
```
// wrong: missing count, or a stray comma after it
users{id,name}:        users[2,]{id,name}:
```
```toon
users[2]{id,name}:
  1,Alice
  2,Bob
```

**Simple scalar array — inline, not a JSON list:**
```
// base default
{"tags":["red","green","blue"]}
```
```toon
tags[3]: red,green,blue
```

**Nesting — indentation, not braces:**
```
// base default
{"server":{"host":"web-1","limits":{"cpu":4,"mem":8}}}
```
```toon
server:
  host: web-1
  limits:
    cpu: 4
    mem: 8
```

**Quoting — only the ambiguous strings:**
```
// base default (over-quotes everything, or drops needed quotes)
{"code":"007","flag":"true","count":12}
```
```toon
code: "007"
flag: "true"
count: 12
```

## Edge cases & exceptions

- **Root is an array of objects.** Give the array a key or emit the bare tabular header at the
  root: `[3]{id,name}:` followed by the rows. Still declare fields once, still mark the count.
- **Empty array.** Write `key[0]:` (count zero, nothing after). Do not emit `[]`.
- **Empty string vs null.** An empty string is `key: ""` (quoted); a null is `key: null` (bare).
  They are different values — do not collapse one into the other.
- **Ragged / non-uniform objects.** If objects in a list do NOT share the same keys, they are
  not tabular — nest each one under a key instead of forcing a `{fields}` header.
- **Value with a comma or colon.** Quote it: `note: "hold, then review"`, `time: "12:30"`.
- **Number-like string that must stay a string** (zip, SKU, version): quote it — `zip: "02101"`.

## Do / Don't

- DO write the tabular header `key[N]{f1,f2}:` and put values-only rows beneath it.
- DON'T repeat the field keys on every row (that is JSON, and defeats TOON).
- DO put the exact element count in `[N]`.
- DON'T add a trailing comma or delimiter after the count for comma data (`[4]`, not `[4,]`).
- DO nest with 2 spaces and a bare `parentKey:` line.
- DON'T wrap nested objects in `{ }` or use 4-space / tab indentation.
- DO keep scalar arrays inline: `key[N]: a,b,c`.
- DON'T quote numbers/booleans that are genuinely numeric/boolean.
- DO quote a string that would otherwise parse as a number, boolean, or null.

## Common mistakes (the base's wrong defaults)

- Emitting JSON or YAML instead of TOON — the single most common miss.
- Repeating `{"id":..,"name":..}` per element instead of one `{id,name}` header + value rows.
- Dropping the `[N]` length marker, or writing the count wrong.
- Writing `[N,]` with a stray comma after the count when the delimiter is already comma.
- Using braces `{ }` for nested objects instead of 2-space indentation.
- Over-quoting every value, or failing to quote a numeric-looking string like `"02101"`.

## Quick checklist

- [ ] Output is TOON, not JSON/YAML.
- [ ] Uniform arrays use `key[N]{fields}:` with fields declared once; rows are values-only.
- [ ] Every array carries an exact `[N]` count; comma arrays have no marker after the count.
- [ ] Scalar arrays are inline `key[N]: a,b,c`.
- [ ] Nesting is 2-space indented, no braces; scalars are `key: value` (one space).
- [ ] Strings quoted only when numeric-looking / boolean-like / containing the delimiter.
