A fast, keyboard-first, local-only spreadsheet for people who care about flow.
VisiGrid is a native spreadsheet app that starts instantly, stays out of your way, and makes its work visible. It's built for Linux-first workflows, power users, and anyone tired of heavyweight, ribbon-driven spreadsheets.
Built in Rust, powered by GPUI (the GPU-accelerated UI framework behind Zed).
Most spreadsheets feel heavy.
They take seconds to open. They hide actions behind menus. They encourage copy-paste instead of understanding.
VisiGrid is built to feel light, fast, and intentional:
When correctness matters, VisiGrid also makes failure visible:
For advanced workflows, VisiGrid also includes a CLI and headless mode built on the same engine.
VisiGrid was influenced by keyboard-first Linux environments such as Omarchy — prioritizing speed, minimal friction, and staying in flow.
The desktop app is the debugger for your data.
Most AI tools trade explainability for convenience. VisiGrid doesn't.
The problem: AI in spreadsheets typically means black-box automation — formulas appear, values change, and you're expected to trust the result. When something goes wrong, there's no audit trail.
VisiGrid's approach: AI is a witness, not an author.
Cell-level truth — Inspector shows formula, value, inputs, dependents. Deterministic, local, zero AI involvement.
Change-level accountability — Every mutation is tagged: Human vs AI (with provider and timestamp). The diff engine surfaces net effects. AI-touched filter exposes exactly where AI participated.
Narrative understanding — "Explain this change" and "Explain differences" describe what happened in plain language. Both are optional, bounded, and never modify data.
When you open a workbook six months from now, you can answer: - Which values came from AI? - What exactly did it change? - Can I verify the formula it suggested?
The answer to all three is yes. That's what "explainable" means.
Get the latest release from Releases.
| Platform | Download |
|---|---|
| macOS (Universal) | .dmg |
| Windows (x64) | .zip |
| Linux (x86_64) | .tar.gz / .AppImage |
Or via package manager:
# macOS
brew install --cask visigrid/tap/visigrid
# Windows
winget install VisiGrid.VisiGrid
# Arch Linux
yay -S visigrid-bin
Requires Rust 1.80+.
git clone https://github.com/VisiGrid/VisiGrid.git
cd VisiGrid
cargo build --release -p visigrid-gpui
./target/release/visigrid
# Ubuntu / Debian
sudo apt-get install libgtk-3-dev libxcb-shape0-dev libxcb-xfixes0-dev \
libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev
For users who treat spreadsheets as part of a larger system, VisiGrid includes a full CLI and headless execution mode built on the same engine.
VisiGrid ships a CLI that runs without a GUI. Same engine, no window.
# Evaluate a formula against piped data
cat sales.csv | vgrid calc "=SUM(B:B)" --from csv
# Reconcile two datasets by key
vgrid diff vendor.xlsx ours.csv --key Invoice --compare Total --tolerance 0.01
# Convert between formats
vgrid convert data.xlsx --to csv
# Project a vendor export down to reconciliation columns, then diff
vgrid convert vendor.xlsx -t csv --headers --select 'Invoice,Amount' | \
vgrid diff - our_export.csv --key Invoice --compare Amount --tolerance 0.01
The CLI reads spreadsheet files (CSV, XLSX, JSON, TSV), runs the same formula engine and comparison logic as the GUI, and writes structured output to stdout. Exit codes are stable for scripting. Output is JSON or CSV.
Filtering rows (convert --where) — no awk required:
# Pending transactions
vgrid convert rh_transactions.csv -t csv --headers --where 'Status=Pending'
# Pending charges (negative amounts)
vgrid convert rh_transactions.csv -t csv --headers \
--where 'Status=Pending' --where 'Amount<0'
# Vendor name contains
vgrid convert rh_transactions.csv -t csv --headers \
--where 'Description~"google workspace"'
Five operators: = != < > ~ (contains). Typed comparisons — numeric RHS triggers numeric compare, string RHS triggers case-insensitive string compare. Lenient parsing handles $1,200.00. Multiple --where = AND.
Column selection (convert --select) — pick and reorder output columns:
vgrid convert data.csv -t csv --headers --select 'Status,Amount'
# Filter by one column, output different ones
vgrid convert data.csv -t csv --headers \
--where 'Status=Pending' --select 'Amount,Vendor'
Reconciliation (diff) compares two datasets row-by-row:
- Rows only in the left file, only in the right file, or in both with value differences
- Numeric tolerance for financial data ($1,234.56, (500.00) handled natively)
- Either side can be - to read from stdin — pipe live exports directly into reconciliation
- Duplicate keys and ambiguous matches fail loudly instead of guessing
Example summary (from --out json):
{
"contract_version": 1,
"summary": {
"matched": 14238,
"only_left": 12,
"only_right": 9,
"diff": 3,
"diff_outside_tolerance": 1
},
"results": [ ... ]
}
Control a running VisiGrid GUI from the terminal. Inspect cells, apply changes, and watch state evolve — all from scripts or the command line.
# List running sessions
visigrid sessions
# View live grid snapshot (auto-refresh on changes)
visigrid view --follow
# Inspect a cell
visigrid inspect A1
# → A1 = 1234.56 (number)
# Apply operations with retry on contention
cat ops.jsonl | visigrid apply --atomic --wait
# Query server health
visigrid stats
Session protocol: TCP localhost with token auth. Protocol v1 is frozen — wire format locked by golden vectors.
Scriptable control loop:
# Get session
SESSION=$(visigrid sessions --json | jq -r '.[0].session_id')
# Inspect current state
REV=$(visigrid inspect workbook --json | jq '.revision')
# Apply changes with revision check (prevents stale overwrites)
visigrid apply ops.jsonl --atomic --expected-revision $REV --wait
# Verify new state
visigrid view --range A1:D10
Exit codes are stable for scripting: 0 = success, 20-29 = session errors (conflict, auth, protocol).
VisiGrid provides a headless build loop for LLM agents and CI pipelines. Write Lua, build a .sheet, inspect results, verify fingerprint.
# Build from Lua script (replacement semantics — Lua is source of truth)
vgrid sheet apply model.sheet --lua build.lua --json
# Inspect cells to verify results
vgrid sheet inspect model.sheet B3 --json
# → {"cell":"B3","value":"220000","formula":"=SUM(B1:B2)","value_type":"formula"}
# Get fingerprint for audit trail
vgrid sheet fingerprint model.sheet --json
# → {"fingerprint":"v1:42:abc123...","ops":42}
# Verify in CI (exit 0 = match, exit 1 = mismatch)
vgrid sheet verify model.sheet --fingerprint v1:42:abc123...
Fingerprint boundary: set(), clear(), and meta() affect fingerprint. style() does not. Agents can format sheets without breaking verification.
Workflow rule: Always apply → inspect → verify. Never assume results.
See Agent Tools for MCP definitions and Claude MD Snippet for copy-paste instructions.
Exit 0 means reconciled (within tolerance). Exit 1 means material differences — missing rows or diffs outside tolerance. Exit ≥ 2 means error. No wrapper scripts needed.
Bank statement vs ledger:
# Reconcile bank export against your ledger
# --key-transform digits: match "INV-001" to "PO-001" by extracting "001"
vgrid diff bank_export.csv ledger.csv \
--key Reference --key-transform digits \
--compare Amount --tolerance 0.01 \
--out json
Vendor export via stdin:
# Pipe a live vendor export, project to reconciliation columns, then diff
curl -s https://vendor.example.com/api/export.csv | \
vgrid convert - -t csv --headers --select 'Invoice,Amount' | \
vgrid diff - our_export.csv --key Invoice --compare Amount --tolerance 0.01
CI gate with strict exit:
# In CI: fail the build if ANY value differs, even within tolerance
vgrid diff expected.csv actual.csv \
--key SKU --tolerance 0.01 --strict-exit --quiet || {
echo "Reconciliation failed — diffs detected"
exit 1
}
More examples:
# Quiet mode: just the exit code, no output
vgrid diff expected.csv actual.csv --key id --quiet
# Pipe a live export into diff
rails runner 'Ledger.export_csv' | vgrid diff - expected.csv --key id --quiet
# Verify a provenance trail hasn't been tampered with
vgrid replay audit-trail.lua --verify --quiet
NOW(), TODAY(), RAND(), RANDBETWEEN() fail --verify even in dead-code branchescalc reads from stdin only; no file-path argumentVisiGrid is fully usable under its open-source license.
Some organizations require additional guarantees around scale, support, or long-term use. Commercial licenses are available for large-file performance, team controls, and operational assurances.
See visigrid.app/commercial for details.
VisiGrid integrates with VisiHub, a public-first publishing service for versioned datasets.
VisiHub is optional and not required to use VisiGrid.
VisiGrid is open source under AGPLv3 with a plugin exception.
This ensures improvements remain open while allowing commercial plugins and extensions. Plugins using the public API may be licensed independently. Commercial licenses are available for organizations that require alternative terms.
See LICENSE.md for details.
Issues and pull requests are welcome.
Diff bug reports: if you file a bug against visigrid diff, include a minimal
CSV fixture that reproduces the issue. Every confirmed diff bug becomes a corpus
golden test in tests/cli/diff/ — this is how the contract stays honest.
See the Roadmap for what's next.
$ claude mcp add VisiGrid \
-- python -m otcore.mcp_server <graph>