Example · wolf transact
An agent's broken edit, refused before the file changes
Run wolf transact with the edit and the invariants it must keep. The edit is applied in memory and checked, and the workbook is written only when every check passes. In this run, an agent's Q3 close edit failed 3 of 3 declared checks, with exit code 7 and a byte-identical input file. A repaired request then committed with exit 0.
3 failed checks, exit 7, and the same file hash before and after
The workbook holds a Regions table with Q2 and Q3 revenue, a Q3 ledger control of 21,750, and a board summary sheet. The agent's task: Post the final Q3 actuals: Europe 6,240 and APAC 4,410. Then fill the Summary line Variance to ledger. Its request has two mistakes: APAC's 4,410 goes to the Q2 column, and the variance formula names a table column, Q3 Actual, that the table lacks. Each step below is read from the receipts.1
- 1. Request3 ops, 3 checks
- 2. Verdicts3 failed, exit 7
- 3. Diskhash unchanged
- 4. Repair2 ops changed
- 5. Commitexit 0, committed
- 1
The agent's request
bad-request.jsonTask: Post the final Q3 actuals: Europe 6,240 and APAC 4,410. Then fill the Summary line Variance to ledger.
table:Regions/row:Europe/col:Q36,240as askedtable:Regions/row:APAC/col:Q24,410mistakesheet:Summary/cell:B7=SUM(Regions[Q3 Actual])-Regions!C10mistake
Declared with it:
scope, the 6 cells the task may change;no-errors, no new error values; andledger, the Q3 column summing to the ledger control in Regions!C10. - 2
Verdicts: the edit is applied in memory and checked
exit 7invariant-violatedcommitted: false- FAIL
scopeonly-changessheet:#1/cell:B8, table:Regions/row:APAC/col:Q2, sheet:#2/cell:B4 changed but are not declared
Cells: Regions!B8, Regions table, APAC row, Q2 column, Summary!B4
- FAIL
no-errorsno-new-errorsnew errors at sheet:#2/cell:B7
Cells: Summary!B7
- FAIL
ledgerreconcile21750 != 21440 (tolerance 0.005)
Cells: Regions!C10
- PASS
address-resolutionaddress-resolution, implicit - PASS
parts-preservedparts-preserved, implicit10 of 12 input parts byte-identical
In the receipt, the diff the edit would have made: 7 cells modified and 1 added. Rows named by a failed verdict are marked.
sheet:#1/cell:B8Regions!B8modified, recalculated:19,400 →20,010sheet:#1/cell:C8Regions!C8modified, recalculated:21,200 →21,440table:Regions/row:Europe/col:Q3Regions table, Europe row, Q3 columnmodified, op 0:6,000 →6,240table:Regions/row:APAC/col:Q2Regions table, APAC row, Q2 columnmodified, op 1:3,800 →4,410sheet:#2/cell:B3Summary!B3modified, recalculated:21,200 →21,440sheet:#2/cell:B4Summary!B4modified, recalculated:19,400 →20,010sheet:#2/cell:B5Summary!B5modified, recalculated:9.3% →7.1%sheet:#2/cell:B7Summary!B7added, op 2:formula written
- 3
Disk: nothing written
input unchanged- sha256 before
- f4a778a56b0edb331e85d3193b2938ab5030e441c960fa453cecbae23839e240
- sha256 after
- f4a778a56b0edb331e85d3193b2938ab5030e441c960fa453cecbae23839e240 (identical)
- out/ folder
- not created
- receipt outputs
- []
- unwritten result
- bebdd7671be398d17e18cc98165a63ce21c7a4c8bcfb4a7e52bf30a97ac05928
- 4
The repaired request
fixed-request.jsonWith the cell addresses from the failed verdicts, the repair is local: 2 ops change, and the invariants stay exactly as declared.
op 1
table:Regions/row:APAC/col:Q2 4,410
table:Regions/row:APAC/col:Q3 4,410
op 2
sheet:Summary/cell:B7 =SUM(Regions[Q3 Actual])-Regions!C10
sheet:Summary/cell:B7 =SUM(Regions[Q3])-Regions!C10
- 5
Commit: every check passes
exit 0committed: true- PASS scope
- PASS no-errors
- PASS ledger 21750 = sum 21750
- PASS address-resolution
- PASS parts-preserved 10 of 12 input parts byte-identical
sheet:#1/cell:C8Regions!C8modified, recalculated:21,200 →21,750table:Regions/row:Europe/col:Q3Regions table, Europe row, Q3 columnmodified, op 0:6,000 →6,240table:Regions/row:APAC/col:Q3Regions table, APAC row, Q3 columnmodified, op 1:4,100 →4,410sheet:#2/cell:B3Summary!B3modified, recalculated:21,200 →21,750sheet:#2/cell:B5Summary!B5modified, recalculated:9.3% →12.1%sheet:#2/cell:B7Summary!B7added, op 2:formula written
- parts written
- xl/worksheets/sheet1.xml, xl/worksheets/sheet2.xml
- parts preserved
- 10, byte for byte
- output sha256
- 2ce514439fd7224f69063c03981ba084000496a2bcafab5aa614061d0acf6444
- input sha256
- f4a778a56b0edb331e85d3193b2938ab5030e441c960fa453cecbae23839e240 (unchanged)
5 of 5 verdicts passed. The committed copy is written to
out/beside the input.
Watch both runs in a terminal
In the clip, both requests are run against the published workbook with the Wolf 0.2.17 release binary. The first run ends with exit 7 and an unchanged digest; the second ends with exit 0 and 5 passing checks.
wolf transact --request bad-request.json > bad-receipt.json; echo "exit $?" jq -r -f verdicts.jq bad-receipt.json shasum -a 256 q3-close.xlsx # same digest as before the run wolf transact --request fixed-request.json > fixed-receipt.json; echo "exit $?" jq -r -f verdicts.jq fixed-receipt.json
Save the same faulty request with openpyxl and get no warning
Apply the same three edits with openpyxl 3.1.5 and the save exits 0 with 0 warnings. The saved copy has 6 of 6 formula cells with no cached value, so without recalculation they read as empty. After a LibreOffice recalculation, the Q3 total is 21,440 against a ledger control of 21,750, the Q2 total is 20,010, and the variance cell shows #NAME?.23


