bilig

Node.js spreadsheet formula engine for services

Use @bilig/headless when a Node.js service needs spreadsheet formulas as part of its own runtime. The useful case is not “make a prettier spreadsheet.” It is “accept inputs, update workbook state, recalculate formulas, persist the document, and return values that were actually read back from the engine.”

That shows up in ordinary backend work:

If you only need to write an XLSX file for Excel to open later, use an XLSX library. If you need maximum Excel-function coverage today, evaluate HyperFormula first. If you need a small TypeScript WorkPaper object that a Node process can mutate, verify, and save as JSON, @bilig/headless is the slice to try.

What the engine owns

@bilig/headless gives the service a WorkPaper object. A WorkPaper is a programmatic workbook with sheets, cell addresses, formulas, computed values, structural edits, and persistence helpers.

The important boundary is readback. Do not trust that a service “wrote the formula” just because a string was assigned. Read the calculated cell value through the WorkPaper API, serialize the document, restore it, and read the same value again. That is the path the package is built around.

Quick smoke test

Run this from an empty directory:

mkdir bilig-formula-engine-eval
cd bilig-formula-engine-eval
npm init -y
npm pkg set type=module
npm install @bilig/headless
npm install -D tsx typescript @types/node
cat > formula-engine-smoke.ts <<'EOF'
import { WorkPaper } from '@bilig/headless'

type NumericCell = {
  value: number
}

function readNumber(cell: unknown, label: string): number {
  if (typeof cell === 'object' && cell !== null && typeof (cell as NumericCell).value === 'number') {
    return (cell as NumericCell).value
  }

  throw new Error(`Expected ${label} to be numeric, got ${JSON.stringify(cell)}`)
}

const workbook = WorkPaper.buildFromSheets({
  Plan: [
    ['Metric', 'Value'],
    ['Customers', 80],
    ['Price', 49],
    ['Discount', 0.08],
  ],
  Summary: [
    ['Metric', 'Value'],
    ['Net revenue', '=Plan!B2*Plan!B3*(1-Plan!B4)'],
  ],
})

const sheet = workbook.getSheetId('Summary')
if (sheet === undefined) {
  throw new Error('Summary sheet was not created')
}

const netRevenue = readNumber(workbook.getCellValue({ sheet, row: 1, col: 1 }), 'net revenue')
if (netRevenue !== 3606.4) {
  throw new Error(`Unexpected formula readback: ${netRevenue}`)
}

console.log({ netRevenue, verified: true })
EOF
npx tsx formula-engine-smoke.ts

Expected output:

{ "netRevenue": 3606.4, "verified": true }

That tiny check proves three things at once: multi-sheet workbook creation, formula evaluation, and computed readback from Node.

When it fits

Start here when the service needs a workbook model, not just isolated formula functions.

Need Why @bilig/headless helps
Put spreadsheet formulas behind an API The service can build a WorkPaper, edit input cells, and return computed cells.
Let an agent edit a workbook safely The agent can report exact changed cells and post-write readback instead of only narrating intent.
Persist formula-backed state Export the WorkPaper document, store JSON, restore it later, and verify formulas still calculate.
Keep examples runnable The repo includes invoice, budget variance, subscription MRR, quote approval, and capacity examples.

When to choose something else

Use a different tool when the job is outside this package’s current shape:

Evaluation path

If the smoke test matches your use case, run the maintained example next:

git clone https://github.com/proompteng/bilig.git
cd bilig/examples/headless-workpaper
npm install
npm start
npm run agent:verify

Then inspect the focused examples:

If this package saves you a workbook automation spike, star the repository so the project is easier for the next backend developer to find: https://github.com/proompteng/bilig/stargazers.

If it almost matches but a gap blocks adoption, use the adoption blocker form: https://github.com/proompteng/bilig/discussions/new?category=general.