Sheetkit: Spreadsheets for AI, Not AI for Spreadsheets
sheetkit is an open-source toolkit (Rust, MIT/Apache-2.0) that gives a language model a live spreadsheet as a tool. It runs as an MCP server you can add to Claude Code in one line, as a network daemon with a REST API and a WebSocket channel, and as a wasm module inside a browser tab. It's built on IronCalc, an open-source spreadsheet engine, and it exists because we think the current wave of spreadsheet AI has the relationship backwards: products keep adding AI to spreadsheet UIs, when the more interesting problem is shaping the spreadsheet into something an AI can operate.
Spreadsheets are hard for language models
Arithmetic is the easy part. A spreadsheet is a two-dimensional, sparse, spatially addressed artifact; a language model consumes a one-dimensional token stream. Serialize naively (address, value, format, row by row) and the encoding drowns the content. Boilerplate dominates, homogeneous regions repeat themselves thousands of times, and a mostly empty sheet can still swallow a context window.
The reference point here is Microsoft's SpreadsheetLLM paper from mid-2024. Its encoding framework, SheetCompressor, keeps the rows and columns near structural boundaries and prunes the homogeneous interior, dedupes repeated values into an inverted index, and merges uniformly formatted cells into regions. That cut token usage by roughly 96% (a 25× average compression ratio) and pushed fine-tuned table detection to 78.9% F1, about twelve points over the previous state of the art. But those benchmarks are reading tasks: table detection, QA over sheets. The paper is about understanding spreadsheets, not editing them.
The lesson we took from it is that the encoding matters more than almost anything else you do. But the framing the paper works within treats the spreadsheet as a document: compressed, then handed to a model that answers questions about it. The model looks at a snapshot.
The sidebar wave inherits that framing
The products shipping today mostly do too. Copilot sits in a pane in Excel. Claude for Excel runs in a sidebar, reads the open workbook, explains formulas, traces dependencies, and modifies cells with citations back to what it touched. That citation trail is the strongest transparency story in the category.
These products share a contract shape: the assistant sits on the far side of an integration surface, reads a range, writes a range, and issues further reads to learn what a write did to dependent cells. Add-in APIs do expose dependency queries and batched reads, so a well-built sidebar can pull back the ripple of a write; the point is that it has to know to ask. Nothing pushes the recalculated consequences to the model. That follows from working against real Excel: an assistant that doesn't own the engine cannot return the recalc alongside the write. It matters because the recalculation loop (change a cell and every dependent formula moves) is what makes a spreadsheet more than a table.
The consequence of the write is a separate read the model must know to issue — and pay for.
The recalculated ripple comes back in the write's own result. Act, then observe — one call.
What sheetkit does instead
sheetkit rebuilds random-access vision, instant recalc feedback, and spatial addressing as text, in a tool contract designed for a model:
- Structure-aware views under a token budget. Opening a workbook returns a sketch: every sheet, detected table regions, per-column types, value ranges, fill formulas, deviations. A 10,000-row sheet describes itself in a few hundred tokens, and it announces every truncation. This is SpreadsheetLLM's insight applied as an interface: the compression isn't a preprocessing pass, it's the return type of the read.
- A delta echo after every mutation. Change one cell and the tool result tells you exactly what recalculated, old value ⇒ new value, formula ripple included. The model sees what its edit did without issuing another read.
- Range-level verbs.
fill,sort,expect: one command each, not thousands of cell writes.
A session against a 10k-row file looks like this:
$ sheetd repl orders.xlsx
Sheet1: used A1:E10001
table1 (Sheet1!A1:E10001, 10000 rows + header)
A "Order" text · sorted asc
B "City" text, 6 distinct · values: "Vienna"×1754, "Rome"×1675, …
C "Date" date 2024-01-01..2024-12-28
D "Qty" number 1..50
E "UnitPrice" number 1.09..499.98
> set F2 =D2*E2
> fill F2 -> F2:F10001
recalc: 9999 cells changed
F3 ⇒ 1137.72 · F4 ⇒ 1304.34 · F5 ⇒ 7662.24 · …
> sort table1 by Total desc
⚠ 10000 formula cells moved and re-anchored to their new rows
> expect F2 > 24000
expect F2 > 24000: OK (actual 24495)
sheetd mcp exposes this over the Model Context Protocol as five tools
(sheet_open, sheet_exec, sheet_view, sheet_save, sheet_close).
The surface is deliberately small, because the command language carries the
verbs. With Claude Code:
cargo build --release
claude mcp add sheets -- /path/to/sheetkit/target/release/sheetd mcp
A realistic task ("clean this export, add a margin column, reconcile the
totals") lands in a handful of tool calls in our sessions, with every intermediate state
verifiable from the transcript alone. sheetd serve runs the same engine as
a network service: one authoritative session per workbook, the same tools
over HTTP MCP, a REST API, and a WebSocket channel that broadcasts every
applied script with its recalc delta, the acting principal, presence, and
highlights.
The formula language is the sandbox
The standard answer to "the agent needs to compute something" is a code interpreter: the model writes Python, a sandboxed runtime executes it, and the result is pasted back. This works, and it costs infrastructure: a sandbox per session, resource limits, network policy. It is also opaque. The computation lives in a script the user will never open, and the sheet ends up holding pasted static values.
The formula language already is a programming language. Since
LAMBDA,
Microsoft Research's own conclusion is that the Excel formula language is
Turing-complete: with LAMBDA, LET, and the dynamic-array functions, the
formula layer is a pure functional language with reactive evaluation.
sheetkit pins IronCalc at a git revision (9ee7e066) that implements this
modern set; the published npm release predates roughly 150 of these
functions. At the pinned revision,
=LET(f, LAMBDA(self, n, IF(n<=1, 1, n*self(self, n-1))), f(f, 5))
returns 120, in the native build and in wasm.
An agent with these tools rarely needs to leave the sheet to compute:
- No exfiltration surface. In this engine, formulas have no filesystem,
no network, no processes; Excel's
WEBSERVICEclass of functions has no counterpart here. To be precise about what Turing-completeness costs: a formula can fail to terminate or exhaust memory, so recalculation bounds are still needed; that much of the sandbox survives. What it cannot do is reach outside the engine. - Every intermediate value is inspectable. A Python script returns an answer; a sheet computation is its own trace, and each step occupies a cell someone can click on.
- The result stays alive. When the agent answers "which plans beat the average?" with a formula instead of a pasted list, the human can change an assumption and watch the answer update.
- The delta echo closes the loop. Write a formula, and the recalculated consequences come back in the same tool result: a read-eval-print loop for a reactive language.
We're not claiming you'd want to write a ray tracer in formulas (you can; please don't). The claim is narrower. Aggregation, filtering, projection, and what-if cover most real questions asked of business data. That class is native to this substrate, and here it runs where the person who asked can audit and edit it.
The same code, native and in the browser
The core crate (sheetkit) holds the tool semantics (sketch, command
language, delta computation, sessions) and sheetd is a thin daemon around
it. sheetkit-wasm is the same crate compiled to WebAssembly; the only
change was feature-gating xlsx I/O, whose compression libraries pull in C
code. The identical session/command/delta code runs in a browser tab with
no server at all.
crates/sheetkitsketch · command language · delta echo · sessions
sheetd mcpMCP over stdio — one line to add to Claude Code or any local agent.
sheetd serveNetwork daemon: REST API, HTTP MCP, and a WebSocket channel broadcasting every applied script with its recalc delta.
sheetkit-wasmThe same crate compiled to WebAssembly — runs in a browser tab with no server at all.
That's what Ingram Sheets is: a product UI on top of the same pinned engine, where the agent's tools execute in the browser against the document you're editing and you watch its cursor work: blue for you, violet for it. Its landing page runs a replay of a real agent session in your browser, no account needed. A replay proves nothing, but it's the fastest way to see what "watching the agent work" means.
The delta echo turned out to work in the other direction too. Your own
edits get the same treatment the agent's do: each burst shows in the chat
transcript as a passive note, and the accumulated changes reach the agent
at the earliest seam — appended to its next tool result if you edit while
it's mid-task (user edited meanwhile: C3 29 ⇒ 35), or attached beside the
workbook state on your next message. The prompt frames these as awareness
rather than requests, so the agent adapts to your hand without replying to
it, reverting it, or re-applying it. Both principals on the document now
see each other move, which is the shape the collaboration protocol wants
anyway — every edit an attributed event — arriving one seam early.
What it is and isn't
sheetkit is a research project, and we use it daily. The engine is a subset of Excel: it evaluates the modern formula core, and a workbook that leans on pivot tables, Power Query, or VBA is outside it. The engine is pinned to an IronCalc git revision, and stored engine bytes are version-locked to it; workbooks migrate across engine bumps through xlsx, which is lossy at the margins. The delta is computed by snapshot-diffing (IronCalc exposes no dependents API; if upstream adds one, we delete that mechanism). And we owe the token-economics claim a number: we've watched the delta echo eliminate re-reads in practice, but we haven't benchmarked it against a read-write-read contract on a task suite. Until we do, that claim is an observation, not a measurement. Measuring it is next.
We're also looking into offering this natively to agents on
Ingram Cloud, our agent platform: a
spreadsheet tool any agent can enable, backed by a hosted sheetkit
session. The reasoning is the sandbox argument above — for the
aggregation-and-what-if class of computation, a live workbook gives an
agent an effect-free substrate with per-cell auditability and a deliverable
that stays alive, where a code interpreter needs sandbox infrastructure and
returns dead values. An agent answering questions in Slack or over email
could compute in a workbook and hand back the workbook itself.
The hard part is the engine, and that work is IronCalc's. What sheetkit adds is the tool surface a model can drive: github.com/ingram-technologies/sheetkit.
References
- SpreadsheetLLM: Encoding Spreadsheets for Large Language Models · Microsoft, 2024
- LAMBDA: The ultimate Excel worksheet function · Microsoft Research, 2021
- Claude for Excel · Anthropic
- IronCalc · sheetkit · Ingram Sheets
