terset
Color theme

TERse SETs.

Same data.
Fewer tokens.

It writes a set of records as one terse table, so a model reads the same data with fewer tokens.

Package manager
pnpm add @stackdeck/terset
356tokens
{"orders":[{"id":"ORD-20001","customer":"Ana Silva","status":"paid","currency":"USD","ship":{"city":"Lisbon","zip":"1100-148"},"lines":[{"sku":"A-100","qty":2,"price":9.99}],"total":19.98},{"id":"ORD-20002","customer":"Ben Okafor","status":"shipped","currency":"USD","ship":{"city":"Lagos","zip":"101233"},"lines":[{"sku":"B-220","qty":1,"price":24.5},{"sku":"D-400","qty":3,"price":7.25}],"total":46.25},{"id":"ORD-20003","customer":"Chen Kim","status":"delivered","currency":"USD","ship":{"city":"Osaka"},"lines":[{"sku":"E-555","qty":1,"price":39.9}],"total":39.9,"note":"Gift wrap"},{"id":"ORD-20004","customer":"Dara Patel","status":"refunded","currency":"USD","ship":null,"lines":[],"total":0},{"id":"ORD-20005","customer":"Eli Rossi","status":"paid","currency":"USD","lines":[{"sku":"C-310","qty":2,"price":15}],"total":30},{"id":"ORD-20006","customer":"Fatima Garcia","status":"shipped","currency":"USD","ship":{"city":"Austin","zip":"78701"},"lines":[{"sku":"A-100","qty":1,"price":9.99},{"sku":"E-555","qty":1,"price":39.9}],"total":49.89}]}
  • Terset325
  • JSON356
  • TOON, best variant405

8.7% fewer tokens than JSON. 19.8% fewer tokens than TOON.

Six orders, counted with o200k_base. JSON is compact. Terset counts include the RULES sentence, and the text round trips exactly.

1of 8

JSON repeats every key on every row.

71key names in the 6 orders as JSON
37key names in the same orders as Terset

The 8 field names, written onceid customer status currency ship lines total note

Keys inside nested values stay JSON, so they still repeat. The tally counts them.

How often each key name is written, as JSON and as Terset
KeyWritten in JSONIn Terset
orders11
id61
customer61
status61
currency61
ship51
city44
zip33
lines61
sku77
qty77
price77
total61
note11
Total7137

2of 8

Paste rows. Get the table.

Sample data
Round trip exactRound trip failedToo longWaiting for valid JSONNeeds an object or arrayCannot encodeRound trip exact
Edits run live
Terset, from the real encoder
orders:
id	customer	status	currency	ship	lines	total	note
ORD-20001	Ana Silva	paid	USD	{"city":"Lisbon","zip":"1100-148"}	[{"sku":"A-100","qty":2,"price":9.99}]	19.98	
ORD-20002	Ben Okafor	shipped	USD	{"city":"Lagos","zip":"101233"}	[{"sku":"B-220","qty":1,"price":24.5},{"sku":"D-400","qty":3,"price":7.25}]	46.25	
ORD-20003	Chen Kim	delivered	USD	{"city":"Osaka"}	[{"sku":"E-555","qty":1,"price":39.9}]	39.9	Gift wrap
ORD-20004	Dara Patel	refunded	USD	null	[]	0	
ORD-20005	Eli Rossi	paid	USD		[{"sku":"C-310","qty":2,"price":15}]	30	
ORD-20006	Fatima Garcia	shipped	USD	{"city":"Austin","zip":"78701"}	[{"sku":"A-100","qty":1,"price":9.99},{"sku":"E-555","qty":1,"price":39.9}]	49.89	
Terset686 B
Compact JSON1,051 B

Sizes return when the JSON parses.Live sizes are in bytes. Token counts show for the samples.Sample tokens, o200k_base: Terset 325, JSON 356, TOON 405. Claude: Terset 500, JSON 553, TOON 530. Sample tokens, o200k_base: Terset 295, JSON 420, TOON 541. Claude: Terset 400, JSON 637, TOON 671. Sample tokens, o200k_base: Terset 139, JSON 99, TOON 118. Claude: Terset 225, JSON 153, TOON 148.

3of 8

Six marks carry all the structure.

