Every agent now speaks xlsx

Full Excel compatibility for agents and machines.

BETA
~/reports
$

// what it does

The whole spreadsheet, headless and pipeable

compute

Every formula calculated correctly

Set a cell to =PMT(…) or =XLOOKUP(…) and read the answer back. It's the same engine the app runs, so if Excel can compute it, so can a shell script.

pipe

Text in, text out

Every command reads stdin and writes stdout, so a workbook works with jq, awk, curl, sqlite, and everything else you already use.

render

Pixel perfect rendering

Render any range to a PNG, or a whole workbook to a PDF, drawn the way the app would draw it. Post a chart to Slack, or mail a report from cron.

// getting started

Your first sheet, start to finish

~/budget
# Create a workbook and see its sheets
nobie workbook new budget.xlsx
nobie sheet list budget.xlsx # Sheet1
# Write a value and a formula
nobie cell set budget.xlsx Sheet1!A1 --value 'Revenue'
nobie cell set budget.xlsx Sheet1!B1 --value 1000
nobie cell set budget.xlsx Sheet1!B2 --value '=B1*1.2'
# Read the evaluated result — the formula is actually computed
nobie cell read budget.xlsx Sheet1!B2 # 1200
nobie cell read budget.xlsx Sheet1!B2 --inputs # =B1*1.2
# Render a slice to PNG, or the whole book to PDF
nobie range render budget.xlsx Sheet1!A1:B2 --out preview.png
nobie workbook print budget.xlsx --out budget.pdf

tip: nobie --help, nobie <noun> --help, and nobie <noun> <verb> --help never go stale.

// naming things

Point at a cell

Every command takes a target (which workbook) and usually a selector (which cells).

TargetMeans
report.xlsxA file path. This is the default; no session needed.
@Report.xlsxA workbook you've held open with workbook open, for back-to-back edits.
file:@odd-nameEscape hatch: force a literal to be treated as a path.
--path PForce P to be a path regardless of how it looks.

A selector is a sheet-qualified cell or rectangle: Sheet1!A1, Sheet1!A1:C9, or a bare A1 with --sheet Sheet1. Quote sheets with spaces for your shell: 'Q1 Sales'!A1.

Input accepts A1 or absolute R1C1 anywhere (auto-detected). Output is A1 by default; the global --ref-style r1c1 flag flips it.

terminal
nobie cell set m.xlsx Sheet1!R1C1 --value '=2*21'
nobie cell read m.xlsx Sheet1!R1C1 --json --ref-style r1c1
# {"schema":"nobie.cells.v1","projection":"values","cells":[{"ref":"Sheet1!R1C1","value":"42"}]}

// the shape

One grammar for everything

Learn it once and the whole tool falls out of it. A noun, a verb, the workbook, and what to act on:

grammar
nobie <noun> <verb> <TARGET> [SELECTOR] [FLAGS]
NounVerbs / Actions
workbookopen, new, close, path, info, undo, print (PDF)
savesave in place, Save As, save a copy
sheetadd, rename, delete, list
cellset, read
rangeread, clear, paste, copy, cut, render (PNG)
styleset, read (effective styles), compact
calcrecalc, mode (automatic / manual / …)
sessionstart, stop, list, open, close (the local daemon)
scriptrun a readable spreadsheet program (replaces batch)
serveserve a workbook's defined-name HTTP APIs
versionversion & self-update (nobie update)

Sixteen things to do in a pipe

every recipe runs as written

01

CSV → formula-driven workbook

Pipe a CSV in, drop a live =SUM total under it, and bold the header row.

command

terminal
nobie workbook new sales.xlsx
nobie range paste sales.xlsx Sheet1!A1 --from - <<<$'Region\tQ1\tQ2\tTotal'
tail -n +2 sales.csv | tr ',' '\t' \
| nobie range paste sales.xlsx Sheet1!A2 --from -
nobie cell set sales.xlsx Sheet1!D5 --value '=SUM(D2:D4)'
nobie style set sales.xlsx Sheet1!A1:D1 --bold --fill '#1F4E78' --font-color white

stdout

stdout — recipe-01
$ nobie range read sales.xlsx Sheet1!A1:D5
Region Q1 Q2 Total
East 15000 18000 33000
West 12000 14500 26500
South 9000 11000 20000
79500

// over http

Serve a sheet as an API

Name a cell NOBIE_API__quote__INPUT__quantity and nobie serve turns the workbook into an HTTP service: defined names become JSON routes, inputs go in with a POST, and recalculated outputs come back. The spreadsheet is the backend.

serve.sh
# Defined names in pricing.xlsx:
# NOBIE_API__quote__INPUT__quantity -> request field "quantity"
# NOBIE_API__quote__INPUT__unit_price -> request field "unit_price"
# NOBIE_API__quote__OUTPUT__total -> response field "total"
nobie serve ./pricing.xlsx
# ...then from anywhere: discover the routes, POST inputs
curl -sS http://127.0.0.1:8000/apis
curl -sS http://127.0.0.1:8000/api/quote \
-H 'content-type: application/json' \
-d '{"quantity": 3, "unit_price": 19.95}'
stdout — serve
{"total":"59.85"}

The formula behind the total cell does the work; there's no handler to write. Each request leases an isolated replica of the workbook, applies the inputs, recalculates, reads the outputs, and restores the replica before responding — so callers never see each other's state and the file on disk is never modified. It binds to 127.0.0.1:8000 by default (--bind, --replicas to change), and caps request bodies at 1 MiB.

// the whole toolbox

Command reference

Every command is nobie <noun> <verb> <target>. Pick a noun to see its verbs and flags.

Workbook Commands

Create, inspect, print, undo, and open workbooks as background sessions.

terminal
nobie workbook new budget.xlsx # create empty workbook (--force to overwrite)
nobie workbook info budget.xlsx --json # path, dirty bit, calc mode
nobie workbook path budget.xlsx # print the on-disk path
nobie workbook undo budget.xlsx # undo the last change
nobie workbook print budget.xlsx --out b.pdf # render the WHOLE workbook to PDF
nobie workbook open /data/Budget.xlsx # open as a background session (prints handle)
nobie workbook close budget.xlsx --save # close a session (--save | --discard if dirty)

// good to know

Tricks worth stealing

Generate sheets from code

Any program can build a spreadsheet. Have it print nobie script sentences and pipe them in — a thousand cells land in one transaction.

Keep workbooks in git

It's just an .xlsx, and nobie can diff it by value. Wire it up as a git textconv and review spreadsheet changes in a pull request, like any other code.

Preview without opening anything

range render … --out p.png && open p.png gets you a styled snapshot in about a second, without launching the app.

Quote your sheet names

Sheet names with spaces need quotes for your shell: 'Q1 Sales'!A1. Same for any selector you build by hand and pipe in.

Own Your Craft.