{"id":"5fd2a0a5-9933-4250-9caf-3ff49e4a0aa2","slug":"agent-spreadsheet","kind":"mcp","name":"agent-spreadsheet","summary":"MCP server for spreadsheet analysis and editing. Slim, token-efficient tool surface designed for LLM agents.","owner":"PSU3D0","repoUrl":"https://github.com/PSU3D0/agent-spreadsheet","license":"Apache-2.0","licenseTier":"permissive","trust":"community","stars":62,"match":null,"fewStars":false,"format":"mcp","createdAt":"2025-09-19T01:56:38.000Z","addedAt":"2026-10-14T05:17:08.066Z","logoUrl":"https://avatars.githubusercontent.com/u/10227908?u=699be3f0fd01680b4c21a3d60903b311bc2c0f70&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["files-documents","cloud-infra"],"tags":["spreadsheet","spreadsheet-ai","spreadsheet-mcp","spreadsheet-agent"],"runtime":"docker","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-17T13:54:48.825Z","sample":false,"url":"https://conduits.dev/tools/agent-spreadsheet","language":"Rust","transports":["stdio"],"install":{"docker":"ghcr.io/psu3d0/spreadsheet-mcp:0.11.1-full"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# agent-spreadsheet\n\n[![CI](https://github.com/PSU3D0/agent-spreadsheet/actions/workflows/ci.yml/badge.svg)](https://github.com/PSU3D0/agent-spreadsheet/actions/workflows/ci.yml)\n[![Crates.io](https://img.shields.io/crates/v/agent-spreadsheet-mcp.svg)](https://crates.io/crates/agent-spreadsheet-mcp)\n[![npm](https://img.shields.io/npm/v/agent-spreadsheet.svg)](https://www.npmjs.com/package/agent-spreadsheet)\n[![License](https://img.shields.io/crates/l/agent-spreadsheet-mcp.svg)](https://github.com/PSU3D0/agent-spreadsheet/blob/main/LICENSE)\n\n![agent-spreadsheet](https://raw.githubusercontent.com/PSU3D0/agent-spreadsheet/main/assets/banner.jpeg)\n\n**agent-spreadsheet is the tool interaction service for agent-based spreadsheet usage.**\n\nIt gives agents a safe, inspectable, token-efficient way to **read, analyze, mutate, verify, and operationalize Excel workbooks** without falling back to brittle UI automation.\n\nIf you want an agent to work with spreadsheets like a real system instead of a screenshot puppet, this is the stack.\n\n---\n\n## What this project is\n\nagent-spreadsheet ships a unified spreadsheet interaction layer across three surfaces:\n\n| Surface | Binary / Package | Mode | Best for |\n| --- | --- | --- | --- |\n| **CLI** | `agent-spreadsheet` / `asp` | Stateless files + resident sessions | One-shot pipelines or retained multi-turn workbook editing |\n| **MCP server** | `agent-spreadsheet-mcp` | Stateful | Multi-turn agent sessions, workbook caching, fork/recalc workflows |\n| **TypeScript SDK** | `agent-spreadsheet-sdk` | Library | App integrations — drives the server's canonical `/v1` route, or runs fully in-process via the embedded WASM engine (no server required) |\n\nThe WASM build (`agent-spreadsheet-wasm`) is the SDK's local runtime, not a separate product surface: JS and TypeScript code targets one object model and the execution substrate (server vs embedded engine) is a configuration choice.\n\nIn 0.16 these surfaces share the resident Rust document/evaluator runtime and 32-operation registry. Explicit native sessions automatically start a private journal-backed host. SDK/WASM and genuine just-bash sessions retain their history in memory; XLSX export saves a document snapshot, not a restartable session journal. Warm edit/recalculate/read loops avoid XLSX serialization and repeated evaluator ingestion. See [runtime guarantees and limits](docs/architecture/resident-session-runtime.md) and the [SDK/just-bash examples](npm/agent-spreadsheet-sdk/README.md).\n\nSupported workbook modes:\n\n- `.xlsx` / `.xlsm` — read + write\n- `.xls` / `.xlsb` — discovery/read-oriented workflows only\n\n## Powered by Formualizer\n\nDefault in-process calculation uses **[Formualizer](https://github.com/PSU3D0/formualizer)** — a permissively licensed (MIT/Apache-2.0) spreadsheet engine written in Rust: formula parsing, dependency-graph recalculation, 400+ Excel functions, dynamic arrays, and deterministic evaluation built for agents. No Excel COM or headless LibreOffice is required. Optional LibreOffice integration remains available, but Formualizer is the release-critical backend.\n\nThat native engine is why this project can offer what most spreadsheet tooling for agents cannot: **recalculate the actual workbook, trace which cells changed and why, and prove it** — not just read cached values or push blind edits.\n\nEmbedding spreadsheet logic in your own product rather than driving workbooks as an agent? Use [Formualizer](https://github.com/PSU3D0/formualizer) directly (Rust, Python, JS/WASM).\n\n---\n\n## Why agents use agent-spreadsheet\n\n### Built for tool use, not just humans\n- deterministic JSON contracts\n- schema and example discovery from the CLI itself\n- explicit pagination and compact output modes\n- machine-readable warnings and error envelopes\n\n### Safe mutation, not blind mutation\n- dry-run first workflows\n- stateless output modes and overwrite safety\n- event-sourced session editing\n- verification surfaces for proving downstream outcomes\n- structural impact analysis before risky workbook changes\n\n### Spreadsheet-aware, not generic file editing\n- region detection\n- table and footer-aware append helpers\n- template row / row band cloning\n- formula-specific replace and diagnostics\n- named range CRUD\n- recalculation + diff + proof flows\n\n### Good agent ergonomics\n- nested command groups with legacy alias compatibility\n- token-efficient reads\n- exact-cell inspection and layout inspection\n- workflow helpers for the repetitive parts agents usually get wrong\n\n---\n\n## What is new / what makes this stack different\n\nThe current surface is much stronger than a plain “read some cells” tool. Major capabilities now include:\n\n- **`asp` as the primary CLI** with `agent-spreadsheet` preserved as a compatibility alias\n- **grouped verification** via `asp verify proof` and `asp verify diff`\n- **preview-first workflow helpers** for:\n  - `write append`\n  - `write clone-template-row`\n  - `write clone-row-band`\n- **formula-safe batch workflows** with parse-policy diagnostics\n- **cell/layout/export/import inspection surfaces**\n- **named range management** (`write name define|update|delete`)\n- **formula-only replacement** (`write formulas replace`)\n- **event-sourced session editing** with log, branch, undo/redo, fork, apply, and materialize\n- **SheetPort manifest lifecycle + execution** for contract-driven spreadsheet automation\n\n---\n\n## Install\n\n### Shell installer\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/PSU3D0/agent-spreadsheet/main/install.sh | sh\n```\n\nThe installer downloads a prebuilt CLI to `~/.local/bin` and creates the `asp` command. Pin a release with `ASP_VERSION=0.16.0`, set `ASP_INSTALL_DIR` to choose another destination, or pass `--mcp` to install the MCP server too:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/PSU3D0/agent-spreadsheet/main/install.sh | sh -s -- --mcp\n```\n\n### npm\n\n```bash\nnpm i -g agent-spreadsheet\n```\n\nThis installs both `asp` (the primary command) and `agent-spreadsheet` (the compatibility alias) from a prebuilt native binary. No Rust toolchain is required.\n\n### cargo-binstall\n\n```bash\ncargo binstall agent-spreadsheet\n```\n\nThis installs the prebuilt CLI in seconds.\n\n### Cargo\n\n```bash\ncargo install agent-spreadsheet --features recalc --bin asp --bin agent-spreadsheet\n```\n\nThis builds the CLI from source. Formualizer (the native Rust recalc engine) is included by default.\n\n### mise\n\n```bash\nmise use -g \"ubi:PSU3D0/agent-spreadsheet[exe=asp]\"\n\n# Homebrew\nbrew install psu3d0/tap/agent-spreadsheet\n```\n\n### MCP server\n\n```bash\ncargo install agent-spreadsheet-mcp\n```\n\n### Docker\n\n```bash\n# Read-only / slim\ndocker pull ghcr.io/psu3d0/agent-spreadsheet-mcp:latest\n\n# Write + recalc + screenshots\ndocker pull ghcr.io/psu3d0/agent-spreadsheet-mcp:latest-full\n```\n\n### JavaScript SDK\n\n```bash\nnpm i agent-spreadsheet-sdk\n```\n\n### Prebuilt binaries\n\nDownload raw binaries and archives from [GitHub Releases](https://github.com/PSU3D0/agent-spreadsheet/releases).\n\nPublished native assets include:\n- Linux x86_64\n- Linux arm64\n- macOS x86_64\n- macOS arm64\n- Windows native binaries are not shipped for 0.16; native release validation targets Linux and macOS\n\n---\n\n## Start here: the core workflows\n\n## 1) Orient the workbook before reading cells\n\n```bash\n# What sheets are here?\nasp read sheets data.xlsx\n\n# What regions/tables/parameter blocks does this sheet contain?\nasp read overview data.xlsx \"Model\"\n\n# What named items are available?\nasp read names data.xlsx\n\n# Read a structured region as a table\nasp read table data.xlsx --sheet \"Model\"\n```\n\n## 2) Inspect exactly what an agent needs\n\n```bash\n# Raw values for exact ranges\nasp read values data.xlsx Model A1:C20\n\n# Detail-view for targeted cells (value / formula / cached / style triage)\nasp read cells data.xlsx Model B2 D10:F12\n\n# Layout-aware rendering for a bounded range\nasp read layout data.xlsx Model --range A1:H30 --render both\n\n# Export a bounded range to csv or grid json\nasp read export data.xlsx Model A1:H30 --format csv --output model.csv\n```\n\n## 3) Do a safe stateless edit → recalc → proof → diff loop\n\n```bash\nasp workbook copy data.xlsx /tmp/draft.xlsx\nasp write cells /tmp/draft.xlsx Inputs \"B2=500\" \"C2==B2*1.1\"\nasp workbook recalculate /tmp/draft.xlsx\nasp verify proof data.xlsx /tmp/draft.xlsx --targets Summary!B2,Summary!B3 --named-ranges\nasp verify diff data.xlsx /tmp/draft.xlsx --details --limit 50\n```\n\nA representative label-mode lookup:\n\n```bash\nasp analyze find-value data.xlsx \"Net Income\" --mode label --label-direction below\n```\n\n## 4) Preview structural risk before mutating the workbook\n\n```bash\nasp analyze ref-impact data.xlsx --ops @structure_ops.json --show-formula-delta\n```\n\nThis is intentionally read-only. It surfaces shifted spans, absolute-reference warnings, token counts, and optional before/after formula samples.\n\n## 5) Use workflow helpers instead of reinventing row logic\n\n```bash\n# Stateless batch writes\nasp write batch transform data.xlsx --ops @ops.json --dry-run\nasp write batch style data.xlsx --ops @style_ops.json --dry-run\n\n# Append rows into a detected region or table, respecting footer rows when present\nasp write append data.xlsx --sheet Revenue --table-name RevenueTable --from-csv rows.csv --header --dry-run\n\n# Clone one template row with preview-first planning\nasp write clone-template-row data.xlsx --sheet Inputs --source-row 8 --after 8 --count 3 --dry-run\n\n# Clone a contiguous row band repeatedly\nasp write clone-row-band data.xlsx --sheet Forecast --source-rows 12:16 --after 16 --repeat 4 --dry-run\n```\n\n## 6) Use a stateful session when the edit story gets complex\n\n```bash\nasp session start --base data.xlsx --workspace .\nasp session op --session <id> --ops @edit.json --workspace .\nasp session apply --session <id> <staged_id> --workspace .\nasp session materialize --session <id> --output result.xlsx --workspace .\n```\n\nAnd when you need proper history and branching:\n\n```bash\nasp session log --session <id> --workspace .\nasp session fork --session <id> scenario-a --workspace .\nasp session undo --session <id> --workspace .\nasp session redo --session <id> --workspace .\nasp session checkout --session <id> <op_id> --workspace .\n```\n\n## 7) Turn workbook interfaces into contracts with SheetPort\n\n```bash\n# Discover candidate ports from workbook structure\nasp sheetport manifest candidates model.xlsx\n\n# Validate or normalize a manifest\nasp sheetport manifest validate manifest.yaml\nasp sheetport manifest normalize manifest.yaml\n\n# Bind-check a workbook against a manifest\nasp sheetport bind-check model.xlsx manifest.yaml\n\n# Execute the manifest with JSON inputs\nasp sheetport run model.xlsx manifest.yaml --inputs @inputs.json\n```\n\n---\n\n## CLI overview\n\nThe primary CLI is **`asp`**.\n\n`agent-spreadsheet` remains available as a compatibility alias, so both of these are valid:\n\n```bash\nasp read sheets data.xlsx\nagent-spreadsheet read sheets data.xlsx\n```\n\n### Preferred command groups\n\n- `asp read ...`\n- `asp analyze ...`\n- `asp write ...`\n- `asp workbook ...`\n- `asp verify ...`\n- `asp session ...`\n- `asp sheetport ...`\n\n### Legacy aliases\n\nLegacy flat commands are still normalized to the new nested surface where practical. That makes migration easier for older prompts, docs, and automation.\n\n### Discoverability built into the CLI\n\nWhen an agent is unsure of payload shape, it can ask the tool directly:\n\n```bash\nasp operations                  # CLI-supported runtime subset\nasp registry --all              # complete host-independent registry + schemas\nasp schema read_cells\nasp example read_cells\nasp schema write batch transform\nasp example write batch transform\nasp schema session op transform.write_matrix\nasp example session op transform.write_matrix\n```\n\nCanonical machine calls use the same registry and dispatcher as other surfaces. `asp schema <canonical-op>` and `asp example <canonical-op>` project the native adapter contract: `resource_id` and, for verification, `baseline_resource_id` are omitted from required JSON because `--bind` and `--baseline` inject ephemeral resources. The host-independent `asp registry --all` remains unchanged.\n\n```bash\nasp op read_cells --bind data.xlsx --json '{\"sheet_name\":\"Sheet1\",\"selection\":{\"kind\":\"range\",\"ranges\":[\"A1:C10\"]}}'\nasp op verify_workbook --baseline base.xlsx --bind current.xlsx --json '{}'\necho '{\"action\":\"schema\"}' | asp op sheetport_manifest\n```\n\n`--bind` reads the current workbook, while `--baseline` supplies the second workbook only for `verify_workbook`. Canonical mutable CLI calls require exactly one persistence target: `--output <path>` writes a new file or `--in-place` atomically replaces the bound file; pure preview persists nothing and accepts neither. Durable fork, checkpoint, stage, and history operations are intentionally absent from stateless CLI discovery. This is a core design principle: **the surface should explain itself to the agent**.\n\n---\n\n## Command families\n\n## `read` — extraction and inspection\n\n| Command | Purpose |\n| --- | --- |\n| `asp read sheets <file>` | List sheets with summary metadata |\n| `asp read overview <file> <sheet>` | Detect regions, headers, and orientation |\n| `asp read values <file> <sheet> <range> [range...]` | Pull raw values for exact A1 ranges |\n| `asp read export <file> <sheet> <range>` | Export a bounded range to csv or grid json |\n| `asp read cells <file> <sheet> <target> [target...]` | Inspect exact cells/ranges with value/formula/cached/style snapshots |\n| `asp read page <file> <sheet> ...` | Deterministic sheet paging with `next_start_row` |\n| `asp read table <file> ...` | Structured table/region read with deterministic `next_offset` |\n| `asp read names <file>` | Named ranges, named formulas, and table items |\n| `asp read workbook <file>` | Workbook-level metadata |\n| `asp read layout <file> <sheet>` | Layout-aware rendering with widths, merges, borders, and optional ascii output |\n\n### Why these matter for agents\n\nAgents rarely need “the whole spreadsheet.” They need:\n- the right region\n- the right page\n- the right cells\n- just enough layout to understand intent\n\nThat is why the read surface combines **region detection**, **structured reads**, **detail inspection**, and **explicit continuation**.\n\n---\n\n## `analyze` — search, diagnostics, and impact understanding\n\n| Command | Purpose |\n| --- | --- |\n| `asp analyze find-value <file> <query>` | Search by value or by label semantics |\n| `asp analyze find-formula <file> <query>` | Text search within formulas |\n| `asp analyze formula-map <file> <sheet>` | Summarize formulas by complexity/frequency |\n| `asp analyze formula-trace <file> <sheet> <cell> <precedents\\|dependents>` | Dependency tracing with continuation |\n| `asp analyze scan-volatiles <file>` | Find volatile formulas |\n| `asp analyze sheet-statistics <file> <sheet>` | Density and type statistics |\n| `asp analyze table-profile <file>` | Header/type/cardinality profiling |\n| `asp analyze ref-impact <file> --ops @structure_ops.json` | Preflight structural edit impact without mutation |\n\n### Why this matters\n\nHeadless spreadsheet automation wins when it can **explain consequences**, not just execute mutations. `ref-impact`, `formula-trace`, and grouped diagnostics are all part of that story.\n\n---\n\n## `write` — safe mutations and workflow helpers\n\n| Command | Purpose |\n| --- | --- |\n| `asp write cells <file> <sheet> ...` | Direct shorthand cell edits |\n| `asp write import <file> <sheet> ...` | Import grid json or csv into a workbook range |\n| `asp write append ...` | Footer-aware row append into a region or table |\n| `asp write clone-template-row ...` | Clone one template row with preview-first planning |\n| `asp write clone-row-band ...` | Clone a multi-row template band repeatedly |\n| `asp write formulas replace ...` | Formula-only find/replace on a sheet/range |\n| `asp write name define|update|delete ...` | Named range mutation helpers |\n| `asp write batch transform ...` | Stateless transform pipeline |\n| `asp write batch style ...` | Stateless style edits |\n| `asp write batch formula-pattern ...` | Autofill-like formula application |\n| `asp write batch structure ...` | Rows/cols/sheets/copy/move style mutations |\n| `asp write batch column-size ...` | Column width operations |\n| `asp write batch sheet-layout ...` | Freeze panes, zoom, page setup, print area |\n| `asp write batch rules ...` | Data validation + conditional formatting |\n\n### Safety model\n\nMost mutating commands support a strict mode matrix:\n- `--dry-run`\n- `--in-place`\n- `--output <PATH>`\n\nThis matters for agents because it allows:\n- dry-run planning\n- non-destructive execution\n- explicit overwrite control\n\n### Formula maintenance\n\nFormula mutation is now a first-class surface:\n\n```bash\nasp write formulas replace data.xlsx Sheet1 --find '$64' --replace '$65' --dry-run\nasp write formulas replace data.xlsx Sheet1 --find 'Sheet1!' --replace 'Sheet2!' --range A1:Z100 --output fixed.xlsx\n```\n\n### Named range maintenance\n\n```bash\nasp write name define data.xlsx RevenueInput 'Inputs!$B$2'\nasp write name update data.xlsx RevenueInput 'Inputs!$B$2:$B$4' --in-place\nasp write name delete data.xlsx RevenueInput --in-place\n```\n\n---\n\n## `workbook` — file-level flows\n\n| Command | Purpose |\n| --- | --- |\n| `asp workbook create <path>` | Create a new workbook |\n| `asp workbook copy <source> <dest>` | Safe copy for edit workflows |\n| `asp workbook recalculate <file>` | Recalculate formulas via the configured backend |\n\n---\n\n## `verify` — proof, not vibes\n\n| Command | Purpose |\n| --- | --- |\n| `asp verify proof <baseline> <current>` | Prove target deltas and isolate new/resolved/preexisting errors |\n| `asp verify diff <original> <modified>` | Summary-first grouped workbook diff with optional paged details |\n\n### Why verification matters\n\nMost spreadsheet automation tools stop at “the edit applied.”\n\nagent-spreadsheet goes further:\n- did the target cells change the way we expected?\n- did the workbook introduce new errors?\n- which changes were direct edits vs recalculation fallout?\n- what changed overall, grouped in a way an agent can reason about?\n\nThis verification layer is a big part of why this project is a serious agent substrate rather than a utility script.\n\n---\n\n## `session` — event-sourced stateful editing\n\nThe session surface is for workflows that are too complex for a single stateless write.\n\n### What sessions give you\n- persistent editing state\n- staged dry-run operations\n- compare-and-swap apply semantics\n- logs and replayability\n- branch/switch/fork flows\n- undo / redo / checkout\n- explicit materialization back to a workbook file\n\n### Canonical loop\n\n```bash\nasp session start --base model.xlsx --workspace .\nasp session op --session <id> --ops @ops.json --workspace .\nasp session apply --session <id> <staged_id> --workspace .\nasp session materialize --session <id> --output result.xlsx --workspace .\n```\n\n### History and branching\n\n```bash\nasp session log --session <id> --workspace .\nasp session branches --session <id> --workspace .\nasp session fork --session <id> experiment-b --workspace .\nasp session switch --session <id> experiment-b --workspace .\nasp session undo --session <id> --workspace .\nasp session redo --session <id> --workspace .\nasp session checkout --session <id> <op_id> --workspace .\n```\n\nUse sessions when you want **repeatability, auditability, and multi-step safety**.\n\n---\n\n## `sheetport` — spreadsheet interfaces as executable contracts\n\nSheetPort is the workflow surface for turning workbook inputs/outputs into explicit machine contracts.\n\n### Manifest lifecycle\n\n```bash\nasp sheetport manifest candidates model.xlsx\nasp sheetport manifest schema\nasp sheetport manifest validate manifest.yaml\nasp sheetport manifest normalize manifest.yaml\n```\n\n### Bind-check + run\n\n```bash\nasp sheetport bind-check model.xlsx manifest.yaml\nasp sheetport run model.xlsx manifest.yaml --inputs @inputs.json --freeze-volatile\n```\n\nUse this when you want a workbook to behave less like an opaque file and more like a **declared service interface**.\n\n---\n\n## Output contracts for agents\n\n### Canonical vs compact shapes\n\nAll commands default to JSON. Many also support:\n\n```bash\n--shape canonical\n--shape compact\n```\n\nPolicy:\n- **canonical** keeps the full stable schema\n- **compact** removes wrapper noise where the contract allows it while preserving continuation fields and command-specific semantics\n\nShape policy:\n- **Canonical (default):** preserve the full response schema.\n- **range-values:** returns a stable `values: [...]` envelope in both canonical and compact modes.\n- **range-values default encoding:** dense JSON (`dense.encoding = \"dense_v1\"`) with `dictionary` + run-length `row_runs`.\n- **range-values `--include-formulas`:** includes sparse formula coordinates in dense mode (`dense.formulas`), or a matrix in explicit `json` format.\n- **read-table and sheet-page: compact preserves the active branch and continuation fields (`next_offset`, `next_start_row`)**.\n- **formula-trace compact:** omits per-layer `highlights` while preserving `layers` and `next_cursor`.\n\n### Deterministic pagination loops\n\n```bash\n# sheet-page continuation\nasp read page data.xlsx Sheet1 --format compact --page-size 200\nasp read page data.xlsx Sheet1 --format compact --page-size 200 --start-row 201\n\n# read-table continuation\nasp read table data.xlsx --sheet \"Sheet1\" --table-format values --limit 200 --offset 0\nasp read table data.xlsx --sheet \"Sheet1\" --table-format values --limit 200 --offset 200\n```\n\n#### `sheet-page` machine contract\n- Inspect top-level `format` before reading payload fields.\n- `format=full`: read top-level `rows` plus optional `header_row` and `next_start_row`.\n- `format=compact`: read `compact.headers`, `compact.header_row`, `compact.rows` plus optional `next_start_row`.\n- `format=values_only`: read `values_only.rows` plus optional `next_start_row`.\n- Continuation is always driven by top-level `next_start_row` when present.\n- Global `--shape compact` preserves the active `sheet-page` branch; it does not flatten `sheet-page` payloads.\n\nMachine continuation example:\n1. Request page 1 without `--start-row`.\n2. If `next_start_row` is present, call `sheet-page` again with `--start-row <next_start_row>`.\n3. Stop when `next_start_row` is omitted.\n\n### Self-describing payloads\n\nWhen the agent is unsure what to send, ask for a schema or example:\n\n```bash\nasp schema write batch rules\nasp example write batch rules\nasp schema session op structure.insert_rows\nasp example session op structure.insert_rows\n```\n\n### Batch payload examples\n\nAll batch payloads use a top-level envelope object. Most commands require `{\"ops\":[...]}`; `column-size-batch` prefers `{\"sheet_name\":\"...\",\"ops\":[...]}` and also accepts per-op `sheet_name` inside `{\"ops\":[...]}`.\n\n##### transform-batch payloads (`@transform_ops.json`)\n- Minimal: `{\"ops\":[{\"kind\":\"fill_range\",\"sheet_name\":\"Sheet1\",\"target\":{\"kind\":\"range\",\"range\":\"B2:B4\"},\"value\":\"0\"}]}`\n- Advanced: `{\"ops\":[{\"kind\":\"replace_in_range\",\"sheet_name\":\"Sheet1\",\"target\":{\"kind\":\"region\",\"region_id\":1},\"find\":\"N/A\",\"replace\":\"\",\"match_mode\":\"contains\",\"case_sensitive\":false,\"include_formulas\":true}]}`\n\n##### style-batch payloads (`@style_ops.json`)\n- Minimal: `{\"ops\":[{\"sheet_name\":\"Sheet1\",\"target\":{\"kind\":\"range\",\"range\":\"B2:B2\"},\"patch\":{\"font\":{\"bold\":true}}}]}`\n- Advanced: `{\"ops\":[{\"sheet_name\":\"Sheet1\",\"target\":{\"kind\":\"cells\",\"cells\":[\"B2\",\"B3\"]},\"patch\":{\"number_format\":\"$#,##0.00\",\"alignment\":{\"horizontal\":\"right\"}},\"op_mode\":\"merge\"}]}`\n\n##### write batch formula-pattern payloads (`@formula_ops.json`)\n- Minimal: `{\"ops\":[{\"sheet_name\":\"Sheet1\",\"target_range\":\"C2:C4\",\"anchor_cell\":\"C2\",\"base_formula\":\"B2*2\"}]}`\n- Advanced: `{\"ops\":[{\"sheet_name\":\"Sheet1\",\"target_range\":\"C2:E4\",\"anchor_cell\":\"C2\",\"base_formula\":\"B2*2\",\"fill_direction\":\"both\",\"relative_mode\":\"excel\"}]}`\n- `relative_mode` valid values: `excel`, `abs_cols`, `abs_rows`\n\n##### structure-batch payloads (`@structure_ops.json`)\n- Minimal: `{\"ops\":[{\"kind\":\"rename_sheet\",\"old_name\":\"Summary\",\"new_name\":\"Dashboard\"}]}`\n- Advanced: `{\"ops\":[{\"kind\":\"copy_range\",\"sheet_name\":\"Sheet1\",\"dest_sheet_name\":\"Summary\",\"src_range\":\"A1:C4\",\"dest_anchor\":\"A1\",\"include_styles\":true,\"include_formulas\":true}]}`\n\n##### column-size-batch payloads (`@column_size_ops.json`)\n- Minimal (preferred): `{\"sheet_name\":\"Sheet1\",\"ops\":[{\"range\":\"A:A\",\"size\":{\"kind\":\"width\",\"width_chars\":12.0}}]}`\n- Advanced (preferred): `{\"sheet_name\":\"Sheet1\",\"ops\":[{\"target\":{\"kind\":\"columns\",\"range\":\"A:C\"},\"size\":{\"kind\":\"auto\",\"min_width_chars\":8.0,\"max_width_chars\":24.0}}]}`\n- Also accepted (harmonized shape): `{\"ops\":[{\"sheet_name\":\"Sheet1\",\"range\":\"A:A\",\"size\":{\"kind\":\"width\",\"width_chars\":12.0}}]}`\n\n##### sheet-layout-batch payloads (`@layout_ops.json`)\n- Minimal: `{\"ops\":[{\"kind\":\"freeze_panes\",\"sheet_name\":\"Sheet1\",\"freeze_rows\":1,\"freeze_cols\":1}]}`\n- Advanced: `{\"ops\":[{\"kind\":\"set_page_setup\",\"sheet_name\":\"Sheet1\",\"orientation\":\"landscape\",\"fit_to_width\":1,\"fit_to_height\":1}]}`\n\n##### rules-batch payloads (`@rules_ops.json`)\n- Minimal: `{\"ops\":[{\"kind\":\"set_data_validation\",\"sheet_name\":\"Sheet1\",\"target_range\":\"B2:B4\",\"validation\":{\"kind\":\"list\",\"formula1\":\"\\\"A,B,C\\\"\"}}]}`\n- Advanced: `{\"ops\":[{\"kind\":\"set_conditional_format\",\"sheet_name\":\"Sheet1\",\"target_range\":\"C2:C10\",\"rule\":{\"kind\":\"expression\",\"formula\":\"C2>100\"},\"style\":{\"fill_color\":\"#FFF2CC\",\"bold\":true}}]}`\n\n`write batch formula-pattern` clears cached results for touched formula cells; run `workbook recalculate` to refresh computed values.\n\n### Formula parse policy\n\nFormula-aware commands support:\n\n```bash\n--formula-parse-policy fail|warn|off\n```\n\n- `fail` — abort\n- `warn` — continue and attach grouped diagnostics\n- `off` — skip silently\n\nThis lets agents choose between strictness and progress depending on the workflow.\n\n### CLI reference excerpts\n\n- `read values <file> <sheet> <range> [range...] [--format dense\\|json\\|values\\|csv] [--include-formulas]`\n- `read cells <file> <sheet> <target> [target...] [--include-empty]`\n- `read page <file> <sheet> --format <full|compact|values_only> [--start-row ROW] [--page-size N]`\n- `workbook create <path> [--sheets Inputs,Calc,...] [--overwrite]`\n- `analyze find-value <file> <query> [--sheet S] [--mode value\\|label] [--label-direction right\\|below\\|any]`\n- `write batch transform <file> --ops @ops.json (--dry-run\\|--in-place\\|--output PATH)`\n\n#### Formula write-path provenance (`write_path_provenance`)\n\nFormula-writing commands emit optional provenance metadata for troubleshooting:\n- `written_via`: write path (`edit`, `transform_batch`, `apply_formula_pattern`)\n- `formula_targets`: sheet/cell or sheet/range targets touched by formula writes\n\nDebug compare workflow:\n1. Apply the same formula target via two paths.\n2. Compare `write_path_provenance.written_via` and `formula_targets` in responses.\n3. Use `inspect-cells` plus `recalculate` to compare resulting behavior.\n\n#### Financial presentation starter defaults\n- Keep label columns (often column A) explicitly sized (roughly `24–36` chars) to prevent clipping.\n- Apply consistent number formats by semantic type:\n  - Currency: `\"$\"#,##0.00_);[Red](\"$\"#,##0.00)`\n  - Percent: `0.0%`\n  - Integer/count: `#,##0`\n- Apply `sheet-layout-batch` freeze panes after header layout stabilizes.\n\nJSON output is compact by default; use `--quiet` to suppress warnings.\nGlobal `--output-format csv` is currently unsupported; use command-specific CSV options like `read table --table-format csv`.\n\n---\n\n## MCP server quickstart\n\nThe MCP surface is the stateful server version of agent-spreadsheet.\n\nUse it when you want:\n- workbook caching across calls\n- fork lifecycle instead of stateless file replacement\n- multi-turn agent workflows\n- screenshots and richer server-side orchestration\n\n### Claude Code / Claude Desktop\n\nAdd to `~/.claude.json` or project `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"spreadsheet\": {\n      \"command\": \"agent-spreadsheet-mcp\",\n      \"args\": [\"--workspace-root\", \"/path/to/workbooks\", \"--transport\", \"stdio\"]\n    }\n  }\n}\n```\n\n### Docker\n\n```json\n{\n  \"mcpServers\": {\n    \"spreadsheet\": {\n      \"command\": \"docker\",\n      \"args\": [\n        \"run\", \"-i\", \"--rm\",\n        \"-v\", \"/path/to/workbooks:/data\",\n        \"ghcr.io/psu3d0/agent-spreadsheet-mcp:latest-full\",\n        \"--transport\", \"stdio\"\n      ]\n    }\n  }\n}\n```\n\n`:latest` is the read-only slim image (write/fork/recalc tools disabled); `:latest-full` includes the write tools and recalculation (LibreOffice-backed).\n\n### HTTP mode\n\n```bash\nagent-spreadsheet-mcp --workspace-root /path/to/workbooks\n# -> http://127.0.0.1:8079  (POST /mcp, and the canonical route under /v1)\n```\n\nThe same process also serves a plain canonical HTTP route for programmatic clients that do not speak MCP:\n\n| Route | Purpose |\n| --- | --- |\n| `POST /v1/op/{operation}` | Run a canonical operation; the body is the canonical input object, the response is the canonical envelope |\n| `GET /v1/operations` | Runtime-filtered operation discovery for this process |\n| `GET /v1/registry` | Full canonical registry projection plus the error schema |\n| `GET /v1/artifacts/{handle}` | Bytes for an `artifact:sha256:<hex>` handle produced by `screenshot_sheet` |\n\n```bash\ncurl -sS -X POST http://127.0.0.1:8079/v1/op/list_workbooks -d '{}'\n```\n\nCanonical errors return the canonical error envelope with the status mapped from the error code (400 invalid request, 404 unknown operation / resource, 409 revision conflict, 500 operation failed, 501 capability unavailable). Like `/mcp`, `/v1` has **no authentication**; the loopback default bind is the security boundary. See [docs/architecture/canonical-http-route.md](docs/architecture/canonical-http-route.md).\n\n### Configuration\n\nEvery setting is available as a CLI flag (`agent-spreadsheet-mcp --help`), an environment variable, or a config file key (`--config file.yaml`). CLI takes precedence over the config file.\n\n| Variable | Default | Description |\n| --- | --- | --- |\n| `SPREADSHEET_MCP_WORKSPACE` | `.` | Workspace root containing spreadsheet files |\n| `SPREADSHEET_MCP_WORKBOOK` | none | Lock the server to a single workbook path |\n| `SPREADSHEET_MCP_EXTENSIONS` | `xlsx,xlsm,xls,xlsb` | Comma-separated list of allowed workbook extensions |\n| `SPREADSHEET_MCP_ENABLED_TOOLS` | all tools | Restrict execution to the provided tool names (comma-separated) |\n| `SPREADSHEET_MCP_TRANSPORT` | `http` | Transport to expose (`http` or `stdio`) |\n| `SPREADSHEET_MCP_HTTP_BIND` | `127.0.0.1:8079` | HTTP bind address when using http transport |\n| `SPREADSHEET_MCP_RECALC_ENABLED` | `false` | Enable write/recalc tools (uses the native Formualizer backend by default) |\n| `SPREADSHEET_MCP_RECALC_BACKEND` | `auto` | Recalc backend preference: `auto`, `formualizer`, or `libreoffice` |\n| `SPREADSHEET_MCP_MAX_CONCURRENT_RECALCS` | `2` | Max concurrent LibreOffice instances |\n| `SPREADSHEET_MCP_VBA_ENABLED` | `false` | Enable VBA introspection tools (read-only) |\n| `SPREADSHEET_MCP_ALLOW_OVERWRITE` | `false` | Allow `save_fork` to overwrite original workbook files |\n| `SPREADSHEET_MCP_CACHE_CAPACITY` | `5` | Maximum number of workbooks kept in memory |\n| `SPREADSHEET_MCP_TOOL_TIMEOUT_MS` | `30000` | Tool request timeout in milliseconds |\n| `SPREADSHEET_MCP_MAX_RESPONSE_BYTES` | `1000000` | Max response size in bytes |\n| `SPREADSHEET_MCP_MAX_PAYLOAD_BYTES` | `65536` | Max tool payload size in bytes before truncation |\n| `SPREADSHEET_MCP_MAX_CELLS` | `10000` | Max cells per tool payload before truncation |\n| `SPREADSHEET_MCP_MAX_ITEMS` | `500` | Max items per tool payload before truncation |\n| `SPREADSHEET_MCP_OUTPUT_PROFILE` | `token_dense` | Output profile for tool responses (`token_dense` or `verbose`) |\n| `SPREADSHEET_MCP_SLIM_SURFACE` | `true` | Canonical-only router; set `false` to add legacy 0.13 tool names |\n| `SPREADSHEET_MCP_SCREENSHOT_DIR` | `<workspace_root>/screenshots` | Directory to write screenshot PNGs |\n| `SPREADSHEET_MCP_PATH_MAP` | none | Path mapping(s) `INTERNAL=CLIENT` to include client-visible paths in responses (comma-separated; useful for Docker volume mounts) |\n\nSetting any of the timeout/limit variables (`TOOL_TIMEOUT_MS`, `MAX_RESPONSE_BYTES`, `MAX_PAYLOAD_BYTES`, `MAX_CELLS`, `MAX_ITEMS`) to `0` disables that limit.\n\n---\n\n## MCP tool surface\n\nThe default MCP router is generated from the canonical operation registry. A write-capable baseline exposes 27 operations: 17 discovery/read/analysis operations and 10 write/lifecycle operations. Capability-backed deployments can add `screenshot_sheet`, `sheetport_manifest`, `execute_sheetport`, and `inspect_vba`, for up to 31. Nineteen canonical operations are read-only.\n\nEach tool uses the registry descriptor's closed input schema and returns the canonical `schema_version` / `operation` / `resource_id` / `revision_id` / `data` envelope. A `revision_id` identifies the complete observable resource state, not only workbook cell-content bytes: recalculation, evaluation/provenance state, or lifecycle metadata can advance it without a content edit. Clients must use the revision from the latest response envelope for compare-and-swap, cursor, and freshness decisions rather than computing or retaining a content hash. Static MCP annotations report the descriptor's worst-case risk; descriptions identify action-specific risk. `close_workbook` is excluded because cache eviction is runtime administration.\n\nFor the complete operation list and contracts, see [Canonical Operation Surface](docs/architecture/canonical-operation-surface.md). To add the legacy 0.13 names for one compatibility window, set `SPREADSHEET_MCP_SLIM_SURFACE=false`; shared names use their legacy schema and envelope in compatibility mode and are registered only once.\n\n## JS SDK\n\n`agent-spreadsheet-sdk` is the app-facing integration layer — the one surface JS/TS code should target.\n\nIt provides generated canonical convenience methods, legacy input aliases, unchanged canonical envelopes, and typed capability errors. The complete 31-operation manifest supplies schemas and methods, while availability always comes from the selected live backend.\n\n**Backends** are a configuration choice, not separate APIs:\n- **MCP backend** — connect to a running `agent-spreadsheet-mcp` server (shared state, forks, multi-client)\n- **Embedded WASM backend** — the engine runs in-process on workbook bytes, no server or filesystem required (browser, Node, serverless). The `agent-spreadsheet-wasm` crate in this repo is that backend's build artifact; it is an internal dependency of the SDK, not a package you consume directly.\n\nInstall:\n\n```bash\nnpm i agent-spreadsheet-sdk\n```\n\nBackend status: MCP backend is stable and negotiates operations through live tool discovery (or an explicit `supportedOperations` list); the embedded WASM backend derives support from its generated binding's `operations()` descriptors and is tested against the real wasm-bindgen Node package in CI.\n\n---\n\n## Recalc backends\n\nFormula recalculation is pluggable.\n\n| Backend | How | Default | Best for |\n| --- | --- | --- | --- |\n| **Formualizer** | Native Rust engine | **Yes** | Fast default recalc with no external dependency |\n| **LibreOffice** | Headless `soffice` | Docker `:latest-full` / explicit builds | Maximum compatibility and screenshot flows |\n\nFeature notes:\n- `recalc-formualizer` is enabled by default\n- `recalc-libreoffice` is available for LibreOffice-backed builds\n- read and many write flows still work without recalc; only recalculate itself requires a backend\n\n---\n\n## Docker images\n\nPublished at `ghcr.io/psu3d0/agent-spreadsheet-mcp`:\n\n| Image | Size | Recalc | Best for |\n| --- | --- | --- | --- |\n| `latest` | ~15 MB | No | Read-only analysis and lightweight agent deployments |\n| `latest-full` | ~800 MB | Yes | Write + recalc + screenshots |\n\nExamples:\n\n```bash\n# Read-only\ndocker run -v /path/to/workbooks:/data -p 8079:8079 ghcr.io/psu3d0/agent-spreadsheet-mcp:latest\n\n# Write + recalc\ndocker run -v /path/to/workbooks:/data -p 8079:8079 ghcr.io/psu3d0/agent-spreadsheet-mcp:latest-full\n```\n\n---\n\n## Workspace layout\n\n```text\nagent-spreadsheet/\n├── crates/\n│   ├── agent-spreadsheet/        # shared engine + asp / agent-spreadsheet CLI\n│   ├── agent-spreadsheet-mcp/        # MCP server adapter\n│   └── agent-spreadsheet-wasm/   # experimental WASM-facing wrapper\n├── npm/\n│   ├── agent-spreadsheet/      # npm CLI wrapper\n│   └── agent-spreadsheet-sdk/    # JS SDK\n├── docs/                       # architecture and design docs\n├── benchmarks/                 # scenario budget regression harnesses\n└── .github/workflows/          # CI, release, docker builds\n```\n\n### Package roles\n\n| Package | Role |\n| --- | --- |\n| `agent-spreadsheet` | shared engine and CLI binaries |\n| `agent-spreadsheet-mcp` | stateful MCP transport + server surface |\n| `agent-spreadsheet-wasm` | WASM-facing byte/session wrapper |\n| `agent-spreadsheet` | npm wrapper for the CLI binary |\n| `agent-spreadsheet-sdk` | JS SDK for MCP/WASM-style integrations |\n\n---\n\n## Architecture notes\n\n![Architecture Overview](https://raw.githubusercontent.com/PSU3D0/agent-spreadsheet-mcp/main/assets/architecture_overview.jpeg)\n\nCore ideas:\n- **one semantic core** shared across CLI, MCP, session, and WASM-facing work\n- **region detection** for structural awareness\n- **token-efficient defaults** so agents do not over-read spreadsheets\n- **verification as a first-class feature** rather than an afterthought\n- **workflow helpers** for the common mutations that spreadsheet agents repeatedly struggle with\n\nToken-efficient workflow reference:\n\n![Token Efficiency Workflow](https://raw.githubusercontent.com/PSU3D0/agent-spreadsheet-mcp/main/assets/token_efficiency.jpeg)\n\nRecommended progression:\n1. discover workbook + sheets\n2. detect regions / table-like structures\n3. inspect only the exact region or cells needed\n4. mutate with dry-run or session staging\n5. recalculate if needed\n6. verify proof and review grouped diffs\n\n---\n\n## Development\n\n```bash\n# Build everything\ncargo build --release\n\n# Run formatting, lint, and tests\ncargo fmt --all -- --check\ncargo clippy --workspace --all-targets -- -D warnings\ncargo test --workspace\n```\n\nLocal MCP iteration:\n\n```bash\nWORKSPACE_ROOT=/path/to/workbooks ./scripts/local-docker-mcp.sh\n```\n\nOr point your MCP client directly at the local binary:\n\n```json\n{\n  \"mcpServers\": {\n    \"spreadsheet\": {\n      \"command\": \"./target/release/agent-spreadsheet-mcp\",\n      \"args\": [\"--workspace-root\", \"/path/to/workbooks\", \"--transport\", \"stdio\"]\n    }\n  }\n}\n```\n\n---\n\n## Read more\n\n- CLI package README: [`npm/agent-spreadsheet`](./npm/agent-spreadsheet/)\n- Core crate README: [`crates/agent-spreadsheet`](./crates/agent-spreadsheet/)\n- MCP crate README: [`crates/agent-spreadsheet-mcp`](./crates/agent-spreadsheet-mcp/)\n- JS SDK README: [`npm/agent-spreadsheet-sdk`](./npm/agent-spreadsheet-sdk/)\n- WASM wrapper README: [`crates/agent-spreadsheet-wasm`](./crates/agent-spreadsheet-wasm/README.md)\n- Packaging/versioning notes: [`docs/PACKAGING.md`](./docs/PACKAGING.md)\n- Heuristics and region detection: [`docs/HEURISTICS.md`](./docs/HEURISTICS.md)\n- Recalc architecture: [`docs/RECALC.md`](./docs/RECALC.md)\n\n---\n\n## License\n\nApache-2.0\n"}