The six orders, as the model reads them
orders:
id	customer	status	currency	ship	lines	total	note
ORD-20001	Ana Silva	paid	USD	{"city":"Lisbon","zip":"1100-148"}	[{"sku":"A-100","qty":2,"price":9.99}]	19.98	
ORD-20002	Ben Okafor	shipped	USD	{"city":"Lagos","zip":"101233"}	[{"sku":"B-220","qty":1,"price":24.5},{"sku":"D-400","qty":3,"price":7.25}]	46.25	
ORD-20003	Chen Kim	delivered	USD	{"city":"Osaka"}	[{"sku":"E-555","qty":1,"price":39.9}]	39.9	Gift wrap
ORD-20004	Dara Patel	refunded	USD	null	[]	0	
ORD-20005	Eli Rossi	paid	USD		[{"sku":"C-310","qty":2,"price":15}]	30	
ORD-20006	Fatima Garcia	shipped	USD	{"city":"Austin","zip":"78701"}	[{"sku":"A-100","qty":1,"price":9.99},{"sku":"E-555","qty":1,"price":39.9}]	49.89	
A user named 42
team: core
users:
id	name	role	tags
u1	Ada	null	
u2		ops	
u3	"42"		["new"]
  1. 1orders:A root key on its own line. A list of records follows.
  2. 2id customer ...The field names, written once, split by tabs.
  3. 3ORD-20001A bare id header means each row starts with its id as plain text.
  4. 4{"city":"Lisbon"}Nested values stay compact JSON inside the cell.
  5. 5 empty cellAn empty cell means the field is absent. null stays null.
  6. 6"42"Text that looks like a number, boolean or null gets JSON quotes.

4of 8

Real rows are messy. The table holds them.

ANo zip for Osaka

"ship": {"city": "Osaka"}

Row 3, ship cell

ORD-20003Chen KimdeliveredUSD{"city":"Osaka"}[{"sku":"E-555","qty":1,"price":39.9}]39.9Gift wrap

BShip is null

"ship": null, "lines": []

Row 4, ship cell

ORD-20004Dara PatelrefundedUSDnull[]0

CNo ship key at all

"status": "paid", no "ship", "lines": […]

Row 5, empty ship cell

ORD-20005Eli RossipaidUSD[{"sku":"C-310","qty":2,"price":15}]30

DA note on one order only

"total": 39.9, "note": "Gift wrap"

Row 3, last cell

ORD-20003Chen KimdeliveredUSD{"city":"Osaka"}[{"sku":"E-555","qty":1,"price":39.9}]39.9Gift wrap

57lines as TOON
8lines as Terset

5of 8

Decode it. Get the same JSON back.

orders.jsoninput
{
  "orders": [
    {
      "id": "ORD-20001",
      "customer": "Ana Silva",
      "status": "paid",
      "currency": "USD",
      "ship": {
        "city": "Lisbon",
        "zip": "1100-148"
      },
      "lines": [
        {
          "sku": "A-100",
          "qty": 2,
          "price": 9.99
        }
      ],
      "total": 19.98
    },
    {
      "id": "ORD-20002",
      "customer": "Ben Okafor",
      "status": "shipped",
      "currency": "USD",
      "ship": {
        "city": "Lagos",
        "zip": "101233"
      },
      "lines": [
        {
          "sku": "B-220",
          "qty": 1,
          "price": 24.5
        },
        {
          "sku": "D-400",
          "qty": 3,
          "price": 7.25
        }
      ],
      "total": 46.25
    },
    {
      "id": "ORD-20003",
      "customer": "Chen Kim",
      "status": "delivered",
      "currency": "USD",
      "ship": {
        "city": "Osaka"
      },
      "lines": [
        {
          "sku": "E-555",
          "qty": 1,
          "price": 39.9
        }
      ],
      "total": 39.9,
      "note": "Gift wrap"
    },
    {
      "id": "ORD-20004",
      "customer": "Dara Patel",
      "status": "refunded",
      "currency": "USD",
      "ship": null,
      "lines": [],
      "total": 0
    },
    {
      "id": "ORD-20005",
      "customer": "Eli Rossi",
      "status": "paid",
      "currency": "USD",
      "lines": [
        {
          "sku": "C-310",
          "qty": 2,
          "price": 15
        }
      ],
      "total": 30
    },
    {
      "id": "ORD-20006",
      "customer": "Fatima Garcia",
      "status": "shipped",
      "currency": "USD",
      "ship": {
        "city": "Austin",
        "zip": "78701"
      },
      "lines": [
        {
          "sku": "A-100",
          "qty": 1,
          "price": 9.99
        },
        {
          "sku": "E-555",
          "qty": 1,
          "price": 39.9
        }
      ],
      "total": 49.89
    }
  ]
}
6 orders, 1,051 bytes
encode()
Terset table8 lines
orders:
id	customer	status	currency	ship	lines	total	note
ORD-20001	Ana Silva	paid	USD	{"city":"Lisbon","zip":"1100-148"}	[{"sku":"A-100","qty":2,"price":9.99}]	19.98	
ORD-20002	Ben Okafor	shipped	USD	{"city":"Lagos","zip":"101233"}	[{"sku":"B-220","qty":1,"price":24.5},{"sku":"D-400","qty":3,"price":7.25}]	46.25	
ORD-20003	Chen Kim	delivered	USD	{"city":"Osaka"}	[{"sku":"E-555","qty":1,"price":39.9}]	39.9	Gift wrap
ORD-20004	Dara Patel	refunded	USD	null	[]	0	
ORD-20005	Eli Rossi	paid	USD		[{"sku":"C-310","qty":2,"price":15}]	30	
ORD-20006	Fatima Garcia	shipped	USD	{"city":"Austin","zip":"78701"}	[{"sku":"A-100","qty":1,"price":9.99},{"sku":"E-555","qty":1,"price":39.9}]	49.89	
8 lines, 686 bytes
decode()
Back to JSONoutput

