For agents
Teach your agent Terset
Paste one prompt, or point the agent at the raw files.
Agent prompt
For a coding agent that writes prompts. Paste it into its instructions.
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.
Raw files
Every file is plain text with its own content type. Sizes are o200k_base tokens.
agents.mdThe agent guide. When to use Terset, the encode call, the rules and how to read a table.
895 tokensSKILL.mdA skill file any agent harness can load. It teaches reading and writing Terset.
668 tokensspec.mdEvery rule of the format, with examples.
1,114 tokensbenchmark.mdThe method, the limits and every token count.
3,069 tokensllms.txtA short index of these files for language models.
247 tokensllms-full.txtThe agent guide, the spec and the benchmark in one file.
5,080 tokens
Skill
SKILL.md 668 tokens
A skill file any agent harness can load. It teaches reading and writing Terset.
What an agent needs
- When to use it. Lists of records that share keys. Keep JSON for config and tiny data.
- How to call it. encode() for the data, and the RULES sentence that explains it.
- Where the rules go. Put RULES in the system prompt once. The data itself carries no legend.
- What to ask for. Answers in JSON. Terset is for reading.
How to read a Terset table
A root field is key: value, or key: then a table. Each table has one tab-separated header and one row per record. An empty cell means the field is absent. A bare id header means the ids are plain text. A quoted "id" header means typed cells. Text that looks like a number, boolean or null is JSON-quoted.
team: core users: id name role tags u1 Ada null u2 ops u3 "42" ["new"]
The same data as JSON:
{"team":"core","users":[{"id":"u1","name":"Ada","role":null},{"id":"u2","role":"ops"},{"id":"u3","name":"42","tags":["new"]}]}
A root array is a table with no name line:
"id" code ok 7 "007" true 8 B12 false 9 "true"
The same data as JSON:
[{"id":7,"code":"007","ok":true},{"id":8,"code":"B12","ok":false},{"id":9,"code":"true"}]
Technique: short handles
Long ids are easy for a model to copy wrong. Before the prompt, swap each one for 1, 2, 3. After the answer, map the handles back and flag any the input never had. This is a technique your code applies. It is not part of the package.
| Handle in the prompt | Real id, kept in your code | Name |
|---|---|---|
| 1 | doc_7f3a91c2-4be0-4d55-9a1e-0c6b2f8d1e47 | Invoice March.pdf |
| 2 | doc_1c0e55aa-93f2-4a7d-b8e4-55d0c9a3f612 | Team photo.jpg |
| 3 | doc_e9b2d4f0-1a6c-4f83-a2d7-9be0f15c3a08 | Invoice April.pdf |
- The model answers:
["1","3","7"] - Mapped back:
doc_7f3a91c2-4be0-4d55-9a1e-0c6b2f8d1e47doc_e9b2d4f0-1a6c-4f83-a2d7-9be0f15c3a08 - Not in the input:
7. Report it or ask again. Never guess.
function toHandles(rows) {
const back = new Map();
const handled = rows.map((row, i) => {
const handle = String(i + 1);
back.set(handle, row.id);
return { ...row, id: handle };
});
return { rows: handled, back };
}
function fromHandles(handles, back) {
const ids = [], unknown = [];
for (const h of handles) {
const id = back.get(h);
id === undefined ? unknown.push(h) : ids.push(id);
}
return { ids, unknown };
}Measured result
A file-organizing task with 30 to 100 items. Accepted answers out of 24 runs per arm:
| Arm | Accepted, of 24 | Failed on a wrong id |
|---|---|---|
| JSON, long ids | 10 | 12 |
| JSON, short handles | 19 | 0 |
| Terset, short handles | 16 | 0 |
| JSON, handles and repair | 24 | 0 |
| Terset, handles and repair | 24 | 0 |
- Repair means your code fixes small, safe slips in the answer by fixed, deterministic rules before it checks it. It does not ask the model again. Names with hard characters came back byte for byte: 132 of 132.
- Handles and repair help JSON as much as Terset. The layout alone does not give better answers.
- Limits. One task, one model, reasoning off, development setup, 24 runs per arm. Production behavior was not measured.