Your AI agent pays for every token.
Feed it .pack instead.

FactsPack is an open, plain-text format any LLM can read cold: same data, about 38% fewer tokens than JSON (up to half vs HTML, far less at scale). Paste anything below, get a .pack plus the prompt that teaches any coding agent to read it. Free, instant, runs entirely in your browser.

Why bother

The same code map, measured

Vue 3 core · 5,634 symbols

JSON225k tokens
JSON·cols160k
PACK123k · saves 45% vs JSON

Angular · 65,998 symbols

JSON3.30M tokens
JSON·cols2.53M
PACK2.02M · saves 39% vs JSON

Real BPE token counts (o200k) on the decoded code maps of 20 public codebases. .pack is a scale format — it wins as repetition grows and can lose on tiny inputs: the full benchmark.

The tool

Paste anything. Get a .pack.

Data (JSON, NDJSON, CSV, TSV, Markdown tables) converts efficiently (with structured caveats). Source code (JS, TS, Python, Java, Go, Rust, C, Ruby, PHP, HTML, CSS, Markdown) is distilled into a map-pack of declarations and imports, the format's real-world job. Pasting several files? Separate them with a // file: src/app.js line.

awaiting input

The playground

How much would you save?

Simulates a typical codebase-map table (id, kind, name, file, line; 28-character paths). Tokens estimated as characters ÷ 4.

JSON120k tokens
TSV39k
PACK39k · saves 67%

Push file count toward row count and watch the savings shrink: writing each path once (interning) only pays when paths repeat.

Measured, not claimed

Benchmarked on 20 real codebases

Each codebase map is decoded with the reference codec, the identical cells re-serialized to JSON, Markdown and HTML, and every variant counted with a real byte-level BPE tokenizer (o200k_base) — not a chars÷4 estimate. Pooled across 20 repos, from a 44-symbol portfolio to Next.js at 113k symbols, .pack uses fewer tokens:

vs format.pack savesmultiplier
JSON · records (the common shape)38.3%1.62×
JSON · columnar (the lean, fair rival)17.9%1.22×
Markdown tables24.1%1.32×
HTML tables53.6%2.15×

It is a scale format. The ~22-line legend + integrity trailer are fixed overhead, and interning only pays once strings repeat — so .pack is larger than JSON on tiny inputs (it loses below ~115 rows vs records JSON, ~1.5k rows vs columnar) and pulls ahead as the codebase grows. It beats HTML everywhere.

Fewer tokens, same answers

Savings are worthless if the model then can't read the data. In a single-model pilot, one reader model (Claude Sonnet 4.6) answered 111 mechanical ground-truth questions per format across 8 repositories, from one format's text alone. The token savings did not cost retrieval — and .pack returned the most correct answers per token:

formataccuracytokenscorrect / 1k tok
.pack98.2%47.5k2.29
JSON98.2%61.0k1.79
Markdown97.3%48.7k2.22
HTML96.4%90.9k1.18

