tsvsheet logo tsvsheet

A spreadsheet in plain text.

A .tsvt file is the spreadsheet — a tab-separated grid whose cells are values or =formulas that address other cells in A1 notation, computed by a processor, versioned as text, diffed line by line.

grades.tsvt
StudentMathReadingScienceAveragePass
Alice859078=round(avg(B2:D2), 1)=if(E2 >= 70, 1, 0)
Bob726880=round(avg(B3:D3), 1)=if(E3 >= 70, 1, 0)
ABCDEF
1StudentMathReadingScienceAveragePass
2Alice85907884.31
3Bob72688073.31
hover or tap a shaded cell to see its formula

Same file, two readings: the text you commit, and the sheet your processor computes. Shaded cells hold formulas — hover or tap one and the formula bar shows what it computes.

Why TSV, not CSV

Formulas are full of commas. Because fields are separated by tabs, =if(A1, C3, D3) is written verbatim — no quoting, no escaping, no dialect. Every cell in a .tsvt file reads exactly as it would in a formula bar.

Spreadsheets earned their place by making computation visible: a grid you can read, formulas you can point at. What they never earned is a file format — binary blobs and XML archives that no diff can explain and no text editor can open. tsvsheet keeps the grid and the formulas and drops everything else: one row per line, versioned like source code, reviewed line by line.

Because the file holds =round(avg(B5:D5), 1) and never 71.7, a diff shows the decision someone made — one changed number — while the consequences stay computable: recompute both sides of a commit and compare, merge two people's edits to different rows, blame a formula, gate the whole thing on check. Working a sheet through git →

Formulas that read like pipelines

The expression language is Excel-faithful — ^, &, postfix %, A1 cells and ranges — plus one unix-native addition: the pipe. expr | fn(arg) feeds the expression in as the function's first argument, so a transformation reads left to right in execution order instead of inside-out:

=B2 | round(1)                    ≡  =round(B2, 1)
=concat(A2, " ", A3) | len      ≡  =len(concat(A2, " ", A3))
=sum(B2:B7) | round(2)            ≡  =round(sum(B2:B7), 2)

The pipe is pure sugar over function calls — the two spellings are the same formula, and everything downstream (dependency order, memoization, explain) sees an ordinary call, while your sheet keeps the spelling you wrote.

Live sheets, right here

These grids are real .tsvt files. Load the engine — the actual Go implementation, compiled to WebAssembly, running entirely in this page — and every cell becomes editable: click, type a value or an =formula, and watch the sheet recompute.

a one-time download, then everything runs locally
StudentMathReadingScienceAverageResult
Alice85907884.3Pass
Bob72688073.3Pass
Carol95889191.3Pass
Dave60557061.7Fail

Each Average reads its row's scores; each Result reads the Average beside it. Change a score and both follow.

MonthRevenueChart
Jan1200█████████████
Feb1350███████████████
Mar1280██████████████
Apr1510█████████████████
May1620██████████████████
Jun1810████████████████████

A chart you can cat: rept scaled by max draws bars in the grid itself — diffable, greppable, reviewable.

CategoryMonthlyShare %
Compute420048.8
Storage190022.1
Network110012.8
Observability8009.3
CI6007

Every share reads sum($B$2:$B$6) — change one number and the whole column reflows.

Want the full experience — formula bar, keyboard navigation, row/column edits, precedent highlighting, the raw .tsvt pane? Open the playground →

One engine, every workflow

The tsvsheet CLI is a strict unix citizen: text in, text out, exit codes for scripting. The same engine also serves a browser editor and a terminal UI — no frontend re-implements a single formula.

$ tsv render sheet.tsvt          # compute and print the grid
$ tsv check  sheet.tsvt          # validate formulas and references
$ tsv explain D5 < sheet.tsvt    # trace how one cell was produced
$ tsv serve  sheet.tsvt          # local browser spreadsheet editor
$ tsv tui    sheet.tsvt          # terminal spreadsheet editor

A .tsvt can carry a #! shebang and # comments, so a sheet is directly executable — render is the default command. Computed output is plain TSV: pipe it to column -t, load it with d3.tsv(), feed it to gnuplot, commit it to git. Formulas draw on 140 built-in functions — Excel-faithful math, text, dates, lookups, and more.

Built for agents

An AI agent works best on artifacts it can read, edit, diff, and verify as text — which is precisely what a .tsvt is. An agent edits three characters, the diff shows three characters, CI recomputes the sheet, and the review shows exactly what changed and what it rippled into.

  • check as a gate — validate every formula and reference, with exit codes an agent (or CI) can act on.
  • explain as ground truth — the evaluation trace of any cell, so "why is D5 wrong?" has a mechanical answer.
  • parse as structure — the typed AST as JSON, stable enough to jq.
  • tsvsheet.mcp — the engine's render/check/explain surface as MCP tools, so agents drive spreadsheets through files, not screenshots.

Sheets where you already write

A fenced ```sheet block in Markdown renders as a computed grid — in Go pipelines through tsvsheet.goldmark, in JS pipelines through tsvsheet.remark, and in your vault through tsvsheet.obsidian, which also gives .tsvt files a live view. tsvsheet.lsp brings diagnostics, hovers, and completion to any editor that speaks the language-server protocol; dedicated VS Code and IntelliJ extensions are built on it and not yet published. The full catalog — editors, agents, servers, libraries — is on the tools page.

One grammar, every runtime

The language is specified grammar-first: the ANTLR4 grammar in tsvsheet is the source of truth, implementations follow it, and the same file computes identically in every runtime.

tsvsheetThe grammar-first language home: ANTLR4 grammar and the specification
tsvsheet.go · tsvsheet.jsLanguage implementations — the Go engine, and the same engine as WebAssembly with a typed JS API and a <tsv-sheet> web component
tsvsheet.goldmark · tsvsheet.remark · tsvsheet.obsidianMarkdown and Obsidian integrations — sheets computed inside your notes
tsvsheet.lsp · tsvsheet.mcpEditor and agent tooling: language server and MCP server
tsvsheet.apiThe sheet API server — the edit language over HTTP: document plane, change feed, computed reads
go-tsvsheetThe engine as an importable Go library — parse, compute, and inspect .tsvt files

Get started

$ brew install tsvsheet/tap/tsv
$ printf 'a\tb\tsum\n2\t3\t=A2+B2\n' > first.tsvt
$ tsv render first.tsvt
a	b	sum
2	3	5

Scoop on Windows, deb/rpm packages, prebuilt binaries with verifiable provenance, or go install — every way in is on the install page. Prefer the browser? The playground runs the same engine as WebAssembly — no install, nothing leaves your machine. Go programs import go-tsvsheet; the JS package tsvsheet.js (typed API + <tsv-sheet>, consumed straight from the repository) is what powers the live sheets on this page.