# D2B – Spreadsheets for AI Agents

> Source: <https://d2b.dev/developers>
> Published: 2026-10-01 02:08:01+00:00

Take spreadsheets made for people in at the door, hand your agent typed, row-identified, versioned, governed tables, and return the result to humans as Excel in its original formatting. Not just answers — every number traceable to where it came from.

```
claude mcp add d2b --transport http https://d2b.dev/mcp/ \
  --header "Authorization: Bearer $D2B_PAT"

# Codex / Cursor / VS Code / Claude Desktop → docs.d2b.dev/ja/mcp
```

Letting an LLM write and run Python in a sandbox gets you an answer, but not how it got there — you can't trace it or run it again. D2B records the same work as transforms with lineage, so a changed input recomputes and every version can be restored.

``` python
from d2b import D2BClient

client = D2BClient(api_key="d2b_pat_...", base_url="https://d2b.dev")
wb = client.workbooks.create(title="monthly-sales")["id"]

# 1) a spreadsheet made for people in → typed tables (raw kept, lineage from day one)
client.sources.upload(wb, "sales_2026-06.xlsx", wait=True)

# 2) logic as a transform — {{ arg }} bindings keep lineage
client.transforms.create(
    wb, name="agg/monthly", kind="sql", artifact_name="product_sales",
    template='CREATE TABLE "{{ artifact_name }}" AS '
             'SELECT product, sum(amount) AS revenue FROM "{{ src }}" GROUP BY 1',
    args={"src": "sales"},
)

# 3) back to humans as Excel, 4) a named, revertible version
xlsx = client.export.tables(wb, tables=["product_sales"])
client.versions.commit(wb, "2026-06")
```

A foundation that survives an agent's mistakes: concurrent writes are caught, any number can be traced and rolled back, permissions hold at the data layer, and results go back to people as Excel.

Transforms are stored content-addressed; the DAG is queryable upstream and down. Snapshots, named versions, an op log and undo — plus a diff between any two versions: unified diffs of the transforms, rows touched, and every artifact the change reaches. An agent can find out why a number moved, fix it, and compare.

Every table is typed with row ids; writes require expected_version, so concurrent edits are never silently overwritten. A per-table row JSON Schema is available at runtime for constrained decoding.

mask / deny are enforced in the data layer — the same policy applies to SQL, export and MCP, with no side door. Audited.

xlsx / csv, write-back into the original workbook's formatting, live per-row Excel formulas, export = branch → re-import = 3-way merge. Round trips on Excel users' own terms.

Pull transforms (SQL / Python), sheets, charts and opted-in base tables as CSV into a repository, review them in a pull request, push them back. Reviewing the SQL an AI wrote before it counts becomes an ordinary workflow.

transforms/ sheets/ charts/ data/ plus d2b.json (the merge-base hashes).

git diff / PR. Transforms the chat agent wrote show up in the same place.

Only what changed: re-run, PUT, 3-way merge. Refused when both sides moved (--force overrides). The git sha becomes a named version.

```
d2b pull --workbook WB --data customers     # transforms/ sheets/ charts/ data/ + d2b.json
git add -A && git commit -m "pull from D2B"
d2b push --dry-run
d2b push --commit "$(git rev-parse --short HEAD)"
d2b github-workflow > .github/workflows/d2b.yml  # push on merge, scheduled pull → PR
```

Billing is metered in ops (data operations) and GB-months. Calls from your own agent with your own LLM carry no LLM charge — LLM usage is added only when you use D2B's built-in agent. Capability is identical on every plan.

1 op = one write-side data operation (row writes, transform runs, commits, version operations). Reads are currently not billed.

Mint a PAT and run one claude mcp add. Five minutes with the CLI or an SDK.
