Guide for building custom interactive web apps ("mini apps") displayed in the chat sidebar — scaffolding, iframe constraints, bidirectional messaging with the sandbox, and iteration workflows.
Mini apps are custom interactive web apps that render inside an iframe in the stagewise chat sidebar. Useful for dashboards, visualizations, forms, interactive tools, and any UI that benefits from rich HTML/CSS/JS beyond plain text.
apps/)The apps/ mount is always available with full read-write permissions. Each app lives in its own subfolder with index.html as the required entry point. Optional sibling assets (styles.css, script.js, images, etc.) are resolved via relative references.
apps/{appId}/
index.html ← entry point (required)
styles.css ← optional
script.js ← optional
Create and edit app files (index.html, styles.css, script.js), then reload via the sandbox with await API.openApp("appId").
opts.height).Use API.openApp(appId, opts?) from the sandbox. The sandbox is used only for opening apps and communicating with them.
| Option | Type | Default | Description |
|---|---|---|---|
pluginId | string | — | Opens a plugin app instead of an agent app |
height | number | 300 | Iframe height in pixels |
openApp replaces the current one.appId reloads the iframe — use after editing files.Apps and the sandbox communicate via postMessage.
Sandbox → App: API.sendMessage(appId, data, opts?) — sends a JSON-serializable message to the active app.
App → Sandbox: API.onMessage(appId, callback, opts?) — registers a listener for messages the app sends via window.parent.postMessage(data, "*"). Returns an unsubscribe function. Listeners persist across IIFE executions; use globalThis to accumulate messages.
Inside the app (HTML/JS):
window.addEventListener("message", (e) => { /* e.data */ })window.parent.postMessage({ action: "clicked", id: 1 }, "*")openApp, sendMessage, and onMessage.max-width: 100%, overflow-x: hidden, box-sizing: border-box.<meta name="viewport" content="width=device-width, initial-scale=1">.index.html as entry point. Split CSS and JS into separate files for maintainability.action field to distinguish message types.API.onMessage when interaction is complete.For detailed examples, see:
references/examples.md — Full mini app examples (minimal app, multi-file app, interactive picker with messaging)