name: ralph-loop-test description: >- The Adom "ralph test" (Ralph Wiggum loop) — a screenshot-driven fix loop for apps. Point it at the user's running app (almost always a WEB APP in a webview / pup / the native browser, sometimes a DESKTOP APP driven via an adom-desktop bridge): load it, screenshot it, feed the shot to the AI, the AI analyzes what's wrong and fixes it, then reload the page (or reload the file in the desktop app), screenshot again, and loop until it's right. Covers every Adom screenshot surface — Hydrogen webview (adom-cli), pup, the native Chrome/Edge extension (nbrowser_*), and desktop bridges — plus the shotlog viewer workflow (how to actually see shots when the VS Code extension can't show images inline). Use when the user says "ralph", "ralph test", "ralph wiggum", "ralph loop", "screenshot loop", "visual fix loop", "loop until it's fixed", "test my app with screenshots", or "keep screenshotting and fixing until it works".
Ralph Test (Adom) — the screenshot-driven fix loop
In the Adom world a ralph test (a Ralph Wiggum loop) is a visual fix loop, not a code-build loop. You point it at the user's running app — almost always a web app (shown in a Hydrogen webview, in pup, or in the native Chrome/Edge browser), sometimes a desktop app driven through an adom-desktop bridge — and you grind this cycle:
- Load the app on a surface you can screenshot.
- Screenshot it.
- Feed the shot to the AI → it analyzes what's wrong (broken layout, wrong/missing data, a console error, off-brand styling, an element that should be there and isn't).
- Fix the cause — edit the app's code / config / data (or the desktop file).
- Reload — reload the page in the browser, or reload the file in the desktop app.
- Screenshot again, and
shotlog injectit — that's how you and the user actually SEE the shot (the Claude Code VS Code extension can't show images inline). - Loop — repeat until the screenshot matches intent.
"Ralph" because it's gloriously dumb and persistent: the same look → fix → reload cycle, over and over, until the shot is correct. Memory of what's been tried lives in the app's own state + the shotlog history, not the context window.
Where you're running
The AI always runs from a container, and they all carry the same screenshot tools, so this loop works identically everywhere:
- Hydrogen Web — a Docker cloud container.
- Hydrogen Desktop — a WSL2 container (Windows), a Lima container (Mac), or an Ubuntu container (Ubuntu).
What changes per task is only which surface you load the app on. Pick it in Step 1.
Targeting:
adom-desktopverbs hit the user's laptop. If more than one desktop is on the relay you MUST name one (-t AdomLapper) or it errorsambiguous_target(adom-desktop targetslists them).
⛔ ALWAYS run the surface in the BACKGROUND
A ralph loop runs for a long time, so it must never steal the user's focus or disturb their main work. Always launch the browser/app surface in the background — never foreground to "look at" your app. Adom engineers have put enormous work into making every web surface fully operable while buried, so background operation is always possible:
- pup — its default launch puts Chrome-for-Testing into a non-occluding background mode: the page keeps painting even when fully covered, so 3D views still render and screen recording runs at full framerate in the background. Open and capture; never raise the window.
- Native Chrome/Edge (
nbrowser_*) — opens windows unfocused by default, andnbrowser_screenshotcaptures an occluded window with zero OS-window interaction. If you need the real browser to keep painting while buried (background 3D / full-fps recording), it can offer a full relaunch of the native browser in non-occlusion "full refresh" mode (the user's profile + logins survive), then offer to revert afterward. - adom-desktop —
desktop_screenshot_windowcaptures a window by hwnd in the background (no foregrounding). It also returns a full ARRAY of screenshots including the window's CHILD windows, so error/dialog boxes — almost always child windows of the parent hwnd — are captured automatically. A ralph loop therefore sees the error popup without hunting for it. - Hydrogen webview (
adom-cli) — captures the user's workspace panels without foregrounding.
Only ever foreground when the user explicitly asks to watch (desktop_bring_to_front).
Window, tab & taskbar etiquette (be a tidy guest)
The loop opens browser surfaces on the user's real machine, so don't clutter or hijack it:
- One window per topic — use TABS for the rest. Keep a pup or native-browser window pinned to a
single topic; when the task spans several pages, open them as tabs in that same window, not a
new window each.
browser_open_tab {sessionId,url}"adds a tab to the same Chrome window … avoids a new taskbar icon" (native:nbrowser_open_tab). Editing five wiki pages? Five tabs in one window, thenbrowser_list_tabs→browser_switch_tab {tabId}(or just screenshot a specifictabId) as you go. One taskbar button, not five. - NEVER take over a window that's open for another reason. Always open your OWN fresh window
(
browser_open_window/nbrowser_open_window). Navigating or reloading a window the user — or another AI thread — already had open yanks their page out from under them; it's the rudest move the loop can make, and the AI drifts into it unless it stops to check first. Open fresh, every time. - Clean up after yourself. When done with a window, close it (
browser_close_window/nbrowser_close_window;close_tabfor stray tabs). Long loops otherwise leave a graveyard of stale pup/native windows cluttering the taskbar — tidy as you go and again at the end. - Use the taskbar FLASH to say "come look," gently. Whenever the loop updates a window during a
ralph test (reloaded the page, applied a fix, grabbed a fresh shot), flash its taskbar icon orange
—
browser_alert_window {sessionId}(native:nbrowser_flash {sessionId}). It does NOT steal foreground; it just glows, so the user thinks "oh, the AI updated that window — I'll peek if I want." That gentle nudge is the whole point: never force a window to the foreground to show progress — that's rude and disruptive.
Step 1 — Load + screenshot the app (pick the surface)
A. Web app in a Hydrogen webview — the default for the user's OWN app
The user's app usually renders right in their Hydrogen workspace.
adom-cli hydrogen screenshot workspace # the whole workspace
adom-cli hydrogen screenshot panel --panel-id <id> # just the app's panel (ids: hydrogen workspace get)
Reload between iterations by reloading the webview — or just save a file if the app hot-reloads.
Pro/con — adom-cli hydrogen screenshots are SMART but Web Hydrogen pays a price. These are the
only smart captures: they target a specific webview / panel / tab (not just an OS window), which
adom-desktop cannot do — it only targets hwnds. The catch is the permission model, and it splits
by environment:
- Web Hydrogen (cloud): the first
adom-cli hydrogen screenshotmakes the user approve the browser's native screen-sharing prompt and pick the window (a one-time browser security gate). That also flips the machine into a screen-share mode like a Google Meet, with side effects the user may not expect during a long loop: displays won't sleep, screensavers won't fire, a laptop panel won't turn off at the hardware level, and (likely) Windows suppresses notifications. - Hydrogen Desktop: does everything Web Hydrogen's smart targeting can (webviews/panels/tabs), but with no permission prompt and none of the Google-Meet side effects — it turns screenshotting (and screen recording) on and off on demand because it never has to ask.
- pup and the native browser (with the extension) also capture with no prompt, but they target a window/page, not a Hydrogen panel.
So for an unattended ralph loop, prefer Hydrogen Desktop / pup / native browser; reach for Web Hydrogen's smart panel targeting knowing it imposes the screen-share mode for the session.
B. Web app in pup (Puppeteer) — fast, scriptable
adom-desktop -t AdomLapper browser_open_window '{"sessionId":"app","profile":"Default","url":"<url>"}'
adom-desktop -t AdomLapper browser_screenshot '{"sessionId":"app","fullPage":true}' # → /tmp/adom-desktop-screenshots
adom-desktop -t AdomLapper browser_reload '{"sessionId":"app"}'
Great for your own apps and open public pages. But pup is an empty controlled-Chromium: more and
more sites detect and block it (e.g. digikey.com), and it's logged in to nothing. When that
bites, jump to C.
C. Web app in the NATIVE browser via the Adom extension — logged-in, undetectable ⭐
When a site blocks pup or needs you logged in, drive the user's real Chrome/Edge with the
nbrowser_* verbs. Real cookies, SSO, saved logins and human-trust all apply, so it sails past the
login walls and captchas that stop pup. This is your best friend for surfing the web (or local apps)
with a full logged-in context.
adom-desktop -t AdomLapper nbrowser_status # confirm connected
adom-desktop -t AdomLapper nbrowser_open_window '{"sessionId":"app","url":"<url>"}' # opens in the BACKGROUND
adom-desktop -t AdomLapper nbrowser_screenshot '{"sessionId":"app","toFile":true}' # → a laptop PNG path
adom-desktop -t AdomLapper pull_file '{"filePaths":["<path>"],"saveTo":"/tmp"}' # bring it into the container
adom-desktop -t AdomLapper nbrowser_reload '{"sessionId":"app"}'
Rules that matter (full reference: the driving-the-extension skill):
- One-time install — AD installs it for you (Step 1.5); it's not there by default.
- Never reuse a window the user is working in — always open a FRESH one, and
nbrowser_close_windowit when done. Yanking their live page is hostile. - Stay in the background — never foreground to grab a shot.
nbrowser_screenshotcaptures an occluded window fine (it reads the page bitmap, no OS-window interaction). - Active clicking/typing makes Chrome show the yellow "Adom… started debugging this browser" bar
(that's CDP).
navigate/reload/screenshotgo through native paths and keep it quiet. - Bonus:
nbrowser_login_state {url}checks if you're signed in now;nbrowser_fetch_urlgrabs a file behind a login using the real cookies — no clicking.
D. Desktop app via an adom-desktop bridge
If the "app" is a desktop program (KiCad, Fusion 360, …), reload the file through its bridge and screenshot the window:
adom-desktop -t AdomLapper desktop_list_windows # find the hwnd
adom-desktop -t AdomLapper desktop_screenshot_window '{"hwnd":<hwnd>}' # any native window
adom-desktop -t AdomLapper kicad_screenshot_all '{}' # or fusion_screenshot_all
"Reload" = re-open / re-load the file in the app (e.g. kicad_open_board again after you edit it).
desktop_screenshot_window captures the window in the background and returns an array that
includes child windows, so a popped-up error/dialog box is captured automatically — exactly what a
ralph loop needs to diagnose a failed reload.
Step 1.5 — Installing the native browser extension (adom-desktop installs it for you)
It isn't there by default, but it largely self-installs — don't just hand the user manual steps.
Your container never talks to the extension directly; it drives adom-desktop (AD) on the laptop and
AD does the setup. First-time flow (the extension page's INSTALL-FLOW.md walks every step):
- Get the skills + mechanics:
adom-wiki skills install adom/adom-browser-extension— installsdriving-the-extension,native-browser-safety,driving-the-desktop, the site recipes, etc. - AD installs the bridge (one call) and registers the tiny native-messaging host on the laptop.
- The extension gets loaded into Chrome/Edge. Chrome 137+ removed
--load-extension, so this is a one-timechrome://extensions → Developer mode → Load unpacked. AD can drive that OS-level flow for the user — the driving-the-desktop skill owns the extension's whole install / uninstall / reload lifecycle with a proven, validated recipe. Production uses a Chrome Web Store force-install. - Confirm:
nbrowser_status→ connected, and the fullnbrowser_*surface (navigate, screenshot, reload, click, type, login_state, fetch_url…) is live.
So install it FOR the user, not at them — only ask them to approve a click when their machine isn't Adom-managed and AD can't complete the OS step silently.
Step 2 — Analyze → fix → reload
- Analyze: read the screenshot. Compare against intent — what's broken, wrong, missing, or ugly.
- Fix: edit the app's source / config / data file (or the desktop file).
- Reload: the matching reload for your surface — reload the Hydrogen webview,
browser_reload,nbrowser_reload, or re-open the desktop file. (Web apps with hot-reload refresh on save.)
Step 3 — shotlog: how you AND the user actually SEE every shot (do NOT skip)
This is the most important habit in the loop, and the AI keeps forgetting it — don't. The Claude Code VS Code extension can't render images inline (Claude Desktop can; the VS Code one still can't), so shotlog is the surface where both you and the user actually look at each screenshot as the loop runs. It is not mainly a phone thing — the phone is ~5% of why it matters.
Two rules, every single iteration:
- Open a shotlog TAB in the topic's browser window — up front. Add the channel's live gallery as a
tab alongside your ralph-test tabs (
browser_open_tab {sessionId,url:"<shotlog gallery url>"}/nbrowser_open_tab) so every new shot appears right next to the app you're debugging. The AI routinely forgets this — make it the first thing you do when a ralph test starts. - Inject EVERY screenshot from EVERY surface. Hydrogen, pup, native browser, desktop window — no
matter where the shot came from, it goes into shotlog immediately:
The gallery live-updates over WebSocket, newest-first, in that tab (and on the phone if the user wants it). Never take a shot that doesn't land in shotlog.shotlog inject -c <channel> -d "iter-<N>-<what-changed>" -s <source> <file.png> # +--orig-w/--orig-h if pre-resized
Running the loop
- Unattended: drive it with the
/loopskill (self-paced). Each pass: screenshot → analyze → fix → reload → screenshot →shotlog inject./loopkeeps the harness + Adom tools live between passes. - Stop when fixed: the loop ends when the screenshot matches intent (the AI judges the shot), or on a manual stop. Always cap iterations so a stubborn fix doesn't spin forever.
Surface cheat-sheet
| App / situation | Load + screenshot | Reload |
|---|---|---|
| User's own web app in their workspace | adom-cli hydrogen screenshot workspace | panel |
reload webview / hot-reload on save |
| Your web app or a public page (no login, allows automation) | pup: browser_open_window → browser_screenshot |
browser_reload |
| Site that blocks pup or needs login (DigiKey, vendor portals) | native: nbrowser_open_window → nbrowser_screenshot + pull_file |
nbrowser_reload |
| Desktop app (KiCad / Fusion / …) | desktop_screenshot_window / kicad_screenshot_all |
re-open the file via its bridge |
Then always finish each iteration with shotlog inject → the shotlog tab in your topic window
(where you and the user both watch — the VS Code extension can't show images inline). Phone is a bonus.
---
name: ralph-loop-test
description: >-
The Adom "ralph test" (Ralph Wiggum loop) — a screenshot-driven fix loop for apps. Point it at the
user's running app (almost always a WEB APP in a webview / pup / the native browser, sometimes a
DESKTOP APP driven via an adom-desktop bridge): load it, screenshot it, feed the shot to the AI, the
AI analyzes what's wrong and fixes it, then reload the page (or reload the file in the desktop app),
screenshot again, and loop until it's right. Covers every Adom screenshot surface — Hydrogen webview
(adom-cli), pup, the native Chrome/Edge extension (nbrowser_*), and desktop bridges — plus the
shotlog viewer workflow (how to actually see shots when the VS Code extension can't show images
inline). Use when the user says "ralph", "ralph test", "ralph wiggum", "ralph loop",
"screenshot loop", "visual fix loop", "loop until it's fixed", "test my app with screenshots", or
"keep screenshotting and fixing until it works".
---
# Ralph Test (Adom) — the screenshot-driven fix loop
In the Adom world a **ralph test** (a Ralph Wiggum loop) is a **visual fix loop**, not a code-build
loop. You point it at the user's *running app* — almost always a **web app** (shown in a Hydrogen
webview, in pup, or in the native Chrome/Edge browser), sometimes a **desktop app driven through an
adom-desktop bridge** — and you grind this cycle:
1. **Load** the app on a surface you can screenshot.
2. **Screenshot** it.
3. **Feed the shot to the AI** → it analyzes what's wrong (broken layout, wrong/missing data, a
console error, off-brand styling, an element that should be there and isn't).
4. **Fix** the cause — edit the app's code / config / data (or the desktop file).
5. **Reload** — reload the page in the browser, or reload the file in the desktop app.
6. **Screenshot again**, and `shotlog inject` it — that's how you *and* the user actually SEE the shot
(the Claude Code VS Code extension can't show images inline).
7. **Loop** — repeat until the screenshot matches intent.
"Ralph" because it's gloriously dumb and persistent: the same *look → fix → reload* cycle, over and
over, until the shot is correct. Memory of what's been tried lives in the **app's own state + the
shotlog history**, not the context window.
## Where you're running
The AI always runs from a **container**, and they all carry the same screenshot tools, so this loop
works identically everywhere:
- **Hydrogen Web** — a Docker cloud container.
- **Hydrogen Desktop** — a WSL2 container (Windows), a Lima container (Mac), or an Ubuntu container
(Ubuntu).
What changes per task is only **which surface** you load the app on. Pick it in Step 1.
> Targeting: `adom-desktop` verbs hit the user's laptop. If more than one desktop is on the relay you
> MUST name one (`-t AdomLapper`) or it errors `ambiguous_target` (`adom-desktop targets` lists them).
---
## ⛔ ALWAYS run the surface in the BACKGROUND
A ralph loop runs for a long time, so it must **never steal the user's focus or disturb their main
work. Always launch the browser/app surface in the background — never foreground to "look at" your
app.** Adom engineers have put enormous work into making every web surface fully operable while buried,
so background operation is always possible:
- **pup** — its default launch puts Chrome-for-Testing into a **non-occluding background mode**: the
page keeps painting even when fully covered, so **3D views still render** and **screen recording runs
at full framerate** in the background. Open and capture; never raise the window.
- **Native Chrome/Edge (`nbrowser_*`)** — opens windows **unfocused** by default, and
`nbrowser_screenshot` captures an **occluded** window with zero OS-window interaction. If you need the
*real* browser to keep painting while buried (background 3D / full-fps recording), it can **offer a
full relaunch of the native browser in non-occlusion "full refresh" mode** (the user's profile +
logins survive), then offer to revert afterward.
- **adom-desktop** — `desktop_screenshot_window` captures a window by **hwnd in the background** (no
foregrounding). It also returns a **full ARRAY of screenshots including the window's CHILD windows**,
so **error/dialog boxes — almost always child windows of the parent hwnd — are captured
automatically.** A ralph loop therefore *sees* the error popup without hunting for it.
- **Hydrogen webview (`adom-cli`)** — captures the user's workspace panels without foregrounding.
Only ever foreground when the **user explicitly asks to watch** (`desktop_bring_to_front`).
---
## Window, tab & taskbar etiquette (be a tidy guest)
The loop opens browser surfaces on the user's real machine, so don't clutter or hijack it:
- **One window per topic — use TABS for the rest.** Keep a pup or native-browser **window pinned to a
single topic**; when the task spans several pages, open them as **tabs in that same window**, not a
new window each. `browser_open_tab {sessionId,url}` "adds a tab to the same Chrome window … avoids a
new taskbar icon" (native: `nbrowser_open_tab`). Editing five wiki pages? Five **tabs in one window**,
then `browser_list_tabs` → `browser_switch_tab {tabId}` (or just screenshot a specific `tabId`) as you
go. One taskbar button, not five.
- **NEVER take over a window that's open for another reason.** Always open your OWN fresh window
(`browser_open_window` / `nbrowser_open_window`). Navigating or reloading a window the user — or
another AI thread — already had open yanks their page out from under them; it's the rudest move the
loop can make, and the AI **drifts into it unless it stops to check first**. Open fresh, every time.
- **Clean up after yourself.** When done with a window, **close it** (`browser_close_window` /
`nbrowser_close_window`; `close_tab` for stray tabs). Long loops otherwise leave a graveyard of stale
pup/native windows cluttering the taskbar — tidy as you go and again at the end.
- **Use the taskbar FLASH to say "come look," gently.** Whenever the loop updates a window during a
ralph test (reloaded the page, applied a fix, grabbed a fresh shot), **flash its taskbar icon orange**
— `browser_alert_window {sessionId}` (native: `nbrowser_flash {sessionId}`). It does **NOT** steal
foreground; it just glows, so the user thinks *"oh, the AI updated that window — I'll peek if I want."*
That gentle nudge is the whole point: **never force a window to the foreground** to show progress —
that's rude and disruptive.
---
## Step 1 — Load + screenshot the app (pick the surface)
### A. Web app in a Hydrogen webview — the default for the user's OWN app
The user's app usually renders right in their Hydrogen workspace.
```bash
adom-cli hydrogen screenshot workspace # the whole workspace
adom-cli hydrogen screenshot panel --panel-id <id> # just the app's panel (ids: hydrogen workspace get)
```
Reload between iterations by reloading the webview — or just save a file if the app hot-reloads.
**Pro/con — `adom-cli` hydrogen screenshots are SMART but Web Hydrogen pays a price.** These are the
only **smart** captures: they target a specific **webview / panel / tab** (not just an OS window), which
`adom-desktop` cannot do — it only targets **hwnds**. The catch is the permission model, and it splits
by environment:
- **Web Hydrogen (cloud):** the first `adom-cli hydrogen screenshot` makes the user approve the
browser's native **screen-sharing prompt and pick the window** (a one-time browser security gate).
That also flips the machine into a **screen-share mode like a Google Meet**, with side effects the
user may not expect during a long loop: **displays won't sleep**, **screensavers won't fire**, a
**laptop panel won't turn off at the hardware level**, and (likely) **Windows suppresses
notifications**.
- **Hydrogen Desktop:** does **everything Web Hydrogen's smart targeting can** (webviews/panels/tabs),
but with **no permission prompt and none of the Google-Meet side effects** — it turns screenshotting
(and **screen recording**) **on and off on demand** because it never has to ask.
- **pup** and the **native browser** (with the extension) also capture with **no prompt**, but they
target a window/page, not a Hydrogen panel.
So for an unattended ralph loop, prefer **Hydrogen Desktop / pup / native browser**; reach for **Web
Hydrogen's** smart panel targeting knowing it imposes the screen-share mode for the session.
### B. Web app in pup (Puppeteer) — fast, scriptable
```bash
adom-desktop -t AdomLapper browser_open_window '{"sessionId":"app","profile":"Default","url":"<url>"}'
adom-desktop -t AdomLapper browser_screenshot '{"sessionId":"app","fullPage":true}' # → /tmp/adom-desktop-screenshots
adom-desktop -t AdomLapper browser_reload '{"sessionId":"app"}'
```
Great for your own apps and open public pages. **But** pup is an empty controlled-Chromium: more and
more sites **detect and block it** (e.g. `digikey.com`), and it's **logged in to nothing**. When that
bites, jump to C.
### C. Web app in the NATIVE browser via the Adom extension — logged-in, undetectable ⭐
When a site **blocks pup** or **needs you logged in**, drive the user's **real Chrome/Edge** with the
`nbrowser_*` verbs. Real cookies, SSO, saved logins and human-trust all apply, so it sails past the
login walls and captchas that stop pup. This is your best friend for surfing the web (or local apps)
with a full logged-in context.
```bash
adom-desktop -t AdomLapper nbrowser_status # confirm connected
adom-desktop -t AdomLapper nbrowser_open_window '{"sessionId":"app","url":"<url>"}' # opens in the BACKGROUND
adom-desktop -t AdomLapper nbrowser_screenshot '{"sessionId":"app","toFile":true}' # → a laptop PNG path
adom-desktop -t AdomLapper pull_file '{"filePaths":["<path>"],"saveTo":"/tmp"}' # bring it into the container
adom-desktop -t AdomLapper nbrowser_reload '{"sessionId":"app"}'
```
Rules that matter (full reference: the **driving-the-extension** skill):
- **One-time install — AD installs it for you** (Step 1.5); it's not there by default.
- **Never reuse a window the user is working in — always open a FRESH one**, and `nbrowser_close_window`
it when done. Yanking their live page is hostile.
- **Stay in the background — never foreground to grab a shot.** `nbrowser_screenshot` captures an
occluded window fine (it reads the page bitmap, no OS-window interaction).
- Active clicking/typing makes Chrome show the yellow *"Adom… started debugging this browser"* bar
(that's CDP). `navigate` / `reload` / `screenshot` go through native paths and keep it quiet.
- Bonus: `nbrowser_login_state {url}` checks if you're signed in now; `nbrowser_fetch_url` grabs a file
behind a login using the real cookies — no clicking.
### D. Desktop app via an adom-desktop bridge
If the "app" is a desktop program (KiCad, Fusion 360, …), reload the file through its bridge and
screenshot the window:
```bash
adom-desktop -t AdomLapper desktop_list_windows # find the hwnd
adom-desktop -t AdomLapper desktop_screenshot_window '{"hwnd":<hwnd>}' # any native window
adom-desktop -t AdomLapper kicad_screenshot_all '{}' # or fusion_screenshot_all
```
"Reload" = re-open / re-load the file in the app (e.g. `kicad_open_board` again after you edit it).
`desktop_screenshot_window` captures the window **in the background** and returns an **array that
includes child windows**, so a popped-up **error/dialog box is captured automatically** — exactly what a
ralph loop needs to diagnose a failed reload.
## Step 1.5 — Installing the native browser extension (adom-desktop installs it for you)
It isn't there by default, but **it largely self-installs — don't just hand the user manual steps.**
Your container never talks to the extension directly; it drives **adom-desktop (AD)** on the laptop and
AD does the setup. First-time flow (the extension page's `INSTALL-FLOW.md` walks every step):
1. **Get the skills + mechanics:** `adom-wiki skills install adom/adom-browser-extension` — installs
`driving-the-extension`, `native-browser-safety`, `driving-the-desktop`, the site recipes, etc.
2. **AD installs the bridge** (one call) and registers the tiny **native-messaging host** on the laptop.
3. **The extension gets loaded into Chrome/Edge.** Chrome 137+ removed `--load-extension`, so this is a
one-time `chrome://extensions → Developer mode → Load unpacked`. **AD can drive that OS-level flow for
the user** — the **driving-the-desktop** skill owns the extension's whole install / uninstall / reload
lifecycle with a proven, validated recipe. Production uses a Chrome Web Store force-install.
4. **Confirm:** `nbrowser_status` → connected, and the full `nbrowser_*` surface (navigate, screenshot,
reload, click, type, login_state, fetch_url…) is live.
So **install it FOR the user, not at them** — only ask them to approve a click when their machine isn't
Adom-managed and AD can't complete the OS step silently.
## Step 2 — Analyze → fix → reload
- **Analyze:** read the screenshot. Compare against intent — what's broken, wrong, missing, or ugly.
- **Fix:** edit the app's source / config / data file (or the desktop file).
- **Reload:** the matching reload for your surface — reload the Hydrogen webview, `browser_reload`,
`nbrowser_reload`, or re-open the desktop file. (Web apps with hot-reload refresh on save.)
## Step 3 — shotlog: how you AND the user actually SEE every shot (do NOT skip)
**This is the most important habit in the loop, and the AI keeps forgetting it — don't.** The Claude
Code **VS Code extension can't render images inline** (Claude Desktop can; the VS Code one still
can't), so shotlog is the surface where **both you and the user actually look at each screenshot as the
loop runs.** It is *not* mainly a phone thing — the phone is ~5% of why it matters.
Two rules, every single iteration:
1. **Open a shotlog TAB in the topic's browser window — up front.** Add the channel's live gallery as a
tab alongside your ralph-test tabs (`browser_open_tab {sessionId,url:"<shotlog gallery url>"}` /
`nbrowser_open_tab`) so every new shot appears right next to the app you're debugging. The AI
routinely forgets this — make it the **first** thing you do when a ralph test starts.
2. **Inject EVERY screenshot from EVERY surface.** Hydrogen, pup, native browser, desktop window — no
matter where the shot came from, it goes into shotlog immediately:
```bash
shotlog inject -c <channel> -d "iter-<N>-<what-changed>" -s <source> <file.png> # +--orig-w/--orig-h if pre-resized
```
The gallery live-updates over WebSocket, newest-first, in that tab (and on the phone if the user
wants it). **Never take a shot that doesn't land in shotlog.**
## Running the loop
- **Unattended:** drive it with the `/loop` skill (self-paced). Each pass: screenshot → analyze → fix →
reload → screenshot → `shotlog inject`. `/loop` keeps the harness + Adom tools live between passes.
- **Stop when fixed:** the loop ends when the screenshot matches intent (the AI judges the shot), or on
a manual stop. **Always cap iterations** so a stubborn fix doesn't spin forever.
## Surface cheat-sheet
| App / situation | Load + screenshot | Reload |
| --- | --- | --- |
| User's own web app in their workspace | `adom-cli hydrogen screenshot workspace \| panel` | reload webview / hot-reload on save |
| Your web app or a public page (no login, allows automation) | pup: `browser_open_window` → `browser_screenshot` | `browser_reload` |
| Site that blocks pup or needs login (DigiKey, vendor portals) | native: `nbrowser_open_window` → `nbrowser_screenshot` + `pull_file` | `nbrowser_reload` |
| Desktop app (KiCad / Fusion / …) | `desktop_screenshot_window` / `kicad_screenshot_all` | re-open the file via its bridge |
Then **always** finish each iteration with `shotlog inject` → the **shotlog tab in your topic window**
(where you and the user both watch — the VS Code extension can't show images inline). Phone is a bonus.