Datasette Apps' Invisible-Iframe Sandbox: A Small Blueprint for Safer Coding Agents
A niche release note from Datasette Apps shows a concrete, low-drama pattern for letting an AI agent test the code it writes without giving it a live, interactive session to abuse.
Key Takeaways
- Datasette Apps 0.2a0 adds `app_debug()`, which lets its AI agent run JavaScript smoke tests inside an invisible, non-interactive iframe (`opacity: 0`, `pointer-events: none`) rather than a live, clickable session.
- A companion `app_list()` tool scopes what the agent can even see to apps the current user already has permission to edit — access control enforced before the agent acts, not after.
- Neither tool is presented as a security feature by its author, but the design maps directly onto two problems every team building agentic coding tools has to solve: containing agent-executed code, and bounding what the agent is allowed to touch.
- The pattern is worth studying, not copying blind — an invisible iframe still shares the page's origin, so its guarantees depend on what else that origin exposes.
Datasette Apps, Simon Willison's framework for building small applications inside the Datasette ecosystem, shipped version 0.2a0 with two additions aimed squarely at its companion AI system, Datasette Agent, which creates and edits these apps on a user's behalf. Neither addition is billed as a security fix. Read together, though, they're a useful, low-stakes worked example of a problem every team shipping an AI coding agent now has to answer: what is the agent actually allowed to run, and where does it run it?
What changed
The first addition is app_debug(). It lets the agent open the app it just wrote inside an iframe set to opacity: 0 with pointer-events: none, then execute agent-authored JavaScript inside that iframe to check the app behaves as intended. The app renders — DOM and all — but it is invisible and cannot be clicked, typed into, or otherwise driven by anything outside the agent's own script.
The second is app_list(), which returns the set of apps the *current user* already has permission to edit, so the agent only offers to modify apps that user is authorized to touch. Per the release notes, the two ship together as pull request #33 and issue #36.
Why this is worth a second look
Agentic coding tools have converged on a familiar failure mode: give an agent a real browser session or a real shell to "verify its work," and you've also given it a real browser session or a real shell — with all the side effects, credentials, and blast radius that implies. app_debug() sidesteps that by making the test surface deliberately inert. The agent gets a DOM to interrogate and a script runtime to execute in, but no path to actual user interaction, no visible surface to phish or spoof, and no pointer events to hijack. It's a narrow, purpose-built sandbox rather than a general-purpose one.
app_list() addresses a different, equally common gap: agents that are technically capable of editing *anything* the underlying platform can reach, constrained only by prompt instructions telling them not to. Scoping the agent's own tool output to what the requesting user is already entitled to edit moves that boundary from "the agent was told not to" to "the agent was never shown it as an option" — a meaningfully stronger guarantee, and one enforced in code rather than in a system prompt.
Where the analogy runs out
- An invisible iframe is still same-origin with the parent page in the common case — it isolates *visibility and interaction*, not necessarily cookies, storage, or same-origin fetch access. Teams adopting this pattern should confirm what the iframe's origin actually exposes before treating it as a trust boundary.
- Permission-scoped listing (
app_list()) only helps if every other tool the agent has access to enforces the same check. A single unscoped write path elsewhere reopens the gap. - The release notes don't describe threat modelling behind either change — this is our reading of the design, not a claim Willison made about its security intent.
None of this makes Datasette Apps a security product, and the release itself is a minor, alpha-tagged update to a niche framework. But as more teams wire coding agents into real developer workflows, the specific mechanics — an inert execution surface for self-testing, permission checks baked into what the agent can even enumerate — are a more useful reference point than another generic warning to "sandbox your agents."
Frequently Asked Questions
What is Datasette Apps and Datasette Agent?
Datasette Apps is a framework for building small applications inside Simon Willison's Datasette ecosystem. Datasette Agent is the companion AI agent that creates and edits those apps on a user's behalf; version 0.2a0 of Datasette Apps adds two tools, `app_debug()` and `app_list()`, specifically to support that agent.
How does the app_debug() sandbox actually work?
It renders the app inside an iframe styled with `opacity: 0` and `pointer-events: none`, then runs agent-supplied JavaScript inside that iframe to smoke-test the app. The app executes for real, but it's invisible and cannot receive clicks or input from outside the agent's own script.
Does this pattern fully solve agent sandboxing?
No — it solves visibility and interaction isolation for a specific self-test workflow. It doesn't, on its own, address same-origin data access, and it only constrains one tool; any other tool available to the same agent needs its own equivalent checks.
Sources
- 1datasette-apps 0.2a0 — Simon Willison
- 2datasette-apps 0.2a0 release — GitHub
- 3PR #33: app_debug() tool — GitHub