name: ai-driven-apps user-invocable: true description: >- How the AI builds, shows, drives, and tests an Adom app. In Adom the AI writes the app, shows it to the user (in their own already-signed-in native browser via Adom Desktop, in pup for the logged-out experience, or in a Hydrogen webview), drives the front-end over a live SSE or WebSocket channel to exercise every path (auto-click buttons, show and hide floaty toolbars, load a different symbol or footprint, click send-to-kicad), reads back state, console, and screenshots, and ralph-loops until the UI is right. Covers state-on-the-server, GET /state, GET /console, the live channel, the CLI driving commands, the three display surfaces and when to use each, and the ralph-test loop. Read BEFORE building or testing any Adom web app. Trigger words: ai-drivable, ai driven app, drive the front-end, drive the ui, live channel, SSE, server-sent events, websocket, GET /state, GET /console, ralph test, ralph loop, auto-click buttons, test the ui, show app in native browser, show app in pup, webview vs pup, native browser auth, logged out testing, ui click.

AI-driven apps

This is the loop the whole Adom UI system is designed around. The AI is both the builder and the tester; the user watches and steers. An app is only as good as the AI's ability to drive and observe it, so build for that from the first commit.

The loop

  1. The AI builds the app: a small server plus a webview UI, made drivable from day one (state on the server, a live channel, a CLI).
  2. The AI shows it to the user in one of three surfaces (below), chosen for what is being tested.
  3. The AI drives the front-end over the live channel to exercise every path: click each button, open and close the floating toolbar, load a different symbol or footprint, hit send-to-kicad, and read back state, the console buffer, and screenshots.
  4. The AI ralph-loops: screenshot, analyze what looks wrong, fix the code, reload, repeat, until the UI is correct and a pleasure to use.
  5. The AI narrates through toasts and chat so the user can follow along.

State on the server, observed two ways

  • The server owns the truth. The UI never keeps its own copy of "am I recording?" or "which symbol is loaded?". Buttons fire commands to the server; the server holds state.
  • GET /state returns the current state as JSON. The UI reflects it; the AI reads it to check progress without scraping HTML.
  • GET /console exposes the app's log: override console.log/warn/error to also post to the server, keep a ring buffer, and catch window.onerror and unhandledrejection. Now the AI reads what the UI is doing without DevTools.

The live channel

  • Expose Server-Sent Events for one-way push, or a WebSocket for two-way. The UI subscribes and updates the instant anything changes; the CLI subscribes too. A 300 to 500ms poll of GET /state is the minimum fallback, but the live channel is what makes driving feel instant.
  • Because the channel is two-way, the AI drives the front-end from the CLI. Every user-visible action has a command that does exactly what the click does:
    mytool ui click "send-to-kicad"      # press a button
    mytool ui toolbar show               # reveal the floating toolbar, then `hide`
    mytool ui load-symbol LM358          # swap the loaded symbol or footprint
    mytool ui toast "file downloaded"    # raise a toast (also the AI's narration channel)
    
    Each command drives the real UI through the same path a user click would, so the AI can walk every interaction, assert the resulting state, screenshot it, and move on. This is the test harness and the demo driver in one.
  • Acceptance test: an AI driving the app over the channel and a person clicking the UI produce identical visible results.

The three display surfaces

Pick the surface by what you need to test, and use more than one at once when it helps.

Surface What it is Use it for
Native browser (nb) The user's own Chrome or Edge, driven through Adom Desktop The real, signed-in experience. The browser is already the user's, so the app opens logged in with zero friction. Use it for anything behind a login.
pup A clean, scriptable Chrome the AI fully owns The fresh, logged-out, first-time-user experience, and automated screenshot loops that should not fight the user's own tabs.
Hydrogen webview An in-workspace browser tab Showing a result inside the workbench, next to the code and the chat.
hdbw (HD Browser Window) Under Hydrogen Desktop: a standalone Tauri browser window HD manages directly (window label hd-browse-*, destination id webview-window) A dedicated app window beside the HD shell — bigger than a pane tab, still HD-managed. Note: the in-HD pane tab is the wv surface (the webview skill routes there inside HD).

VS Code's "Simple Browser" is NOT a surface

NEVER show an Adom app in VS Code's built-in "Simple Browser". It is none of the Adom surfaces: no live channel, no console read-back, no AI drivability, wrong pane semantics. If you are about to paste an app URL into Simple Browser, stop and load the webview skill instead.

Every app's SKILL.md must carry a display section (MANDATE)

When you write or update an app's SKILL.md, include a section titled "Displaying this app (REQUIRED)" that (a) names the app's own show/open verb if it has one, (b) instructs loading the webview skill for manual display (pup / native browser / hdbw per the table above), and (c) states the Simple Browser ban verbatim. Skill discovery from trigger words alone is probabilistic; the app skill IS reliably loaded when the app is named, so it must carry the display rules itself. (Decision John 2026-07-17, after a fresh workspace showed adom-parts-search in Simple Browser.)

The native-browser and pup split is the point: open the logged-in path in the native browser and the logged-out path in pup at the same time, and verify both. Tell the user which surface and why.

Ralph-testing the UI

The visual feedback loop that turns "it runs" into "it is right": edit, reload, drive a step over the channel, screenshot, read the console buffer, analyze, fix, repeat. Drive it in pup (or the native browser), capture each frame to the screenshot log, and loop until the UI looks and behaves correctly. This is how the AI debugs UI with no human in the loop, and it is the proof the app is genuinely drivable.

Reaching a container app from outside

  • A webview and a browser window both render outside the container, so they cannot reach http://localhost:<port> or http://127.0.0.1:<port>. Always use the public proxy URL: https://<slug>.adom.cloud/proxy/<port>/.
  • Inside a webview, always use relative URLs. A leading slash bypasses the proxy and hits the wrong origin. Every fetch, href, src, and CSS url() must be relative.

Boundary with app-creator (do not blur it)

adom/app-creator owns CREATING the app: scaffolding, project layout, server + webview skeleton, wiring the first commit. THIS skill owns everything after: SHOWING the app, DRIVING its front-end, and RALPH-TESTING the UI until it is right. If you are adding "how to build/scaffold" content, it goes in app-creator; if you are adding "how to drive/verify/test the UI", it goes here. Keeping the line crisp is what stops the two skills drifting into contradictory duplicates.

app-creator (scaffolding the app), adom-screenshot (the ralph loop and shotlog), adom-cli-design and ai-hints-in-clis (the CLI the driving commands live in), toasts (the narration channel), app-shell (the layout being driven), and adom-ui-design (the hub).