The auto-served Preview pane
When an app builds a web app into the session workdir, the daemon shows the
running result in the Preview pane automatically — no SDK code and no
preview-module call. This is how Craft works: the agent runs npm run build,
and the built dist/ loads in the preview tab on its own. This page is the exact
contract.
1. Turn the Preview view on (in app YAML)
The Preview view is opt-in. Enable it in ui.workspace — this is the real block
from Craft (internal/appmgr/builtins/digitorn-craft/app.yaml), trimmed:
ui:
workspace:
render_mode: react # how the pane renders (react | html | markdown | …)
entry_file: src/App.tsx
position: right
default_open: true # land on the pane, not an empty chat
auto_open_on_first_tool: true
default_view: preview # open ON the preview tab
shown_views: [code, changes, preview] # preview is HIDDEN unless listed here
preview_chrome: # the toolbar above the auto-served iframe
enabled: true
refresh: true
open_in_new_tab: true
viewport_toggle: true # mobile / tablet / desktop
url_bar: auto # shown once the app has ≥ 2 routes
The one line people forget: preview must be in shown_views (it is hidden
by default like every opt-in surface). Grant the preview
module (inspect, snapshot) too if you want the agent to see and drive the
pane — but that grant is not what makes the build appear.
2. The daemon auto-detects the build
With the view on, the daemon watches the workdir and serves the first built entry it finds — you don't point it anywhere. Detection order:
dist/index.html build/index.html out/index.html public/index.html index.html
…checked at the workdir root and one directory deep. Build to any of these
(a Vite app's dist/ is the common case) and the running app appears in the
pane; the toolbar's Refresh re-loads it after a rebuild. Build somewhere else
(e.g. a custom www/) and nothing attaches — move the output to a detected path.
3. Agent-started dev servers (local only)
If the agent starts Vite / Next on a loopback port via bash, the daemon can
also attach that to the pane (as a devserver preview) — but only on a
local / desktop install. On a cloud install (apps.channel: server),
dev-server auto-attach is turned off, so a cloud app must ship a static
build (dist/index.html) to get a live preview. Exposing a dev-server port
publicly is separate infrastructure (reverse proxy / DNS), not an app-YAML
feature.
Not to be confused with
This native, auto-served preview is distinct from a hand-built
usePreviewAttach() view (only needed for a
custom SDK panel) and from a template's preview_path thumbnail. See
Which "preview" is which?.
Related
- preview module (
inspect/snapshot) - Client manifest — the full
ui.workspaceblock - UI surfaces tutorial
- Production checklist