A standalone, read-only preservation gate for .xlsx and .xlsm files.
Compare an original workbook with a candidate produced by an agent, script, or
library. spreadsheet-guard audits OOXML structure, formulas, cached values, and
feature relationships without modifying either input. It emits deterministic
JSON and automation-friendly exit codes.
- MIT licensed
- No proprietary runtime or service dependency
- Local files only
- Fail-closed on invalid or incomplete evidence
Requires Python 3.11 or newer.
pip install spreadsheet-guard
spreadsheet-guard before.xlsx after.xlsx --output preservation-report.json
The command writes the complete report to preservation-report.json and a
one-line summary to stdout:
{"report": "preservation-report.json", "schema_version": 1, "status": "passed"}| Status | Exit code | Meaning |
|---|---|---|
passed |
0 | Every configured preservation dimension passed. |
failed |
1 | At least one configured dimension found a regression. |
unassessed |
1 | Required evidence was unavailable or a dimension was disabled. |
error |
2 | Inputs, policy, or execution were invalid. |
From a clone of this repository, these commands target bash or zsh and use repo-relative paths:
uv sync
uv run spreadsheet-guard \
examples/formula-integrity/before.xlsx \
examples/formula-integrity/after-intact.xlsx \
--output /tmp/spreadsheet-guard-passed.json
uv run spreadsheet-guard \
examples/formula-integrity/before.xlsx \
examples/formula-integrity/after-formula-damaged.xlsx \
--output /tmp/spreadsheet-guard-failed.jsonThe first command exits 0 with passed. The second exits 1 with failed
because SUM(A1:A2) changed to SUM(A1:A1). The frozen reports are checked in
at:
This compact proof demonstrates the packaged engine and report contract. It does not establish universal Excel compatibility or business-output correctness.
The default policy requires all five dimensions to remain unchanged:
- Macro inventory
- External-link inventory
- Worksheet inventory and names
- Formula integrity
- OOXML package integrity
Package integrity checks part relationships, XML parseability, cached formula values, and semantic fingerprints for workbook features such as charts, defined names, data validation, conditional formatting, drawings, external links, and pivot-related metadata.
The strict default also reports intentional formula or structural changes. The caller must compare each finding with the intended edit.
Pass --policy policy.json to replace the strict default:
spreadsheet-guard before.xlsx after.xlsx \
--output preservation-report.json \
--policy policy.json
{
"macro_inventory": {"mode": "unchanged"},
"external_link_inventory": {"mode": "unchanged"},
"worksheet_inventory": {
"mode": "unchanged",
"expected_names": ["Inputs", "Model", "Outputs"]
},
"formula_integrity": {"mode": "unchanged"},
"package_integrity": {"mode": "unchanged"}
}A custom policy should enumerate all five dimensions when a passed result is
required. A dimension set to null is reported as unassessed.
from pathlib import Path
from spreadsheet_guard import guard_workbooks
outcome = guard_workbooks(
Path("before.xlsx"),
Path("after.xlsx"),
Path("preservation-report.json"),
)
print(outcome.status)- The Guard evaluates preservation. It does not determine whether formulas, assumptions, or business logic are correct.
- The Guard is read-only. It reports findings and does not repair either workbook.
- Inputs are limited to OOXML
.xlsxand.xlsmworkbooks. - A clean report applies only to the configured dimensions and the supplied before-and-after pair.
WolfXL applies policy before a workbook
write, runs independent verification, and commits only accepted candidates.
spreadsheet-guard is the free, read-only audit surface.
MIT. See LICENSE.