Round-tripping with Excel
Values flow both ways. Structure travels one direction at a time. Here's why that's the right tradeoff.
"If I edit in Excel, does .deepcell stay in sync? And back?"
We get this question every time we demo. It's the right question. Almost every "export to Excel" feature in every modeling tool I've used is a one-way trapdoor. You export, you edit in Excel, and you've forked. The original file is stale by Tuesday. Whatever logic the source tracked is no longer authoritative. The export is a souvenir.
That's why "export to xlsx" is a checkbox on a feature page and not a workflow anyone actually trusts.
DeepCell does this differently. Two directions, each honest about what it carries.
Direction 1 — .deepcell → Excel#
deepcell to-excel acme_dcf.deepcell -o acme_dcf.xlsx --formulasThat writes a workbook where every Jingwei formula is translated into a
live Excel formula, not a baked value. Open it in plain Excel — no
add-in, no plugin, no login — and it behaves like any xlsx you've ever
touched. Same recalcs. Same F9. Same cells. The person on the other
end of the email doesn't need to know DeepCell exists. They get a
spreadsheet.
If you'd rather hand someone a snapshot they can't poke:
deepcell to-excel acme_dcf.deepcell -o acme_dcf_snapshot.xlsxValues only. Useful for IC packets, audit committees, or anyone who shouldn't be retyping the WACC.
This direction is the easy one. The format owns the structure, the export is a render. Same as printing a PDF.
Direction 2 — Excel → .deepcell#
This is the part most tools punt on. We didn't.
The Excel Add-in is a taskpane — React inside Office.js — that loads
a .deepcell straight from your workspace and renders it into the
worksheet. You're not looking at an export. You're looking at the file.
When you edit a cell, the Add-in's push() sends the change to the
/batch-edit API. The server recalculates dependents, returns the
updated values, and the Add-in pulls them back. A background pull()
runs every thirty seconds in case someone else (or an agent) is editing
the same model from the web app.
Every push is a git commit. The version history isn't a side feature — it's the same history you get from the CLI, the same history the agent reads when it wants to know how a number got there.
The honest scope#
Here's the part I want to be precise about, because it's where most products lie:
| What syncs | Direction |
|---|---|
| Value edits to existing cells | Both ways |
| New items, new periods, new formulas | One way at a time |
Values are bidirectional. Edit Revenue / 2026A / Base / Actual in
Excel, the model recalcs. Edit it in the web app, your Excel taskpane
pulls the new number. Fine.
Structure is one direction at a time. If you want to add a new line item, a new fiscal period, or a new CalcDef, you do it through the format — either by hand with the CLI:
deepcell defs add-calc acme_dcf.deepcell \
--name "Operating Margin" \
--formula "=Operating Income / Revenue"…or by asking the agent to do it for you. Either way, the next time the Add-in pulls, the new row is there.
If you went the other way — added a row in Excel and want it back in
.deepcell — you re-import. We don't try to guess what your new row
means by looking at where it sits and what it's named.
This is a tradeoff, and I want to defend it. Excel's "schema by convention" — the idea that this row is a subtotal because it's bold, that this column is a forecast because it's in italics — doesn't propagate cleanly back into a typed format. A parser that tried would have to make decisions you should make yourself. Better to keep the format as the place where structure is declared, and Excel as the surface where values get edited. See why a new file format for the longer argument.
The import-from-Excel side is its own story — covered in bring your Excel model.
On conflicts#
If you edit Revenue / 2027E in Excel while your colleague edits the
same cell in the web app, the Add-in notices. It tracks your local
edits against the server version, and on the next sync it surfaces the
conflict rather than silently overwriting one of you.
This is the same model any decent collaborative tool uses. The difference is that we have a place to put the conflict — the format has versioned cells, the cells have authors, and the resolution becomes another commit. It's not magic. It's just that a typed format gives the collaboration layer something to grip.
One adapter is a coincidence. Two is a contract.#
A small architecture aside, then I'll stop.
The grid you see in the web app is rendered from a RenderPlan IR. The
grid you see in the Excel taskpane is rendered from the same
RenderPlan IR. Handsontable on the web, Office.js in Excel — two
adapters, one intermediate representation. The cell in the browser and
the cell in the taskpane are the same cell. They have to be. Otherwise
the round-trip story above is a lie, and one of the two surfaces is
quietly lying about what's in the file.
We had this surface-by-surface for a while. It was bad. The IR is what makes the rest of this honest.
Coexistence, not replacement#
DeepCell lives above Excel. Not against it.
If your daily work is Ctrl-arrow and =SUMIFS, stay in Excel. Use the
Add-in. Let .deepcell hold the structure, the formulas, the version
history, and the reasoning behind why the model is shaped the way it
is. You won't notice us most of the time, which is the point.
If your daily work is the web app — because you're collaborating with an agent, or you're building from scratch, or you just prefer it — use the web app. Drop to Excel only when you need to send something to someone who lives there.
Both workflows are real. Neither is wrong. The format is what makes them the same model.
See it for yourself — open a sample .deepcell in the playground. Edit a value, watch the dependents recalculate, inspect the reasoning behind any number.