AeroTable
A browser-first data workspace for VS Code for the Web: edit a CSV like a
spreadsheet, query the edited tables with DuckDB-Wasm, and export the results.
The editor and public agent tools share one workspace session.
First release
- Load headered UTF-8 workspace CSVs, with optional number/boolean inference.
- Edit cells, paste tab-separated rectangular ranges, add/delete rows, and undo/redo.
- Inspect typed columns and select cells or ranges with click / Shift-click.
- Run SQL over the current edited tables, including joins and aggregates.
- Inspect read-only query snapshots and export a whole table, result, or selection.
- Cancel a query without losing edits; later queries start a clean DuckDB Worker.
- Use public tools through AeroCode or any compatible VS Code agent.
VS Code Web is the primary platform. The extension has a browser entry point,
uses vscode.workspace.fs, and has been tested against a virtual filesystem in
VS Code Web 1.109.0. Desktop VS Code uses the browser extension host; a separate
desktop validation lane is not included yet. No terminal, local database server,
Node runtime, CDN, or remote MCP service is needed at extension runtime.
Use it
Install the VSIX in VS Code Web and open a trusted workspace.
Run AeroTable: Open Data Workspace, then Open CSV. A CSV's editor title
and Explorer context menu also expose AeroTable: Open CSV.
Edit a cell and press Enter or move focus to commit. Paste a rectangular range
from a spreadsheet. Add rows before pasting beyond the current table.
Query the table using the name shown in the sidebar, for example:
SELECT name, SUM(amount) AS total
FROM table_1
GROUP BY name
ORDER BY total DESC
Choose Export CSV for all rows, or Export selection for the selected
range. Ctrl/⌘+S opens the export dialog. Choose the original source path and
confirm replacement to save edits back to that CSV.
Queries run with Ctrl/⌘+Enter. Query results are read-only: joins and aggregates
do not necessarily map to an editable source cell.
Each result view owns its SQL draft and latest successful result. Select a view
to restore its draft; Run query again (Ctrl/⌘+Enter) updates that same view.
Run in new view keeps the current result available for comparison. Edits to
SQL are marked until run, and SQL that produced these results always shows
the exact executed SQL. Errors and cancellation retain the previous rows and
identify the failed attempt. Drafts survive switching views and closing/reopening
the editor within the same extension session. They are not saved SQL files.
Visible view names stay stable across reruns; each execution still produces a
new immutable result ID for agent inspection, selection, and export. Retention
is bounded to four snapshots: older executions expire before another view's
latest result. Creating a fifth view expires the oldest other view; Run in new
view protects the view being used for comparison. Close view
removes the view and draft; its immutable result remains available until evicted.
Data and save semantics
The first row is the header. Column names must be unique ignoring case. Inference
recognizes conservative numeric values as DOUBLE and true/false as
BOOLEAN; other values use VARCHAR. Leading-zero identifiers and high-precision
numeric strings stay text. Disable inference when the source must remain text.
DOUBLE columns have normal floating-point arithmetic semantics.
An unquoted \N represents NULL. Empty fields are empty strings; quoted
"\N" is literal text. Set NULL changes the selected cells to missing values.
Invalid typed edits fail atomically. CSV formatting is normalized on export:
CRLF records, standard quote escaping, a header, and the explicit NULL convention.
Edits are temporary until exported. Closing the editor tab preserves the session
in the extension host; closing a table discards it. Reloading the window or
deactivating the extension loses the session. Saved sessions and SQL files are
follow-up work. Exporting under a new name does not mark the original source saved.
Existing and unsaved destination files are protected. Parent directories must
already exist. Filesystem providers do not supply a portable atomic compare-and-swap,
so save-back is an explicit overwrite rather than a concurrent-edit merge.
| Tool |
Purpose |
aerotable_open |
Open/focus the editor |
aerotable_load |
Load a workspace CSV |
aerotable_inspect |
List tables/results or read a bounded page |
aerotable_edit |
Edit cells/rows or undo/redo against an expected version |
aerotable_query |
Query edited tables and obtain an immutable result ID |
aerotable_selection |
Inspect the exact visible selection |
aerotable_export |
Export a complete table, result, or selection |
aerotable_cancel |
Cancel the current query, preserving editable data |
aerotable_close |
Discard one table from the session |
Tools are declared in contributes.languageModelTools and registered through
vscode.lm.registerTool. Consumers use vscode.lm.tools and
vscode.lm.invokeTool; no AeroCode-private API is involved.
Results use the family's protocol-v1 envelope: ok, capabilityStatus,
recoverable, effectOutcome, text, artifacts, and data or error.
Edits require expectedVersion and zero-based row/column indices. Query result
cells use DuckDB's VARCHAR rendering with the original SQL types alongside them,
preserving BIGINT/DECIMAL/timestamp precision across JSON and CSV.
Effectful agent tools request the standard VS Code confirmation. If AeroCode or
another invoking agent already supplies approval, set aerotable.confirmAgentTools
to false to avoid duplicate prompts. Workspace trust, stale-version checks, and
explicit overwrite rules remain enforced.
The versioned direct extension API uses the same operation names:
const extension = vscode.extensions.getExtension('bpcarson.aerotable');
const api = await extension.activate();
const result = await api.invoke('aerotable_load', { workspacePath: 'sales.csv' }, {
// The consuming extension presents approval in its normal user flow.
approve: async ({ tool, input }) => askUserToApprove(tool, input),
cancellationToken,
});
Effectful direct calls without an approval callback return DENIED. This is a
public integration contract, not a sandbox against hostile installed extensions.
Limits and isolation
The extension host owns the editable tables, undo history, selections, workspace
access, and result handles. Each query builds a disposable DuckDB database in a
dedicated Worker from versioned Arrow snapshots of the loaded tables. SQL cannot
modify the canonical source tables. DuckDB external access and automatic extension
loading are disabled; its configuration is locked before user SQL runs. No workspace
credentials are passed to DuckDB. The bundled single-threaded runtime requires no
cross-origin isolation headers.
| Resource |
Initial bound |
| CSV input |
4 MiB per file |
| Tables |
8 per session |
| Table dimensions |
20,000 rows, 100 columns, 200,000 cells |
| Table / session data |
8 MiB / 24 MiB serialized |
| Undo history |
30 entries and 8 MiB per table |
| Edit batch |
10,000 cells |
| Inspection page / selection preview |
200 / 50 rows |
| SQL source / execution deadline |
64 KiB / 30 seconds |
| Complete query result |
10,000 rows and 4 MiB |
| Retained query results |
4 snapshots |
| DuckDB configured memory limit |
128 MB |
The DuckDB memory setting is an engine budget, not a total browser memory guarantee.
The deadline covers runtime setup, import, and query execution. Cancellation or
timeout terminates the Worker. Over-limit results fail visibly; they never become
silently truncated exports. Result previews and grid pagination do not limit exports.
Development
Node.js 22+ is needed for build and test tooling only.
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm ci
npx playwright install --with-deps chromium
npm run verify
npm run test:web
npm run package:vsix
verify runs unit checks, bundles the web extension, and drives the production grid
and actual DuckDB-Wasm in Chromium. The browser harness adapts file dialogs and the
VS Code message transport. test:web separately runs the extension's public API,
tool discovery/invocation, and virtual-filesystem export in pinned VS Code Web
1.109.0 (bdd88df003631aaa0bcbe057cb0a940b80a476fa). Neither lane uses a model.
The verification workflow retains the VSIX and browser evidence as artifacts. AEROTABLE_CHROMIUM optionally selects an installed test browser.
DuckDB-Wasm and both WASM bundles are packaged in the VSIX. The lockfile pins
dependencies; the current npm runtime version is 1.33.1-dev57.0. Runtime assets
are loaded from the installed extension. Browser tests use no runtime CDN.
Releases
AeroTable follows the AeroKit publishing pipeline:
- Verify web extension checks each pull request and push to
main.
- After a successful push check, Auto Patch Version calls the shared
bpcarson/actions workflow. App changes without an explicit version bump
produce a patch-version PR, which the shared workflow merges before dispatching
Release on version bump. Documentation and workflow-only changes do not
trigger an automatic patch.
- Release on version bump creates or resumes the
v<package.json version>
release and calls Publish VSIX directly. This also works for releases
created with GITHUB_TOKEN, which do not trigger another release-event workflow.
- Publish VSIX checks out the release tag, validates the version and Marketplace
identity, runs both browser test lanes, packages
dist/aerotable.vsix, attaches
that exact VSIX to the release, and publishes it as bpcarson.aerotable.
Set the repository Actions secret VSCE_TOKEN to a Marketplace publishing token
for bpcarson. It is exposed only to the publishing step. The repository must
allow access to the shared workflow and permit GitHub Actions to create and
approve pull requests; branch rules must allow the shared version-bump workflow
to merge its PR.
For the initial release after merging these workflows, run Release on version
bump manually on main. A workflow-only merge does not bump the version.
To retry an existing release, run Publish VSIX with its tag (for example
v0.1.0). Retries replace the GitHub release asset and skip a version already
published to the Marketplace.
See the north star for the agreed direction and follow-up
scope: richer grid interactions, editable query-derived tables, JSON/Parquet,
saved workspace sessions, AeroKit evaluation, and optional MCP Apps.
MIT licensed. DuckDB-Wasm and Apache Arrow retain their upstream licenses.