TrueCalc
12,671 verified cases match Google Sheets

Google Sheets semantics, exactly.

A formula engine that matches Google Sheets, function for function. For Rust, JavaScript, Deno — and your AI agent.

MIT licensed — no GPL, no dual-licence conversation with legal.

workbook.truecalc.appOpen in full

Edit any cell — it recalculates here, live

Start here

Pick your runtime. Copy one line.

Same engine everywhere. Pick the one you already write in.

WebAssembly. Runs in the browser, Node and Deno — no server, no network.

npm

npm install @truecalc/core
JavaScript & TypeScript
import { evaluate, list_functions } from '@truecalc/core';

evaluate('SUM(A1, B1)', { A1: 100, B1: 200 });
// => { type: 'number', value: 300 }

evaluate('IF(A1 > 0, "yes", "no")', { A1: 1 });
// => { type: 'text', value: 'yes' }

list_functions().length;
// => 518

Node 24+ — on Node 22 run with `--experimental-wasm-modules`. Bundlers need a WASM plugin: vite-plugin-wasm for Vite, `experiments.asyncWebAssembly` for webpack 5.

Why this is hard

Every spreadsheet engine is 95% right. The last 5% is the product.

Rounding, coercion, date edges, error propagation. The places engines quietly disagree are the places TrueCalc is measured.

Expected values come from Google Sheets itself, not from a reading of what it ought to do. They are fixed, and the engine is measured against them on every change.

That is the part that matters. An engine checked against its own output can only ever agree with itself.

Four formulas where a naive implementation diverges from Google Sheets
FormulaResult
=ROUND(2.5, 0)3
Sheets rounds half away from zero. Banker’s rounding — the IEEE 754 default, and what Python’s round() does — returns 2.
="10" + 515
Text coerces to a number in arithmetic. It does not in a comparison: ="10" = 10 is FALSE.
=1/0#DIV/0!
An error is a value that flows onward through the sheet, not an exception that stops it.
=TEXT(DATE(2026, 13, 1), "yyyy-mm-dd")2027-01-01
There is no month 13, so the date rolls forward into the next year rather than erroring.
518
Functions
12,671 / 12,885
Conformance cases pass
MIT
Licence
v8.1.1
Current release

For AI agents

Your agent should not be doing arithmetic in its head.

Models are confident and wrong about dates, calendars and compounding. Give yours twelve tools and a workbook that lasts the whole conversation.

Claude Code — one command
claude mcp add truecalc -- npx -y @truecalc/mcp

The twelve tools

  • evaluateEvaluate a formula, with optional variable bindings.
  • batch_evaluateEvaluate many formulas over one set of bindings.
  • validateCheck that a formula parses before you trust it.
  • explainDescribe a formula and list every function it reaches for.
  • list_functionsThe whole catalogue, with category, syntax and description.
  • get_statsFunction count, library version, per-category breakdown.
  • workbook_createOpen a workbook. The engine flavour locks at creation.
  • workbook_setWrite a value or a formula to a cell, in A1 notation.
  • workbook_getRead a cell’s effective value, spills resolved.
  • workbook_recalcRecalculate, and get back exactly which cells changed.
  • workbook_exportExport the session as canonical JSON.
  • workbook_importLoad a workbook from canonical JSON.

Reproducible by definition

A workbook is a value, not an application.

Canonical JSON in, canonical JSON out. Commit it, review it in a pull request, recompute it later — and get the same grid back, byte for byte.

  • The clock is an argument

    NOW, TODAY and RAND read from a context you pass in — a timestamp, an IANA timezone and a seed. Same workbook plus same context, same answer, forever.

  • One schema, every surface

    A workbook written in Rust deserializes unchanged in WebAssembly and in the MCP server. There is no second evaluator anywhere.

  • Timezones are vendored

    The engine carries its own timezone tables rather than reading the host’s, so a machine with stale OS data cannot quietly change your results.

@truecalc/workbook
import init, { JsWorkbook } from '@truecalc/workbook';

await init();

const wb = new JsWorkbook('sheets');
wb.addSheet('Budget');
wb.set('Budget', 'A1', '1000');
wb.set('Budget', 'A2', '500');
wb.set('Budget', 'A3', '=SUM(A1:A2)');

// Pin the clock, the timezone and the seed.
wb.recalc(JSON.stringify({
  timestamp_ms: 1780000000000,
  timezone: 'UTC',
  rng_seed: 0,
}));

// resolved() hands back a JSON string, not an object.
JSON.parse(wb.resolved('Budget', 'A3'));
// => { type: 'number', value: 1500 }

// Canonical JSON — RFC 8785. Diffable, committable, replayable.
const snapshot = wb.toJSON();

Install it in the next thirty seconds.

518 functions, MIT licensed, no account, no server. If a result disagrees with Google Sheets, that is a bug — open an issue and it becomes a fixture.

7,288

npm downloads in the last 30 daysas measured on 2026-08-19 — live figure unavailable

How this is counted

Summed across @truecalc/core, @truecalc/workbook and @truecalc/mcp — the three real packages.

The MCP server's five prebuilt platform binaries are excluded, not added: one `npx @truecalc/mcp` pulls the wrapper and one binary, so summing them counts each install twice.

crates.io and JSR are not folded in. A crates.io download is a per-version fetch dominated by CI and an npm download counts every install — the units are different, so a combined total would mean nothing.

Conformance cases
12,885
Published failures
214
Version
8.1.1
Licence
MIT