Waiting for decode()Run the round trip below. The decoded JSON shows here.

Run it to see6 orders, equal to the inputNot equal to the input

Runs encode() and decode() on the six orders, in this page.Equal to the input: same values, same key order.The round trip did not match.

30,000seeded random roots in the fuzz round trip test
0runtime dependencies

6of 8

Fewer tokens than compact JSON in 9 of 11 cases, on both counters.

325Terset, rules included−8.7% against JSON
356Compact JSON
405TOON, best variant

Tokens per case, all 11 cases

Each case is scaled to its own largest count. Bar lengths compare real token counts within a case.

  • UI text, uneven rows
    UI text, uneven rows: Terset 504 tokens, JSON compact 695, YAML 802, TOON best 846. −40.4% against TOON, −27.5% against JSON compact.
  • UI text, uniform rows
    UI text, uniform rows: Terset 534 tokens, JSON compact 742, YAML 857, TOON best 539. −0.9% against TOON, −28.0% against JSON compact.
  • Translation batch
    Translation batch: Terset 1,225 tokens, JSON compact 1,450, YAML 1,623, TOON best 1,660. −26.2% against TOON, −15.5% against JSON compact.
  • File list, short
    File list, short: Terset 9,657 tokens, JSON compact 12,806, YAML 14,453, TOON best 10,643. −9.3% against TOON, −24.6% against JSON compact.
  • File list, long
    File list, long: Terset 16,483 tokens, JSON compact 19,627, YAML 22,129, TOON best 17,476. −5.7% against TOON, −16.0% against JSON compact.
  • 200 users
    200 users: Terset 4,718 tokens, JSON compact 6,811, YAML 7,983, TOON best 5,081. −7.1% against TOON, −30.7% against JSON compact.
  • Metrics, numbers and booleans
    Metrics, numbers and booleans: Terset 2,569 tokens, JSON compact 4,797, YAML 6,115, TOON best 2,654. −3.2% against TOON, −46.4% against JSON compact.
  • Deep nested config
    Deep nested config: Terset 411 tokens, JSON compact 371, YAML 456, TOON best 442. −7.0% against TOON, +10.8% against JSON compact.
  • Mixed-type array
    Mixed-type array: Terset 125 tokens, JSON compact 85, YAML 131, TOON best 160. −21.9% against TOON, +47.1% against JSON compact.
  • Reviews, long text
    Reviews, long text: Terset 3,801 tokens, JSON compact 4,279, YAML 4,787, TOON best 3,833. −0.8% against TOON, −11.2% against JSON compact.
  • Orders with line items
    Orders with line items: Terset 3,968 tokens, JSON compact 4,585, YAML 5,673, TOON best 4,419. −10.2% against TOON, −13.5% against JSON compact.

o200k_base: Terset, rules line included, is under TOON's best in 11 of 11 cases and under compact JSON in 9 of 11.

