Three ways an agent can touch a model — and the one it reaches for
openpyxl on a binary .xlsx, raw .deepcell XML, or the deepcell CLI. Same task, three very different affordances. Here's why the agent picks the CLI.
Give a coding agent a financial model and a job — "add a downside scenario, then tell me where FCF turns negative" — and the first thing it decides, silently, is how to touch the file. That choice is made before a single number changes, and it determines everything that follows: how many round-trips the job takes, whether the edits are safe, and whether you can trust the result.
There are three ways to touch a model that Claude might reach for. They look interchangeable from the outside. They are not.
Option 1: openpyxl on a binary .xlsx#
This is the reflex for anyone who's automated a spreadsheet in Python. It is also the worst fit for an agent, for reasons that compound.
The file is opaque. A .xlsx is a zipped bundle of XML parts. The
agent can't cat it, can't grep it, can't diff it. To see one value
it has to write and run a script:
from openpyxl import load_workbook
wb = load_workbook("model.xlsx", data_only=True)
print(wb["Model"]["C7"].value)Every observation is a round-trip through code it authored. Want the next cell? Another script, or a longer one that guesses at the layout.
The formulas are dead. openpyxl hands you either the formula string
or the last value Excel cached (data_only=True) — never a live
recalculation. Change an input and every dependent cell is stale until
something re-opens the workbook in Excel or LibreOffice. The agent adds a
downside scenario and then genuinely cannot see what it did to FCF without
booting a calculation engine it doesn't have in-process.
There are no semantics. A cell is Model!C7. Nothing says this is
2027 revenue under the base case. The agent reconstructs meaning from
position and prays the layout doesn't shift a row. Merge a cell, insert a
column, and its mental map silently rots.
Writing back is lossy. Preserving styles, merged ranges, named ranges, and charts through an openpyxl round-trip is a minefield; plenty gets dropped or mangled. And there's no history — the edit is a binary overwrite with no record of what changed or why.
openpyxl earns its place in exactly one job: getting data out of a legacy workbook and into something better. As a working surface for an agent, it's a last resort.
Option 2: hand-editing the .deepcell XML#
A .deepcell is plain XML — greppable,
diffable, git-native. So the obvious next thought is: skip the tooling,
let the agent read and write the file directly.
For reading, this is genuinely good. The agent can open the file, scan the ItemDefs and CalcDefs, and build an accurate mental model without running anything. Structure is legible in a way a binary blob never is.
For writing, it's a trap. The entire value of the format — dependency tracking, constraint enforcement, Status and Context rules, schema validation — lives in the calc engine, not in the raw text. Hand-edit the XML and you sail straight past all of it. It's trivially easy to write an internally inconsistent document:
- a formula referencing an Item that doesn't exist,
- a Value that violates its own ItemDef guardrail,
- a dimension tuple that no longer resolves.
Nothing catches you, because nothing ran. And batch changes across many dimensioned values as raw string surgery is precisely the kind of fiddly, namespace-sensitive work where an agent introduces an off-by-one it won't notice until much later.
Direct XML is the right tool for reading structure or a single surgical patch. It's a poor primary write path.
Option 3: the deepcell CLI (or the in-process tool)#
This is the interface the agent actually wants, because it was designed around the affordances an agent has:
Read cheaply and structured. ls, cat, describe, and query
inspect the model at the right altitude with no code to author — and
query returns resolved, live-calculated values with their dimensions
attached. The agent asks "what's FCF in 2027 under downside?" and gets a
number that reflects the edit it just made.
Write through the engine. defs apply and batch-edit go through
Jingwei, so dependency recalculation, constraint checks, and schema
validation all run on every change. The agent cannot silently corrupt
the document — an illegal edit comes back as an error, not a landmine.
Versioned by construction. Every commit carries a title and
rationale, so the file's history reads as a chain of why, not a binary
overwrite. The seam between "the agent did this" and "I did this" stays
legible after the fact.
Self-describing and predictable. Every CLI command is a thin
pass-through to a Jingwei endpoint — Click flags mirror the pydantic
fields one-to-one. The agent discovers capabilities through --help and
the in-product guide topics instead of reverse-engineering a file
format. And the CLI, the MCP deepcell(command) tool, and the
subagents' in-process tool all dispatch to the same service layer, so
behavior is identical whether Claude is at a terminal or orchestrating a
build.
The same task, three times#
openpyxl + .xlsx | raw .deepcell XML | deepcell CLI/tool | |
|---|---|---|---|
| Read a value | write & run a script | read the file | query |
| See live results after an edit | ❌ needs Excel/LibreOffice | ❌ bypasses the engine | ✅ recalculated |
| Illegal edit caught | ❌ | ❌ | ✅ validation error |
| Preserves structure/styles | lossy | manual | ✅ |
| Versioned with rationale | ❌ | git only | ✅ |
| Agent verdict | ingestion only | read / one-off | preferred |
The through-line is simple. openpyxl makes the agent guess and hope. Raw XML lets it read but not safely write. The CLI turns a modeling task into a sequence of legible, validated, reversible commands — which is exactly the shape an agent is good at.
That's the whole thesis behind a new file format: the format is the source of truth, and the CLI is how you touch it without breaking it. Reach for raw XML when you only need to read. Drop to openpyxl only to drag data out of a legacy workbook. For everything else — the actual work of building and changing a model — the agent reaches for the CLI, and it's right to.