@bilig/headless can run spreadsheet logic without opening a browser grid, but
the useful boundary for services and agents is not just formula evaluation. A
workflow also needs a way to save workbook state, restore it later, and prove
that formulas still recalculate after restore.
This is the persistence path in bilig: export a WorkPaper document, serialize
it as JSON, store it wherever the host application stores durable state, then
parse and restore it before the next operation.
The public persistence helpers are exported from @bilig/headless:
exportWorkPaperDocument(workbook, { includeConfig: true })serializeWorkPaperDocument(document)parseWorkPaperDocument(json)createWorkPaperFromDocument(document)The exported document contains sheets, cell contents, named expressions, and optionally the persistable WorkPaper config. It is not a screenshot, CSV dump, or browser session snapshot. Formulas remain formulas, and the restored workbook can continue to evaluate and mutate through the WorkPaper API.
Install the package:
pnpm add @bilig/headless
Build a workbook, write it to disk, restore it, and apply a new edit:
import { readFileSync, writeFileSync } from 'node:fs'
import {
WorkPaper,
createWorkPaperFromDocument,
exportWorkPaperDocument,
parseWorkPaperDocument,
serializeWorkPaperDocument,
} from '@bilig/headless'
const workbook = WorkPaper.buildFromSheets({
Plan: [
['Month', 'Bookings', 'Churn', 'Net MRR'],
['January', 12000, 800, '=B2-C2'],
['February', 15000, 900, '=B3-C3'],
['March', 18000, 1200, '=B4-C4'],
],
Summary: [
['Metric', 'Value'],
['Quarter net MRR', '=SUM(Plan!D2:D4)'],
['Annualized run rate', '=B2*12'],
],
})
const saved = serializeWorkPaperDocument(exportWorkPaperDocument(workbook, { includeConfig: true }))
writeFileSync('workpaper.json', saved)
const restored = createWorkPaperFromDocument(parseWorkPaperDocument(readFileSync('workpaper.json', 'utf8')))
const plan = restored.getSheetId('Plan')
if (plan === undefined) {
throw new Error('Plan sheet was not restored')
}
restored.setCellContents({ sheet: plan, row: 3, col: 1 }, 21000)
The important point is that the edit after restore still goes through the same workbook model. Formula cells can recalculate from the restored document instead of relying on a stale display value.
The focused example is checked in at
examples/headless-workpaper/persistence-roundtrip.mjs.
Run it from the example package:
cd examples/headless-workpaper
npm install
npm run persistence
It verifies:
The expected summary is:
{
"beforeSave": {
"quarterNetMrr": 42100,
"annualizedRunRate": 505200,
"expansionAdjustedArr": 545616
},
"afterRestoreAndEdit": {
"quarterNetMrr": 45100,
"annualizedRunRate": 541200,
"expansionAdjustedArr": 584496
},
"persistedSheets": ["Plan", "Summary"],
"persistedNamedExpressions": ["ExpansionRatePercent"]
}
Keep persistence at the workbook-document boundary:
parseWorkPaperDocument() as the validation step for loaded JSON.For a broader package overview, start with
packages/headless/README.md. For public
evaluation links and shareable copy, use
docs/public-adoption-kit.md.