agentleFS
midasmatterhornmidasmatterhorn/artcraft-skills/gridcraft/SKILL.md

gridcraft

Skill66 starsChanged 6 days agoMITView on GitHub

GridCraft is an open-source, clean-room Rust reimplementation of Microsoft Excel: a spreadsheet app for macOS (also Windows, Linux, BSD and the web) that reads and writes real .xlsx files and can be driven headlessly through a CLI, an MCP server and a live JSON control channel. Use this skill whenever the user mentions GridCraft by name; asks what it can do or which formats, keyboard shortcuts, commands or worksheet functions it has; wants to create, edit, convert, calculate, print or export spreadsheets with it; wants to automate or script it (MCP, CLI, control channel, recorded scripts); needs inputs prepared for it (build or convert .xlsx, CSV, TSV, JSON, or convert .xls/.xlsb/.ods/.slk into .xlsx); wants its output verified, repaired or round-tripped (gridcraft-cli check); or reports a symptom (crash, wrong formula result, formatting lost on save, Excel saying "we found a problem with some content"). Trigger it even when the app is not named but the job is Excel-style spreadsheet work — "make me an Excel file", "add a formula column", "sort and filter this sheet", "pivot this data", "export this workbook to PDF", "read the values out of this spreadsheet". Do not assume Excel parity from Excel knowledge; check this skill first.

  • Installs packages

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    PivotTables: no calculated items, GETPIVOTDATA, timelines, PivotCharts command, number grouping or data-model pivots.

    line 107
  2. Very specific:

    Save semantics: only .xlsx and .json saves clear the dirty flag and become the document's file.

    line 117
  3. Very specific:

    Run ui.inspect first (ribbon tab, editor, open dialog, Backstage page, message, grid rect, scroll, perf, windows) and act on what it shows.

    line 167
  4. Very specific:

    Version and back up: Keep the previous copy of any workbook you edit.

    line 208
  5. Very specific:

    Trust deliberately: Do not call automate.trustScripts on a workbook you did not create unless the user asked you to run its scripts.

    line 211

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

GridCraft

Audit basis. Refreshed 2026-11-07 against tag v0.17.0, commit a6a6a49a0415087474251b08e887a3581fab9e14 — git rev-parse HEAD in the pinned checkout confirms, and the installed GridCraft.app bundle matches it: its binary prints GridCraft 0.17.0, and its Info.plist carries CFBundleShortVersionString 0.17.0 with bundle id ai.storyteller.gridcraft. The previous release this skill described was v0.16.0 (85e51e009c24fad47575f04d3c08f12342615d82).