Show as a tableHide table
o200k_base tokens per case for Terset, compact JSON, pretty JSON, YAML, TOON best variant and plain CSV, with totals
CaseTersetJSON compactJSON prettyYAMLTOON bestCSVvs JSON compactvs TOON
UI text, uneven rows5046951,190802846473 lossy−27.5%−40.4%
UI text, uniform rows5347421,261857539504−28.0%−0.9%
Translation batch1,2251,4502,3961,6231,6601,402 lossy−15.5%−26.2%
File list, short9,65712,80616,77114,45310,643n/a−24.6%−9.3%
File list, long16,48319,62723,59522,12917,476n/a−16.0%−5.7%
200 users4,7186,81110,6107,9835,0814,678−30.7%−7.1%
Metrics, numbers and booleans2,5694,7977,5576,1152,6542,531−46.4%−3.2%
Deep nested config411371653456442n/a+10.8%−7.0%
Mixed-type array12585170131160n/a+47.1%−21.9%
Reviews, long text3,8014,2795,1194,7873,8333,769−11.2%−0.8%
Orders with line items3,9684,5857,7495,6734,4194,952 lossy−13.5%−10.2%
Total43,99556,24877,07165,00947,753n/a−21.8%−7.9%

CSV marked lossy did not read back to the same typed data. Terset counts include the rules line. Pretty JSON is in this table only, not in the chart.

Input cost at list price

Input cost at list price, US dollars per 1,000 requests. GPT 6.1 Sol at $2 per million input tokens, context up to 272K.

Input cost at list price, US dollars per 1,000 requests. GPT 6.1 Sol at $2 per million input tokens, context up to 272K.
CaseTersetJSON compactvs JSON compact
UI text, uneven rows$1.01$1.39−$0.38
UI text, uniform rows$1.07$1.48−$0.41
Translation batch$2.45$2.90−$0.45
File list, short$19.31$25.61−$6.30
File list, long$32.97$39.25−$6.28
200 users$9.44$13.62−$4.18
Metrics, numbers and booleans$5.14$9.59−$4.45
Deep nested config$0.82$0.74+$0.08
Mixed-type array$0.25$0.17+$0.08
Reviews, long text$7.60$8.56−$0.96
Orders with line items$7.94$9.17−$1.23
Total$87.99$112.50−$24.51

Tokens counted two ways: the o200k_base tokenizer and Claude's token count for Claude Opus 5.5. Others will differ. JSON means compact JSON, not pretty printed. The six orders above use o200k_base.

7of 8

Rules once, then the table.

Prompt with the six ordersRULES: 40 tokens
System prompt, onceTables use tab-separated headers and rows. Empty cells mean absent. JSON quotes distinguish numeric, boolean or null text from scalars. Nested cells use JSON. A leading bare id header marks string IDs.User message: the tableorders: id customer status currency ship lines total note ORD-20001 Ana Silva paid USD {"city":"Lisbon","zip":"1100-148"} [{"sku":"A-100","qty":2,"price":9.99}] 19.98 ORD-20002 Ben Okafor shipped USD {"city":"Lagos","zip":"101233"} [{"sku":"B-220","qty":1,"price":24.5},{"sku":"D-400","qty":3,"price":7.25}] 46.25 ORD-20003 Chen Kim delivered USD {"city":"Osaka"} [{"sku":"E-555","qty":1,"price":39.9}] 39.9 Gift wrap ORD-20004 Dara Patel refunded USD null [] 0 ORD-20005 Eli Rossi paid USD [{"sku":"C-310","qty":2,"price":15}] 30 ORD-20006 Fatima Garcia shipped USD {"city":"Austin","zip":"78701"} [{"sku":"A-100","qty":1,"price":9.99},{"sku":"E-555","qty":1,"price":39.9}] 49.89 QuestionWhich orders shipped?

Put RULES in the system prompt once. The data itself carries no legend.

prompt.js
import { encode, decode, RULES } from "@stackdeck/terset";

const system = RULES; // once, in the system prompt
const text = encode(data); // in the user message
Token counts say nothing about answer quality. Terset is about fewer tokens.

Tokens counted with one tokenizer, o200k_base. Others will differ. JSON means compact JSON, not pretty printed.

See the method and the limits

8of 8

One prompt teaches your agent.

Paste this into any coding agent before it builds a prompt.

Agent prompt

For a coding agent that writes prompts. Paste it into its instructions.

90 tokens

Read https://terset.dev/agents.md before you write any prompt.

Install the @stackdeck/terset package from npm with pnpm add @stackdeck/terset, or the same package in the project's own package manager.

When a prompt carries a list of JSON records, encode it with Terset and put its RULES sentence in the system prompt once.

Keep JSON for config and tiny data, and ask for answers in JSON.

Plain text, 4 lines.

All agent files

When to keep something else.

Limits

Try it on your own rows.

Package manager
pnpm add @stackdeck/terset