-
-
DuckStudio idle state prior to dataset selection, displaying upload controls on the left and an empty workspace placeholder.
-
Default workspace screen showing no active tasks and prompting dataset activation from available presets or CSV upload.
-
DuckStudio SQL & Lineage tab displaying the generated aggregation query, execution metadata (92.5 ms over 250k rows).
-
DuckStudio displaying a DATASET_UNAVAILABLE error notification after attempting analysis without an activated dataset.
-
DuckStudio Charts dashboard displaying summary KPI cards and an "accounts by tickets" distribution scatter plot completed in 92.5 ms.
-
DuckStudio Charts view showing re-run or alternate query execution completed in 127.4 ms across 250,000 scanned records.
Inspiration
Analysts in healthcare and finance face strict data protection agreements (DPAs) and egress bans: data cannot leave the tab, but cloud LLMs cannot query browser memory.
WebMCP bridges this actuation gap by giving an agent browser-level tools. However, browser agents can observe both tool outputs and the rendered DOM. Sanitizing tool payloads is ineffective if the UI renders raw sensitive rows where the model can inspect them. DuckStudio solves this through custody with controlled release: the agent steers the analysis and inspects safe aggregates, but raw records never cross into tool envelopes or the rendered canvas.
What it does
DuckStudio is a privacy-first, agent native analytical app where a human and an AI agent operate the same local DuckDB-WASM engine. Data remains in the client tab.
WebMCP registers four imperative tools:
- duckdb_get_context — Returns capabilities, revision, schema digests, budgets, and permitted next actions.
- duckdb_activate_dataset — Switches datasets using optimistic concurrency through expectedRevision and idempotency keys.
duckdb_execute_sql_to_canvas — Validates read-only SQL before execution, runs it locally, creates an immutable artifact with lineage, infers an aggregate KPI or chart specification, and pins it to the canvas. It returns an artifact handle and safe summary—never raw rows.
duckdb_verify_zero_egress — Returns scoped evidence covering uploads, release decisions, network interceptors, and artifact lineage.
Core Invariants:
- › Policy follows the dataset.:
saas_churn(250,000 synthetic rows) runs underpublic_syntheticpermitting bounded row display.healthcare_pii(100,000 rows with MRN and diagnosis) runs undersensitive_aggregate_only, suppressing raw grids entirely and rejecting cohorts smaller than 10 patients ($k \ge 10$). - SQL is gated before execution: Permits only single, parameterized
SELECTorWITHqueries. Blocks DDL, DML,ATTACH,COPY, remote URLs, and extensions before DuckDB receives them. - Deterministic state: Monotonic revisions and idempotency keys prevent race conditions, stale writes, and hallucinated retries.
How we built it
- Stack: Vite, React, TypeScript, Tailwind CSS, lazy-loaded ECharts, and self-hosted
@duckdb/duckdb-wasmin a dedicated Web Worker. - Edge deployment & isolation: Deployed statically to Cloudflare Pages with
Cross-Origin-Opener-Policy: same-originandCross-Origin-Embedder-Policy: require-corp. DuckDB-WASM binaries (ehbundle) and fonts are self-hosted in/publicto avoid third-party CDN failure under strict COEP. - One command path: Human controls, prompt chips, the built-in simulator, and the 4 WebMCP tools all dispatch the exact same 6 domain commands through
revisioned-workspace. - Honest metrics : The initial workspace is empty—there are no pre-baked artifacts. SaaS metrics such as 14.2% churn and $182,400 impacted MRR are computed live by DuckDB from in- memory row generators and verified by CI contract tests
Challenges we ran into
- DOM as an exfiltration surface: Because agents can scrape rendered elements, we implemented a single custody boundary across tool payloads and React rendering. If a requested view violates policy, it is rejected outright ("deny-over-strip") rather than partially rendered.
- Eradicating ambient state: Agents fail when tracking implicit context like "the last query." We eliminated ambient state entirely: every canvas view and query refinement references an immutable artifact ID containing a cryptographic SQL hash and parent lineage.
- Wasm limits & worker lifecycles: Single-threaded DuckDB-WASM (
ehbundle) runs under a browser wasm memory ceiling, clamped to a 5,000 ms execution budget and a 10,000-row cursor. Query cancellation requires terminating and respawning the Web Worker to prevent memory corruption without leaving orphaned partial artifacts. - Evidence must be scoped honestly: The custody badge reads
0 Bytes of Dataset Uploaded. Interceptors auditfetch,XMLHttpRequest,sendBeacon,WebSocket, andWebTransportto separate analytical data from application bundle traffic, avoiding unsupported zero-knowledge claims.
Accomplishments that we're proud of
- Sub-second analytical queries over 250,000 rows executed entirely in client wasm with 0 bytes of dataset egress.
- Agents receive compact envelopes containing KPIs, chart dimensions, and artifact handles instead of raw row dumps.
- Self-healing recovery: queries that fail validation or custody rules return structured error codes and actionable recovery steps, allowing models to self-correct autonomously.
What we learned
- WebMCP is most reliable as an explicit, revisioned state machine. Providing schema digests and monotonic revisions prevents model hallucination far better than generic prompt engineering.
- Local execution is not sufficient for privacy. If an agent has DOM access, data custody must be enforced at the UI projection layer as strictly as the network layer.
What's next for DuckStudio
- Interactive virtualized Data Grid: High-performance, keyboard-accessible table with range selection and clipboard support for public datasets.
- OPFS streaming export subsystem: Stream CSV/Parquet outputs directly to the Origin Private File System to bypass wasm memory ceilings during large exports.
- SQL editor deep links: URL-addressable analysis states to share reproducible artifact lineage graphs.
- *In-tab AI chat panel *: BYO-LLM and WebLLM support with explicit, user-gated PII consent boundaries.
- Multi-threaded execution: Transition to DuckDB-WASM's
coibundle once cross-browser WebAssembly threading ergonomics and worker isolation stabilize.
Built With
- agent-native
- cloudflare-pages
- duckdb
- privacy
- webassembly
- webmcp
- zero-egress

Log in or sign up for Devpost to join the conversation.