v0.16.0 → v0.17.0 delta. The release diff touches 237 files (+15,905 / −1,370 lines). The registry gains 13 command ids and loses none (control.assign, control.format, control.list, control.press, control.setValue, insert.button, insert.slider, insert.spinButton, range.move, selection.nextCorner, view.showSheetTabs, view.showHorizontalScrollBar, view.showVerticalScrollBar) — 385 commands now, catalog 281/296. Form controls are new: buttons, sliders and spin buttons with Assign Action and Format Control, modelled in crates/model/src/features.rs, commanded in crates/engine/src/cmd/controls.rs, round-tripped through <controls>/ctrlProp/VML in crates/xlsx/src/controls.rs. Floating objects share one selection model — charts, pictures, shapes, equations and slicers, eight resize handles, one undo step per drag (crates/ui-egui/src/objects.rs), exposed as the ui.object.select control method. Two new input formats: SYLK .slk opens (import only, crates/engine/src/io/sylk.rs) and a web page's table opens as a sheet (read_html_table in crates/engine/src/io.rs), so HTML is no longer export-only. Also new: paste a picture from the clipboard at the active cell (crates/ui-egui/src/app/clipboard.rs), highlight the active cell's row (options.highlightActiveRow, crates/ui-egui/src/grid/active_row.rs), per-workbook show/hide of sheet tabs and scroll bars, Ctrl+. cycles the selection's corners, key tips grew by 46 sequences to 413 with the Excel 2003 menu paths (xtask/src/keytips.rs, crates/ui-egui/src/keytips/keytips.json), and the web build can host GridCraft in a page's own document (data-host="page", apps/gridcraft-web/src/host.rs). File fidelity: R1C1 reference style, page margins written as decimals and "remove personal information on save" all survive a round trip (crates/xlsx/src/{read,write,sheet_write}.rs), precision-as-displayed rounds calculation results (crates/engine/src/cmd.rs), and xlsx checkboxes no longer make Excel repair the file. Corrections to the previous text: Python cells and equations exist (python.set/python.output, insert.equation/equation.edit; Python code is stored and a file's cached result shown, never executed), the Analysis ToolPak has all 19 tools (crates/engine/src/cmd/analysis.rs), and HTML imports tables (above).

v0.15.0 → v0.16.0. +7 command ids, none removed (data.solverLoadModel, data.solverReset, data.solverSaveModel, equation.edit, insert.equation, python.output, python.set). The Solver surface landed (its data.solver* family, with Answer, Sensitivity and Limits reports), data tables can sit beneath charts, Page Setup gained a page order, and one OS window per workbook window arrived (view.newWindow shares the workbook; view.arrangeAll tiles the windows).

v0.14.2 → v0.15.0 (history). Recorded by the previous audit as a compatibility wave with no command-registry change: .xls files give up cell formatting but keep font family and charset; xlsx writes _xlfn. prefixes for STOCKHISTORY/TRANSLATE/DETECTLANGUAGE; workbook view settings survive an open + save; a Google Sheets _xlfn._xlws.DUMMYFUNCTION wrapper opens as the original formula; CSV/text detect each column's date order; formula edges match Excel (YEARFRAC basis 0, MOD, NUMBERVALUE, PERCENTRANK); range.setValues takes parse: false with a converted report; a locked cell's edit is refused before a draft can block Save. The older v0.14.0–0.14.2 macro-system history is folded into CHANGES.md.

Verify against your installed version — the ArtCraft Launcher auto-updates, so a newer build may differ; every count quoted here was re-measured at this tag, and code paths that moved were re-cited. The measurement method for each count is in evidence.md.

Overview

GridCraft is an open-source, clean-room reimplementation of Microsoft Excel's workflow in pure Rust (README.md), by the ArtCraft team; source: github.com/storytold/gridcraft. XLSX is the native document format, and the architecture is engine-first: every ribbon button, menu item, dialog OK, keystroke and mouse gesture is a command (crates/engine/src/cmd/), reachable over a JSON control channel, an MCP server and a headless CLI. Maturity is alpha: the core workflow (open XLSX → edit/format → sort/filter → chart/pivot → print to PDF → save XLSX) works end to end, but the project's own estimate is ~75% feature breadth and ~50% "ready for real work" (docs/target-app-parity.md summary; ROADMAP.md). It runs natively on macOS 11+, Windows, Linux and BSD, and in the browser via WebAssembly (apps/gridcraft-web). The UI runs on egui 0.37, patched to the storytold fork (Cargo.toml [patch.crates-io]).

Capabilities (verified)

Core workbook and editing

  • One native window per workbook window: view.newWindow opens another window on the same workbook (no clone; saving from either window saves it), view.arrangeAll tiles the windows, window.list/window.close manage them, and view.switchWindows/window.activate {index} switch workbooks (crates/engine/src/cmd/extra.rs:167).
  • Three built-in samples budget, sales, grades: file.new {sample}, CLI --sample, URL ?sample= (crates/engine/src/sample.rs).
  • 385 engine commands (372 at v0.16.0 — the previous text's 363 equals the full 372 minus the nine macro.* ids it documented separately; +13 this release, none removed); 281 of the 296 Excel catalog ids implemented, 94.9% (277/292 at v0.16.0) — crates/engine/src/cmd/*.rs, crates/engine/src/catalog.rs, generated docs/parity-checklist.md (the 15 unimplemented ids are listed there).
  • Formatting: fonts, fills, borders, alignment, merges, Excel's number-format language (crates/numfmt), cell styles and themes, conditional formatting (CellIs, expression, text, top-10, above-average, time period, duplicate/unique, colour scale, data bar, icon set) and data validation (whole, decimal, list, date, time, text length, custom).
  • Tables (structured references, header/total rows, banded rows, style gallery, Resize Table, remove duplicates), notes and threaded comments with replies/resolution/timestamps, hyperlinks, pictures floating or inside a cell (PNG/JPEG only), shapes and text boxes (10 ShapeKinds: rectangle, rounded rectangle, ellipse, triangle, line, arrow, text box, icon, ink, equation), checkboxes, freehand ink with Ink to Shape, sparklines (line/column/win-loss).
  • Form controls (new at v0.17.0): buttons, sliders and spin buttons placed on the sheet, with control.list, control.format (name, text, linked cell, min/max/step/page/value, horizontal, print, locked), control.assign (a macro or a command with params), control.setValue and control.press. A button never opens a web page or a dialog, and control.press on a workbook that came from a file asks first (crates/engine/src/cmd/controls.rs; UI crates/ui-egui/src/form_controls.rs; XLSX crates/xlsx/src/controls.rs).
  • One object selection across charts, pictures, shapes, equations and slicers, with eight resize handles; only the selected object's handles resize, a press elsewhere on it moves it, and each drag is its own undo step (crates/ui-egui/src/objects.rs). ui.object.select {id?, kind?} selects one and replies {selected, rect} in window points.
  • Editing: fill handle (drag; right-drag for Copy Cells / Fill Series / Fill Formatting Only / Fill Without Formatting / Series…), AutoFill with the Auto Fill Options button, Flash Fill, Paste Special, Format Painter, Find/Replace (now with within: "selection"), Go To, Watch Window, undo/redo with bounded history.
  • Paste a picture from the system clipboard at the active cell (new; crates/ui-egui/src/app/clipboard.rs runs insert.picture).
  • AutoSum (formulas.autoSum, ⌘⇧T): a single cell guesses the numbers above it, else the numbers to its left; a multi-cell selection gets column totals below and row totals in the empty last column (one undo step). Options ▸ Formulas Maximum Iterations / Maximum Change; Options ▸ General "Highlight the active cell's row" (new global preference); show/hide sheet tabs and scroll bars per workbook (new: view.showSheetTabs, view.showHorizontalScrollBar, view.showVerticalScrollBar).
  • Background error checking (green corner, warning button, Convert to Number, Circular References); AutoSave switch that saves only workbooks that already have a file; "Remove personal information on save" kept and honoured; R1C1 reference style kept; page margins written as their decimals.
  • Opening recalculates every formula (DocState::new → Calc::recalc_all, crates/engine/src/lib.rs), so a workbook with volatile formulas runs them on open; there is no recalc-on-open switch (from_saved, the constructor that keeps a file's values unevaluated, is used only by a test). To read what a file stores, bypass the session and inspect the package (gridcraft-cli check does exactly that).
  • Slicers exist as in-sheet filter widgets over one table column, but are not written to XLSX.

Formulas and calculation

  • 513 of Excel's 523 worksheet functions by name, 504 working (96.4%) — unchanged at v0.17.0 — including dynamic arrays and spilling, LET/LAMBDA (a self-calling LAMBDA stops at 140 calls with #NUM!), MAP/REDUCE/SCAN/BYROW/BYCOL/MAKEARRAY, GROUPBY/PIVOTBY (a GROUPBY total depth of 2 or more adds subtotals), structured table references and iterative calculation for circular references — docs/function-parity.md, crates/functions/src/, crates/calc/src/eval.rs.
  • Evaluate without editing: gridcraft-cli eval '=SUM(A1:A9)' --in book.xlsx or formulas.evaluate. A formula that could not be typed into a cell is an error that says why, not a silent #VALUE!.
  • Calculation settings travel with the workbook: automatic / automaticExceptTables / manual, iterative on/off, max iterations and max change (formulas.calculationOptions). Set precision as displayed now rounds calculation results (new at v0.17.0).
  • Python cells (a cell type, not an Excel function): python.set {cell, code, output?} and python.output set the code and its return type (value/object); Python mode edits the code in the formula bar (ui.pythonMode, Ctrl+Alt+Shift+M toggles the return type). Code and a file's cached result are stored; GridCraft never runs Python, so new or changed code shows #BLOCKED! (crates/engine/src/cmd/python.rs, crates/xlsx/src/python_part.rs).
  • Equations: Insert ▸ Symbols ▸ Equation (insert.equation {latex}, equation.edit), LaTeX source laid out by gridcraft-math and drawn from the cached layout, written as OMML and read back from OMML for a common subset (crates/xlsx/src/omml.rs).
  • Carried hardening: accounting negatives read as negative numbers; INDEX(A1:C3,2) on a 2-D reference is #REF!; REGEXREPLACE bounds each replacement; a 16-million-cell budget is charged before scanning; arrays the text functions build are capped.

Files it reads and writes

  • .xlsx is native read/write: cells, shared/array/dynamic formulas, styles, themes (per-script typefaces; <scheme val="minor"/> kept), merges, conditional formats, validation, tables, notes and threaded comments, hyperlinks, names, freeze panes, outlines, print settings, pictures (shared media written once), shapes incl. ink, sparklines, form controls, PivotTables, sheet/workbook protection and Allow Edit Ranges, calc settings — each sheet keeps its sheetId across a rewrite.
  • Pass-through on save (kept when their owner survives): custom document properties, ribbon customisation, custom XML, external workbook links (never followed or refreshed), data connections, sheet query tables, printer settings, ActiveX and unmodelled form controls (the three modelled kinds are rebuilt; unknown controls pass through), OLE objects, sheet backgrounds with their VML, header/footer pictures, chart sheets.
  • .xlsm / .xltm keep their VBA project byte-for-byte; macros are never executed. .xltx/.xltm save with the template content type.
  • Import-only: .xls/.xlt (BIFF8: values, formulas, number formats, merges, sizes, names, calc and sheet-display settings; chart/macro/dialog sheets skipped), .xlsb and .ods (worksheet values and cached formula results only), and .slk SYLK (new: values, R1C1 formulas converted to A1, number formats, column widths; save refused).
  • Text/data: CSV and TSV/TXT/TAB with delimiter/encoding detection; writes the displayed text, keeps the separator a file was opened with, refuses output over 512 MiB; file.open {csvAsText:true} keeps every field as text. .json/.scjson is a debug serde dump. HTML: file.exportHtml writes one sheet as a table (pictures as data-URI images, charts as inline SVG, at most 100,001 rows), and opening a page now imports its table as a sheet (header cells bold; x:num values only when values are read; no full HTML document model).
  • .pdf export: own PDF 1.7 writer; file.exportPdf {path?, sheets?: active|all, range?, fitToPage?} returns {pages, bytes, path} or base64; file.print returns the same PDF. http(s) hyperlinks and internal cell destinations become real PDF link annotations; file: links are omitted.
  • Password-encrypted .xlsx open (Agile AES and Standard encryption, [MS-OFFCRYPTO]) via a password param; the Agile dataIntegrity HMAC is verified. RC4/Extensible and encrypted .xls are refused.
  • Save is refused for .xls, .xlsb, .ods and .slk with an explanatory message. Content wins over the extension.
  • Hard caps: 512 MB per decompressed XLSX part and 1 GB per package, 2 GB per file read, 100,001 HTML rows, 512 MiB CSV/TSV output, 16,000,000 cells per array result. Opening an XLSX warns for each skipped drawing object and chart.

Charts, PivotTables and analysis

  • 26 ChartKinds (unchanged at v0.17.0): column/bar/line/pie/doughnut/area/scatter/bubble/radar/histogram/waterfall/funnel/treemap/sunburst/box-whisker/stock/combo and subtypes; chartex parts for histogram/box-whisker/waterfall/funnel/treemap/sunburst, six trendline types, Recommended Charts, Select Data, Switch Row/Column, Change Type/Colours/Layout. A doughnut draws every series as its own concentric ring (new).
  • Chart objects move and resize, use the shared object selection, and all 2-D kinds survive the XLSX round trip. PivotCharts that arrive in a file are read and kept, their series rebuilt from the report when it refreshes; there is no Insert ▸ PivotChart command.
  • PivotTables: field list, Filters/Rows/Columns/Values areas, report filters, filter items by picking labels, layouts, date grouping, show-values-as, calculated fields, values on rows, grand totals, styles, refresh, change source; round-trip to/from XLSX. Show Details and Enable show details exist (command only).
  • Data tools: sort (multi-key), AutoFilter, Advanced Filter, remove duplicates, text-to-columns, Flash Fill, group/ungroup/subtotals, consolidate, scenario manager, Goal Seek, data table; Outline Settings and Show Outline Symbols.
  • Solver (Simplex LP with integer/binary branch-and-bound, GRG Nonlinear, Evolutionary; Answer, Sensitivity and Limits reports; save/load model), Forecast Sheet with hindcast, Analysis ToolPak with all 19 tools (crates/engine/src/cmd/analysis.rs).
  • Printing: native macOS/Windows/Linux printing through the pinned shared craft-print library, Page Setup, Page Break Preview, Page Layout view with rulers, draggable margins and in-place header/footer editing.
  • Conditional formatting's New Formatting Rule formula box takes references clicked or dragged on the grid.

Automation surface (the reason to read this skill)

Counts at v0.17.0, with v0.16.0 in brackets where it differs: 385 engine commands (372); 281/296 catalog ids (277/292); 22 MCP tools (unchanged); 11 CLI subcommands (unchanged); 35 control method names in 30 dispatch arms (unchanged) plus command-id passthrough; 18 UI-only command ids (17); 72 shortcut bindings on command specs (71) plus 5 macOS-only overrides; 413 key-tip sequences (367); 19 interface languages (unchanged); 26 chart kinds (unchanged); 513/523 worksheet functions (unchanged); 3 MCP resources (unchanged); 14 check round-trip categories (unchanged).

  • The control channel requires a token: the first line of a connection must authenticate with the app's token, and a connection that does not — or later sends a malformed line — is answered once and closed (apps/gridcraft/src/control_server.rs:4-5,23-29,59-73; gridcraft_mcp::control_auth). The token is --control-token <token> or GRIDCRAFT_CONTROL_TOKEN (at least 16 characters), else 256 random bits written to a file only the user can read whose path is printed to stderr ($XDG_RUNTIME_DIR/gridcraft/control-<port>.token, else ~/.cache/gridcraft/…; Windows %USERPROFILE%\.gridcraft\…). gridcraft-cli send and mcp --connect read it automatically.
  • CLI gridcraft-cli (headless; the app bundle ships no CLI): info, convert, eval, cat, run, check, commands, functions, mcp, send, version (apps/gridcraft-cli/src/main.rs). Version 0.17.0.
  • check is the one to remember: it recalculates every formula against the file's Excel-cached values (skipping volatile formulas and files flagged fullCalcOnLoad), then writes and re-reads the workbook through GridCraft's own XLSX writer and compares 14 categories — package, sheets, values, formulas, numFmts, merges, names, tables, condFormats, validations, charts, comments, hyperlinks, pivots — and validates the package. Flags --tolerance 1e-9 and --max-report N; exit 1 on any difference; --json emits schema gridcraft-check/1.
  • MCP server over stdio, protocol 2025-06-18 (older clients are answered in their own version); headless (--in FILE | --sample NAME) or remote (--connect PORT). 22 tools: execute_command, list_commands, inspect_workbook, read_range, write_range, set_cell, get_cell, evaluate_formula, select, format_range, insert_chart, create_table, sort_range, filter, open_workbook, save_workbook, new_workbook, undo, redo, screenshot, list_functions, list_windows. Resources: gridcraft://workbook, gridcraft://commands, gridcraft://functions; prompts/list is empty.
  • Control-channel methods (35 names in 30 match arms; aliases share an arm): read state — engine.execute (aliases command, ui.menu.invoke), engine.commands, engine.journal (10,000 entries / 64 MB, passwords stripped), document.inspect, sheet.read, cell.get, selection.stats, ui.inspect; objects and UI — ui.object.select, ui.ribbon, ui.set, ui.dialog, ui.dialog.set|confirm|cancel, ui.message.dismiss, ui.edit.begin|text|commit|cancel, ui.key, ui.text, ui.move, ui.click, ui.drag, ui.cell.click, ui.cell.drag, ui.resize, ui.focus, ui.screenshot; files and lifetime — app.open, app.save, app.quit. Any other method that names an engine command id runs that command (crates/ui-egui/src/control.rs).
  • UI-only commands reachable through engine.execute in the running app (so also over mcp --connect, not in a headless gridcraft-cli mcp session); engine.commands marks them "ui": true and serves 18: ui.ribbonTab, app.checkForUpdates, view.collapseRibbon, view.expandFormulaBar, ui.pythonMode, view.darkMode, view.theme, view.animations, options.autoComplete, options.highlightActiveRow, view.interfaceScale, ui.dialog, ui.backstage, ui.printSettings, ui.printSubmit, app.language.set, app.language.english, app.language.japanese (crates/ui-egui/src/control.rs serves the list; crates/ui-egui/src/app/commands.rs runs them).
  • Recorded scripts (Automate tab): automate.recordActions, automate.newScript, automate.allScripts, automate.runScript, automate.trustScripts, automate.deleteScript, automate.stopAction. A workbook opened from a file that carries scripts starts untrusted; steps may not call file.*, link.* or window.* or pass a path. Scripts are stored in the workbook as the hidden defined name _sc_scripts, so they round-trip XLSX.
  • Engine building blocks: undo groups, the recording buffer, document Trust, and the chunked hidden-name stash _gc_<key>_<n>.
  • Web build: same UI crate via the eframe web runner; URL flags ?sample=, ?webgl, ?chrome=none|notitlebar|nofiletab, ?host=parent&author=; data-host="page" on the canvas lets a page host GridCraft in its own document (new, apps/gridcraft-web/src/host.rs, shared crate craft-web-host); preferences in localStorage; no TCP control channel.
  • Programmatic calls never open dialogs: file.open/file.save/data.getData/data.fromTextCsv without a file path return "missing path…: programmatic calls never open dialogs".
  • Interface languages: 19 (Language::ALL): en, es, el, zh, ja, ko, ru, pt-BR, de, cs, fr, sr, pl, it, uk, vi, nl, ro, tr. Untranslated strings fall back to English; command ids, document text, formulas and number formats stay English/en-US. app.language.set {language|code} switches at runtime.

Known limitations and not-implemented

  • Partial: .xls import covers values, formulas, number formats, merges, sizes, names, print area/titles, calc settings and WINDOW2 sheet-display options; no fonts, fills, borders, charts, pictures, comments, conditional formats, validation, hyperlinks or freeze panes; chart/macro/dialog sheets are skipped, BIFF5 and FILEPASS files refused. .xlsb/.ods import values and cached formula results only. .slk import is values, R1C1 formulas, formats and widths only. None of the four is ever written.
  • Encryption is read-only: Agile and Standard .xlsx open with a password; saves are always unencrypted and have no save path, so Save asks where to go. RC4/Extensible and encrypted .xls are refused.
  • Macros never run. VBA is carried byte-for-byte only into .xlsm/.xltm; any other save drops it. GridCraft's recorded scripts are not VBA.
  • Python cells are storage, not execution. Code and a file's cached result round-trip; GridCraft does not run Python, so new or changed code shows #BLOCKED!, and there is no PY worksheet function.
  • Equations are LaTeX-source shapes. OMML outside the supported subset comes back as a plain text box, and an equation is only as good as gridcraft-math's layout, not a full Office equation editor.
  • Excel-repair-free output is unproven: no real corpus and no Excel verification. Unmodelled content is dropped when its owner is rewritten — slicers and slicer caches, timelines, the data model, query tables attached to tables, unmodelled extLst; chart sheets are passed through unchanged but cannot be viewed, edited or created (open now warns for each skipped drawing/chart).
  • Slicers/timelines: slicers can be created and clicked in-sheet but are not saved to XLSX; timelines are catalogued but not implemented.
  • Charts are shallow: no 3-D types, no axis options (min/max/log/units), no error bars, no per-point formatting; data labels and gridlines are just booleans; ~26 of Excel's ~60 subtypes (~43%); chart sheets are not editable. Move, resize (eight handles) and the Format Chart Area dialog (stacked/100% stacked types) do work. PivotCharts open and keep their link to the PivotTable, but there is no command to insert one.
  • PivotTables: no calculated items, GETPIVOTDATA, timelines, PivotCharts command, number grouping or data-model pivots; filter items select labels only (no Top-10, condition or value filters); Show Details and Enable show details exist but have no Options dialog; XLSX round-trip has not been checked in Excel.
  • No Power Query or data model: Get & Transform is only From Text/CSV, Get Data and From Table/Range; Refresh All refreshes PivotTables only. No From Web (data.fromWeb is absent), Stocks, Geography, Relationships or Analyze Data.
  • Scale: recalculation is single-threaded; the project reports ~100 MB workbooks failing to open (#175). Whole-range work is capped and refuses with an error instead of hanging.
  • Text: no complex shaping (Arabic, Devanagari, Thai) and no bidi; a right-to-left sheet mirrors the grid and HTML export, but text stays LTR inside its box and printing/PDF are not mirrored. PDF export sets characters outside WinAnsi in a predefined, non-embedded Adobe-GB1 CID font (STSong-Light / UniGB-UTF16-H): Chinese is tested; Japanese/Korean coverage depends on that font; Arabic/Devanagari/Thai have no glyphs there.
  • Accessibility: AccessKit is enabled and some widgets set node labels, but grid cells and the ribbon are not exposed as an accessible tree; Check Accessibility is a basic scan; no high-contrast mode.
  • No VBA/Office Scripts/add-in or custom-function API, no collaboration/co-authoring, no mobile build, no in-app AI.
  • Functions: 10 of Excel's 523 names are absent (GETPIVOTDATA, IMAGE, STOCKHISTORY, TRANSLATE, DETECTLANGUAGE, CALL, REGISTER.ID, RTD, COPILOT, PY) and 9 are error stubs (7 CUBE functions, WEBSERVICE, FILTERXML). docs/function-parity.md's headline agrees with the code; its totals row (505/496, "18 missing") is stale — the honest split is 513 present, 10 absent, 9 stubs.
  • HTML is a table extractor, not a document model: opening a saved page imports a table as a sheet (first/only table, header cells bold), and file.exportHtml writes one sheet; there is no HTML editing.
  • Objects: inserted icons lose their artwork on XLSX save (#551); Office InkML is not imported; pictures must be PNG/JPEG.
  • Form controls are three kinds only: buttons, sliders and spin buttons. A button's action is a macro or a command, never a web page or a dialog; control.press on a workbook that came from a file asks for approval.
  • Save semantics: only .xlsx and .json saves clear the dirty flag and become the document's file; .csv/.tsv/.html/.pdf are exports that leave the workbook dirty; .xls/.xlsb/.ods/.slk saves are refused. file.close {force:true} and the control-channel app.quit discard unsaved changes without asking.
  • Stale repo prose (verify against code, not docs): README says "89% of standard ribbon commands" while the generated checklist says 281/296 = 94.9%; docs/target-app-parity.md still reports "321 command ids" (the registry has 385); docs/gaps.md says "59 command shortcuts" (command specs carry 72); docs/function-parity.md's totals row disagrees with its own headline. docs/control-protocol.md now documents the token authentication correctly. Prefer code and the generated docs/parity-checklist.md.

How to operate

macOS launch, flags, environment

  • open -a GridCraft; open -a GridCraft book.xlsx — Finder double-clicks and open arrive as Apple events, and files dropped on the window open too.
  • The bundle's binary is Contents/MacOS/GridCraft. It takes only these flags: [--control PORT [--control-token TOKEN]] [--sample budget|sales|grades] [files…], plus --version/-V, which prints GridCraft 0.17.0 and exits. There is no --help: any unrecognised flag is treated as a file path and starts the GUI, so do not pass one.
  • Environment: GRIDCRAFT_CONTROL_PORT=<port>, GRIDCRAFT_CONTROL_TOKEN=<token> (the control channel requires it), GRIDCRAFT_NO_PREFS=1 (the mode for agent test runs: no preferences read or written, no log file), GRIDCRAFT_NO_NATIVE_MENU, RUST_LOG (env_logger-style directives; default warn,gridcraft*=info).
  • Settings and logs live under Library/Application Support/GridCraft/ in the user's home: ui.json, prefs.json, and logs/gridcraft.log, rotated to .1/.2 at each start, 16 MiB cap.

The CLI (installed separately)

The bundle ships no CLI. Install with cargo install --path apps/gridcraft-cli from a source checkout, or the release zip gridcraft-cli-<ver>-macos-universal.zip.

gridcraft-cli info book.xlsx [--json]
gridcraft-cli convert in.xls out.xlsx [--sheet Sales]     # input may be .xls/.xlsb/.ods/.slk/CSV/TSV/HTML;
                                                          # output .xlsx/.csv/.tsv/.json/.html/.pdf by extension
gridcraft-cli eval '=XLOOKUP("b",{"a","b"},{1,2})'        # → 2
gridcraft-cli cat book.xlsx --range A1:F20 [--formulas|--csv]
gridcraft-cli run --in book.xlsx --cmd 'cell.set={"cell":"D2","input":"=B2*C2"}' \
    --cmd 'edit.fillDown={"range":"D2:D20"}' --out book.xlsx --print A1:D5
gridcraft-cli check corpus/ --json --tolerance 1e-9       # calc oracle + XLSX round-trip fidelity
gridcraft-cli commands --search chart                     # every command and its params doc
gridcraft-cli functions --category statistical            # function list with signatures
gridcraft-cli send 7979 engine.execute '{"command":"home.bold","params":{"range":"A1:C1"}}'
  • run flags: --in FILE | --sample NAME, repeated --cmd, --script FILE, --out FILE, repeated --print RANGE|used, --sheet, --quiet, --csv, --formulas. A --cmd is id, id={json} or id {json}; a script has one step per line; blank lines and #/// comments are skipped. The first failing step stops the run with a non-zero exit.
  • convert refuses an unknown output extension; .pdf goes through file.exportPdf and reports bytes/pages; converting a .slk works because the input side reads SYLK.
  • check never writes next to its inputs. --json output is schema gridcraft-check/1.

MCP

claude mcp add gridcraft -- gridcraft-cli mcp                     # headless in-process session
claude mcp add gridcraft-app -- gridcraft-cli mcp --connect 7979 # drive the visible app

Results are one text block holding pretty JSON; failures set isError: true. Unknown tools, missing/wrong arguments are JSON-RPC -32602; malformed JSON -32700; unknown methods -32601. The remote backend uses a 30 s socket timeout: after a timeout, re-read the state instead of retrying blind. list_windows enumerates the open workbook windows; address a window where the backend accepts it.

Control channel (drive the running app)

GridCraft --sample sales --control 7979
# stderr prints the token file path (or use --control-token / GRIDCRAFT_CONTROL_TOKEN), then
# newline-delimited JSON to 127.0.0.1:7979 — the FIRST line must authenticate with the token:
{"id":0,"method":"auth","params":{"token":"<token>"}}
{"id":1,"method":"engine.execute","params":{"command":"cell.set","params":{"cell":"B2","input":"=SUM(A1:A9)"}}}
{"id":2,"method":"ui.object.select","params":{"id":3}}
{"id":3,"method":"ui.screenshot","params":{"path":"shot.png"}}
  • Authentication is required: a connection that does not authenticate first is closed, as is one that later sends a malformed line. The first line must arrive within 10 s and be at most 4 KiB; at most 16 connections may be waiting to authenticate. gridcraft-cli send reads the token file automatically.
  • Run ui.inspect first (ribbon tab, editor, open dialog, Backstage page, message, grid rect, scroll, perf, windows) and act on what it shows; ui.screenshot needs a presented frame.
  • Limits: 64 MiB per request line; 10,000 queued synthetic pointer events and 8 MiB of synthetic input (pointer, key, text and move events share the budget); the server waits 60 s for the UI, then reports a timeout. A request the client abandoned is dropped unrun; if the app had already started it, the reply says the outcome is unknown — read the cell/state before retrying.
  • The port binds localhost only and is token-authenticated; do not expose it.
  • ui.dialog.confirm sends exactly what the dialog's OK sends; dialogs without an OK command return "this dialog has no OK command; drive it with its own commands".

Document model and save/export flow

  • One native window per workbook window: view.newWindow shares the workbook (no clone; saving from either window saves it), view.arrangeAll tiles, window.list/window.close manage windows, and view.switchWindows/window.activate switch workbooks. Sheet tabs at the bottom. File opens the Backstage with 9 pages: home, new (three samples), open (recents), info, saveAs, print, export, options, account.
  • Save (file.save, file.saveAs, ⌘S, ⇧⌘S): the extension picks the format — .xlsx (default), .csv, .tsv, .json, .html, .pdf; a .pdf save exports the sheet and leaves the document dirty. file.saveBytes {format} returns base64 without writing.
  • Exports: file.exportPdf, file.exportCsv, file.exportHtml, file.printPreview, and on the desktop ui.printSettings / ui.printSubmit (native jobs via craft-print).
  • Opening a .xls/.xlsb/.ods produces a document titled <name> (imported).xlsx with no save path; a .slk keeps its own name and path, so a later Save is refused (SYLK is import-only) — Save As .xlsx first. Opening an already-open path switches to it; a password-decrypted workbook also has no save path.

Keyboard essentials (verified)

  • 72 shortcut bindings on command specs (F3 → Paste Names, Ctrl+8 → Show Outline Symbols, Ctrl+Shift+U formula bar, Ctrl+. → next corner), plus 5 macOS-only overrides, plus a wider keymap table for number formats, borders, F-keys and Alt/Option combinations (crates/ui-egui/src/keymap.rs).
  • Essentials: ⌘S save, ⇧⌘S Save As, ⌘O open, ⌘N new, ⌘W close, ⌘Z undo, ⌘Y redo; ⌘B/⌘I/⌘U; ⌘1 Format Cells; ⌘D fill down, ⌘R fill right; ⌃E Flash Fill; ⌘T table; ⌘K link; Ctrl+Shift+L filter; F2 edit; F3 Paste Name; Ctrl+Shift+4 currency; Ctrl+Shift+7 outline border; Ctrl+` show formulas; F9 calculate; Ctrl+[ / Ctrl+] precedents/dependents; Ctrl+6 hide/show objects; Ctrl+8 outline symbols; Ctrl+. moves to the next corner of the selection (new); Ctrl+Shift+U formula bar.
  • Key tips: F10 (or left Alt on Windows/Linux/BSD), then sequence letters; 413 sequences cover every ribbon tab, including the Excel 2003 menu paths (Alt+I, R; Alt+D, S; …).
  • The macOS native menu has Tools ▸ Command Palette… (⌘⇧P).

Working with an AI agent

Prefer headless over GUI. For read/write/convert/verify jobs use gridcraft-cli (or MCP) on files: no window, no preferences (set GRIDCRAFT_NO_PREFS=1 if you launch the app), deterministic. Drive the GUI over the control channel only when the task is genuinely about the UI. Never drive blind — ui.inspect/ui.screenshot before and after.

Legitimate agent work:

  • Prepare inputs. Build .xlsx from commands (gridcraft-cli run --script steps.jsonl), convert .xls/.xlsb/.ods/.slk/CSV/TSV/HTML into .xlsx, or generate CSV/TSV/JSON and import. Use file.open {csvAsText:true} when leading zeros must survive. Remember an import opens as an unsaved "(imported).xlsx".
  • Interpret/repair files. XLSX is native and documented in code. "Repair" means: open in GridCraft, inspect (info, check), fix with commands or formulas, save as .xlsx. Do not promise recovery of parts GridCraft does not model. Opening recalculates, so read a file's cached values through gridcraft-cli check/package inspection rather than by opening it in a session.
  • Verify exports honestly. Run gridcraft-cli check on round-tripped files, compare cat/info output against expectations, check PDF page counts and links. A zero exit from check means GridCraft agrees with itself and with the file's cached values; it does not prove Excel will open the file without a repair prompt.
  • Scripts. Recorded scripts are a convenience layer over the same command ids. A workbook received from elsewhere carries its scripts as a hidden name; nothing runs until the workbook is trusted, and script steps cannot touch files, links or windows. A leftover undo group blocks undo/redo: clear it with automate.stopAction.
  • Work with two views: view.newWindow shares the workbook — two windows, one document; list_windows (MCP) and window.list enumerate them; view.arrangeAll tiles.
  • Objects and controls: select an object with ui.object.select before clicking or dragging it, and use control.list/control.setValue rather than clicking a slider or spin button by coordinates. control.press on a workbook that came from a file asks for approval — pass approve only when the user asked for that action.

Must NOT attempt:

  • Writing .xls/.xlsb/.ods/.slk, or saving password protection; expecting macros or Python to run; expecting slicers/timelines to survive a save; assuming a full HTML document import.
  • Raw XML surgery on .xlsx files that contain unmodelled parts: GridCraft's own writer is the supported path, and even it drops parts it does not model once it rewrites them. Prefer read-only analysis of such files.
  • Treating formulas as locale-independent without checking docs/formula-input.md: Spanish input/display exists, but files, commands and APIs use canonical English names and , separators.
  • Promising PDF output for Arabic, Devanagari or Thai (no glyphs in the CID font, no shaping); verify CJK output visually first.
  • Calling app.quit or file.close {force:true} while a workbook has unsaved changes: both discard them silently. Save first.
  • Connecting to a --control port without the token (the connection is closed), or assuming the channel is unauthenticated — it is not.

Verification protocol (alpha discipline)

  1. Throwaway round-trip before real work: new workbook → the exact edit → save .xlsx → reopen (or gridcraft-cli info/cat) → gridcraft-cli check file.xlsx. Add the source file itself to check when testing formula fidelity.
  2. Never trust a silent export. CSV/HTML/PDF are one-shot exports with no diff UI. Re-read or re-import the artifact. Remember PDF export cannot be assumed to render Arabic/Devanagari/Thai.
  3. Version and back up. Keep the previous copy of any workbook you edit; autosave covers only workbooks that already have a file. For agent runs, save after each logical step (--out) rather than at the end.
  4. Update between projects, not during. The app auto-updates through the ArtCraft Launcher; update, then re-run your round-trip before a new task. This skill was audited at GridCraft 0.17.0; if the app prints a newer version, re-check the counts in evidence.md against the new tag.
  5. After a control/MCP timeout, re-read state (cell.get, sheet.read, document.inspect) before retrying: a queued request is dropped, but one already taken may still finish.
  6. Trust deliberately. Do not call automate.trustScripts on a workbook you did not create unless the user asked you to run its scripts.

Sources & evidence

  • Repo: https://github.com/storytold/gridcraft — inspected at tag v0.17.0, commit a6a6a49a0415087474251b08e887a3581fab9e14 ("Release 0.17.0"); the v0.16.0 tag (85e51e009c24fad47575f04d3c08f12342615d82) was inspected for id and count diffs. The installed bundle /Applications/GridCraft.app matches the tag: Contents/Info.plist reads CFBundleShortVersionString 0.17.0 / CFBundleIdentifier ai.storyteller.gridcraft, and its binary prints GridCraft 0.17.0. If your installed version differs, verify against it.
  • Date of inspection: 2026-11-07. Repo treated read-only (not built or modified; the app binary was run only with --version).
  • Key files read: README.md, Cargo.toml, Cargo.lock, ROADMAP.md, docs/{cli,mcp,control-protocol,parity-checklist,function-parity,chart-parity,file-format-parity,gaps,target-app-parity,formula-input}.md, apps/gridcraft-cli/src/{main.rs,check.rs,check/fidelity.rs,check/calc.rs,check/package.rs}, apps/gridcraft/src/{main.rs,control_server.rs,native_menu.rs,logging.rs}, apps/gridcraft-web/src/{main.rs,web.rs,host.rs,hostmode.rs}, crates/engine/src/{io.rs,io/sylk.rs,lib.rs,sample.rs,catalog.rs,cmd.rs}, crates/engine/src/cmd/ (incl. controls.rs, extra.rs, view.rs, edit.rs, python.rs, equation.rs, solver.rs, analysis.rs), crates/xlsx/src/{controls.rs,omml.rs,python_part.rs,read.rs,write.rs,drawing.rs,package.rs,csv.rs}, crates/pdf/src/lib.rs, crates/mcp/src/{tools.rs,server.rs,backend.rs,control_auth.rs}, crates/ui-egui/src/{control.rs,keymap.rs,backstage.rs,objects.rs,form_controls.rs,app/commands.rs,app/clipboard.rs,i18n.rs,i18n/}, crates/ui-egui/src/keytips/{keytips.json,keytip_table/generated.rs}, xtask/src/{parity.rs,keytips.rs}, crates/model/src/{features.rs,workbook.rs,sheet.rs}, crates/functions/src/, crates/calc/src/{eval.rs,eval/special.rs}, apps/gridcraft/Cargo.toml, apps/gridcraft-web/Cargo.toml.
  • Counts were re-measured from code, not prose: engine commands by a cmd! first-literal id extract (384 distinct ids) plus the one explicit CommandSpec literal (review.allowEditRanges) — 385 registered at v0.17.0 vs 372 at v0.16.0, register-set diff +13/−0; catalog coverage by intersecting the 296 distinct crates/engine/src/catalog.rs ids with registered ids (281 implemented, matching the generated docs/parity-checklist.md); MCP tools by tool( calls in crates/mcp/src/tools.rs (22, same name set at both tags); CLI subcommands by the main() dispatch arms (11); control methods by the handle match arms (35 names / 30 arms, same set at both tags); UI-only ids by the engine.commands array (18 vs 17); shortcut bindings by the non-None fourth cmd! argument (72 vs 71); key-tip sequences by the crates/ui-egui/src/keytips/keytips.json entries and the generated table (413 vs 367); languages by Language::ALL (19); chart kinds by the ChartKind enum (26); functions by the f! names outside #[cfg(test)] modules plus SPECIAL_FUNCTIONS, minus the two names not on Microsoft's list (USDOLLAR, ECMA.CEILING) → 513 present, 10 absent, 9 stubs; check categories by the diff_workbooks list plus package (14).
  • Pinned shared code: craft-libs c5a1cbfb5f9049f9270955caffb5bee5997aebf7 for craft-update, craft-window, craft-ui, craft-print and craft-i18n; craft-web-host at 2e2312ddaf21bc3d85cd3395d0955c7d239306f6; the egui 0.37 fork at 6d518fc799681571963842f95b55a6b68431b15a (Cargo.toml, Cargo.lock).
  • Deeper per-topic reference (repo docs): docs/target-app-parity.md, docs/gaps.md, docs/architecture.md, docs/parity-checklist.md.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.