| Cell | Before | openpyxl, faulty | Wolf, repaired |
|---|---|---|---|
| Q3 totalRegions!C8 | 21,200 | 21,440 | 21,750 |
| Ledger controlRegions!C10 | 21,750 | 21,750 | 21,750 |
| Variance to ledgerSummary!B7 | empty | #NAME? | 0 |
| Q2 totalRegions!B8 | 19,400 | 20,010 | 19,400 |
| Growth, Q2 to Q3Summary!B5 | 9.3% | 7.1% | 12.1% |
Declare the rules beside the edit
Put invariants in the request, next to the ops. This run uses three kinds: only-changes for the cells the task may change, no-new-errors against new error values, and reconcile to compare a control cell with an aggregate of a table column.4 Every run also gets two implicit checks, address-resolution and parts-preserved. On commit, only the changed parts of the package are rewritten: here 2 worksheets, with 10 parts copied byte for byte.5
[
{
"id": "scope",
"kind": "only-changes",
"addresses": [
"table:Regions/row:Europe/col:Q3",
"table:Regions/row:APAC/col:Q3",
"sheet:Regions/cell:C8",
"sheet:Summary/cell:B3",
"sheet:Summary/cell:B5",
"sheet:Summary/cell:B7"
]
},
{
"id": "no-errors",
"kind": "no-new-errors"
},
{
"id": "ledger",
"kind": "reconcile",
"left": "sheet:Regions/cell:C10",
"right": "table:Regions/col:Q3",
"aggregate": "sum",
"tolerance": 0.005
}
]Reproduce every number and image
Download run_demo.py, fixture.py, openpyxl_edit.py, card.py, verdicts.jq, and refused-edit.tape into an empty folder, point WOLF_BIN at the Wolf 0.2.17 binary, and install LibreOffice, Poppler, jq, VHS, and ffmpeg. Run run_demo.py to build the workbook, run both requests and the openpyxl comparison, render the sheets, record the clip, draw the share card, and write results.json and SHA256SUMS.6
export WOLF_BIN=/path/to/wolf # wolf 0.2.17 (commit dbd2defe08a522e38bcaff9dfddb64876deca10d) export DEMO_OUT="$PWD/out" CARD_FONT=/path/to/Archivo.ttf uv run --no-project --python 3.13 --with openpyxl==3.1.5 \ --with pillow==12.3.0 python run_demo.py
- Input workbook (q3-close.xlsx)
- Faulty request (bad-request.json)
- Receipt for the faulty request (bad-receipt.json)
- Repaired request (fixed-request.json)
- Receipt for the repaired request (fixed-receipt.json)
- Workbook committed by Wolf (q3-close-wolf.xlsx)
- Workbook saved by openpyxl (q3-close-openpyxl.xlsx)
- Terminal clip (refused-edit.mp4)
- Terminal clip, GIF (refused-edit.gif, 406 KB)
- Every published number (results.json)
- Checksums (SHA256SUMS)
- Measurement script (run_demo.py)
- Fixture script (fixture.py)
- openpyxl comparison (openpyxl_edit.py)
- Share card script (card.py)
- Verdict printer (verdicts.jq)
- Clip script for VHS (refused-edit.tape)
- Share card (card.png)