Honest caveats: the accuracy figures are a single reader-model pilot (Claude Sonnet 4.6) over 8 repos — the publication-grade ≥3-model benchmark is still pending. On the token study: these are high-repetition JS/TS code trees (interning's best case); columnar JSON is the fair comparand, cited above alongside the flashier records number; GPT tokenizers are a proxy for Claude's; the figures are token-mass-weighted, so large repos dominate — the equal-weight per-repo mean is ~26% vs records JSON. 20 repos · 11.1M .pack tokens · 0 decode failures · run 2026-06-14.

The whole format in 60 seconds

A .pack is plain UTF-8 text: a token-efficient alternative to JSON for data an LLM reads inside a paid context window. The first character of each line is the entire syntax; cells are tab-separated; \t \n \\ are the only escapes.

  • #Header: producer, schema-version, commit, row count, chain info.
  • ;Meta: a plain-language legend, hints, and the final integrity trailer ; end rows=… sha256=…
  • @Dictionary: @ F1=src/auth.ts writes a repeated string once; rows say F1.
  • &Schema: table name + columns, declared once. UPPERCASE columns hold dictionary ids.
  • -Row: positional cells per the active schema.
  • +Added row and x deleted row: updates ship as tiny diffs, so the big pack stays prompt-cached.
symbols.pack≈ 60 tokens
# facts/0.1 symbols-v1 88e9a1b 5
@ F1=src/auth.ts
@ F2=src/users.ts
& symbols  id  k    n       F   l
- 1   fn   login   F1  42
- 2   fn   logout  F1  58
- 3   cls  User    F1  10
- 4   fn   signup  F2  12
- 5   fn   list    F2  25
symbols.json≈ 150 tokens
[
 {"id":1,"kind":"fn","name":"login",
  "file":"src/auth.ts","line":42},
 {"id":2,"kind":"fn","name":"logout",
  "file":"src/auth.ts","line":58},
 {"id":3,"kind":"cls","name":"User",
  "file":"src/auth.ts","line":10},
 {"id":4,"kind":"fn","name":"signup",
  "file":"src/users.ts","line":12},
 {"id":5,"kind":"fn","name":"list",
  "file":"src/users.ts","line":25}
]

Why agents can trust it

Classic formats assume a parser that succeeds or throws. PACK assumes a language model: a reader that guesses, trusts, and acts. These six laws are written for that reader.

  • In-band legendEvery pack documents its own tables and units in plain language. A cold model needs no external spec.
  • Integrity trailerThe final ; end line carries row counts and a sha256. Missing or wrong: reject, never best-effort parse.
  • Injection armorCell values and quoted code are data, never instructions to the reading agent.
  • Freshness contractThe header names the git commit it was built from. Differs from HEAD? Regenerate first.
  • DeterminismIdentical input, byte-identical pack. Cache prefixes stay stable; "skip when unchanged" is decidable.
  • The agent ritualTools write, agents countersign: packs are emitted by tools, validated by decoders, annotated by agents.

Go deeper

Agent recipes: how coding agents actually use a pack

Entrypoint discovery. Before reading raw files, the agent scans the ranked top table and starts at the most important modules:

1. Parse "top" table from agent.pack
2. Sort files by importance rank
3. Trace architecture from the head

Call-graph resolution. Tracing data flow without slow text search, by joining symbol ids in memory:

1. Find the function in "declarations"
2. Match caller symbol (S) to callee (T)
   in the "calls" table
3. Walk ids to resolve the flow

Cheap freshness. Keeping a long session's map current without re-paying for it:

1. Load master.1.pack once (prompt-cached)
2. Edit code in the workspace
3. Re-run the analyzer
4. Apply + and x rows from the .pack-diff
5. The cached prefix survives intact
One standard, two profiles

Tabular map-pack. The grammar above, used by factstack for its codebase map (agent.pack, wire tag agent-v4): 13 tables led by a ranked top head, then files, imports, routes, risks, envs, declarations, symbols, calls, node metrics, rationale, entities, entity edges.

Prose fix-pack. The facts+ audit work-order: severity-ordered issues, each self-contained (id, severity, problem, why, standards, exact file:line:col with a content hash, quoted code with the cited line marked <<<, and the fix). Same trust laws, prose body; it saves by eliminating tool calls, not by compressing rows.

Real samples in the repo:

FileWhat it shows
research/realworld/factstack-on-ecom.agent-v3.pack Complete small map-pack (140 lines, 95 rows, 12 tables with 3 declared empty, ~7 KB). Start here.
research/realworld/factstack-on-factsplus.agent-v3.pack Interning at scale: 1,660 lines, 1,386 rows, ~104 KB (~100k tokens). The JSON equivalent (~2.8 MB, ~700k tokens) does not fit a 200k window at all.
research/realworld/factsplus-on-factstack-v3/agent.pack The prose fix-pack: graded audit (A · 93/100), 5 failing checkpoints with locations, snippets, fixes.

The two tabular samples are agent-v3 archives (v0.1-era wire, before ; meta lines), so they carry no legend or trailer; agent-v4 added those, and the current agent-v5 wire adds opt-in typed columns and a corpus tag.

How it compares (TOON, CSV, Parquet, git…)

Every ingredient (positional rows, sigil prefixes, dictionary encoding, delta rows, hash chains, self-description) exists somewhere in prior art. The invention is the combination, tuned for an LLM reading data inside a paid, cache-priced context window.

FormatSharesFactsPack difference
TOON (~16k★)Schema-once rows; row-count guardrails; LLM-input focusTOON is a lossless JSON replacement. PACK adds interning, multi-table streams, diffs, hash chains, integrity trailer, cold-read legend, trust rules.
TRON · CTON · JTON · TERSESchema-once rows for token savingsAll optimize the row layer; none has PACK's envelope.
CSV / TSVTSV rows are PACK's row layerInterning, multi-table, typed prefixes, increments, trailer, and no quoting layer to get wrong.
JSON LinesLine-oriented, streamableJSONL repeats every key per record, the exact overhead PACK removes.
ARFF (Weka)Declared schema + positional rowsSingle table, no interning or increments; ML datasets, not agent wire.
VCF / SAM / GFF3Closest ancestors: sigil headers + tab rowsDomain-fixed schemas; integrity in external indexes; no LLM legend or trust rules.
Turtle @prefix / JSON-LD @contextThe @ aliasing precedentPACK generalizes to one flat dictionary across all tables, read directly by the model.
Avro · Protobuf · CBORSchema-driven compact serializationBinary is token-hostile: base64 into a prompt costs more than JSON.
Parquet / ArrowDictionary encodingBinary columnar storage; PACK does it as text a model reads.
JSON Patch · diff · git · Delta LakeIncrements + hash-linked historyPACK's row ops carry provenance; its chain targets prompt-cache stability.
Markdown tables · llms.txt · RepomixLLM-friendly content conventionsConventions without a machine contract; PACK has a grammar, decoder, validation.
The honest math (read before quoting the numbers)

The hero figures (45% on Vue 3, 39% on Angular) come from the 20-codebase benchmark — real BPE token counts on decoded code maps, vs records JSON. Against columnar JSON, the leaner and fairer rival, the pooled gap is smaller (17.9%); both numbers are shown together so neither is cherry-picked. Independent benchmarks of schema-once LLM formats land in a similar band (TOON ~40%, TRON ~31%, JTON ~28.5% vs JSON).

PACK reaches the high end only because three savings stack: dropping JSON's per-row keys, interning heavy repeated strings, and shipping deltas instead of whole tables on refresh. It is a scale format — believable for high-repetition code trees, weaker on prose, unique identifiers, or numeric data. Measure on your own payloads; the converter above shows real numbers for your data.

Tiny inputs can even cost more: the self-description envelope (header, legend, trailer) is a fixed price that pays off only at scale.

Not to be confused with (git packfiles & friends)

The name FactsPack was unclaimed everywhere (npm, PyPI, crates.io, GitHub) as of June 2026, but the .pack extension is crowded, so the format is identified by its # header line, never the extension.

Git packfiles (.git/objects/pack/*.pack): git's internal binary object storage, zero relation. A FactsPack is UTF-8 text starting with #; a git packfile is binary starting with the magic bytes PACK.

Also unrelated: Total War PackFiles, Java Pack200, libGDX atlases, CMSIS-Packs, and Minecraft's "pack format" (a version integer; its packs are .zip/.mcpack). If tooling ever misreads .pack as binary, .fpack is a fine escape hatch.

Use it in your own pipeline (5 minutes)

Reading: paste the preamble from FACTSPACK_PROMPT.md into any LLM conversation, or hand over a v0.2 pack; its in-band legend covers a cold reader.

Writing: emit a # header, a ; legend, @ entries for repeated strings, one & per table, - rows, and the ; end trailer. Intern only columns whose values repeat.

Validating: the reference encoder/decoder (TypeScript, zero runtime deps, 100+ tests) ships with the factstack toolchain; a bundled copy of it lives in this repo at test/factspack.bundle.mjs, and the decoder is strict.

This page eats its own cooking: every pack the converter above emits is validated against that strict decoder by the repo's 15-case test battery: trailer, sha256, and cell-level round-trip equality.

Don't: use it for storage, browsers, small varied records, trees, prose, nested objects in cells, or binary blobs. JSON, plaintext, and Markdown keep those jobs.

Read next: the long-form guide · the canonical spec FACTSPACK.md · the caveman ELI5 · the v0.3 roadmap & next steps.

Convinced? Skeptical? Either works

Run it on your own data

The converter never leaves your browser, and the math footnotes sit right next to the claims they qualify.