Skip to content
Development
Skill

/debug-ui

Drive and visually QA the dev-3.0 UI in a real browser (headless Chromium via agent-browser). Use when verifying a UI/UX change, reproducing a visual bug, taking screenshots of the running app, or self-QA before review. Triggers — "check the UI", "screenshot the app", "does this

From plugin
dev-30
2594 skills
Install
$ npx -y skills add h0x91b/dev-3.0 --skill debug-ui --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/debug-ui

Context preview

The summary Claude sees to decide when to auto-load this skill.

Drive and visually QA the dev-3.0 UI in a real browser (headless Chromium via agent-browser). Use when verifying a UI/UX change, reproducing a visual bug, taking screenshots of the running app, or self-QA before review. Triggers — "check the UI", "screenshot the app", "does this

SKILL.md

debug-ui.SKILL.md
name: debug-ui
description: Drive and visually QA the dev-3.0 UI in a real browser (headless Chromium via agent-browser). Use when verifying a UI/UX change, reproducing a visual bug, taking screenshots of the running app, or self-QA before review. Triggers — "check the UI", "screenshot the app", "does this render", "QA this screen", "verify the UI change in a browser", "drive the app".

debug-ui — QA the dev-3.0 UI in a real browser

See and drive the running dev-3.0 UI in headless Chromium — click, type, screenshot, read console errors — instead of guessing whether a UI change works. No desktop/native dependency; it works the same in a plain terminal session.

This is **dev-internal tooling for the dev-3.0 repo** — NOT one of the skills dev3 ships to its users (those live in `src/bun/agent-skills.ts`).

One rule before the flow: the app starts through `dev3 dev-server`, nothing else

Every QA run in this skill boots the app with `dev3 dev-server start` and takes it down with `dev3 dev-server stop`. **Never start the app any other way** — not a bare `bun run dev`, not `bun run dev --qa`, and not `dev3 pane run "bun run dev …"`. A pane run looks like a shortcut and costs you everything the dev-server owns: the port wait (`--wait`), `status` with its port conflicts, a verified stop that frees `DEV3_PORT0`, the Dev Server button in the task UI that shows the user what is running, and the `show-image` / `attention` routing rules below. If you need the app to behave differently (a throwaway board, an env flag), change what the dev-server runs — see "Scoped QA" — do not route around it.

The whole flow

This task's dev-server **is** the web UI: `bun run dev` serves the full app in local remote mode at a stable per-machine token and a CLI-derivable port — no separate `dev3 remote`. The loop is always the same four beats: **values → server → browser → clean up.**

# 1. Values. AGENT_BROWSER_SESSION isolates THIS task's browser from every other agent's —
#    without it all agents share one global "default" session and stomp each other (see
#    Gotchas). Derived from the always-present $DEV3_TASK_ID, so this exact line is
#    copy-paste-safe at the top of ANY block that calls agent-browser.
export AGENT_BROWSER_SESSION="dev3-${DEV3_TASK_ID%%-*}"
CODE=$(cat "$HOME/.dev3.0/dev-web-access-code" 2>/dev/null || bun scripts/dev-web-code.ts)
PORT=${DEV3_PORT0:-$(dev3 dev-server status | grep -oE 'DEV3_PORT0=[0-9]+' | cut -d= -f2)}

# 2. Start a FRESH dev-server and wait for it to come up. (Skip the start only if one is
#    already running for THIS task — but see the build-snapshot gotcha: stale code needs a
#    restart, so when in doubt restart.)
dev3 dev-server start
until curl -sf "http://localhost:$PORT/?token=$CODE" >/dev/null; do sleep 2; done

# 3. Drive it. Every agent-browser call inherits AGENT_BROWSER_SESSION, so it all runs in
#    this task's own session. (Load /agent-browser for the full command set.) The screenshot
#    path is task-scoped too, so parallel agents never overwrite each other's PNG.
#    `&streamer=on` is MANDATORY: it enables streamer mode (privacy masking), so screenshots
#    can't leak the developer's real emails/accounts/paths/tunnel URLs (see Gotchas).
#    Keep `set viewport` BEFORE `open`, and keep the width ≥ 1024 for desktop QA — the app's
#    mobile gate reads `screen.width` (see Gotchas).
agent-browser set viewport 1440 900
agent-browser open "http://localhost:$PORT/?token=$CODE&streamer=on"
agent-browser wait --load networkidle
sleep 2                                       # networkidle can still land mid-render — let it settle
agent-browser snapshot -i -d 6                # prove it's DRIVABLE, not just screenshot-able
agent-browser screenshot "/tmp/dev3-ui-${DEV3_TASK_ID%%-*}.png"   # then Read it back to look
agent-browser errors                          # confirm no console errors

# 4. Always clean up what you started. `close` closes only THIS session's browser.
agent-browser close
dev3 dev-server stop          # the port frees a second or two later (graceful shutdown)

That's it. `DEV3_REMOTE_PORT=${DEV3_PORT0:-0}` is wired into the repo's `dev` script and `portCount: 1` is committed in `.dev3/config.json`, so the dev app binds the exact port shown above (see [decision 093](../../../decisions/2026/06/30/dev-remote-port-from-pool.md)).

Scoped QA: a throwaway board instead of the real one

`dev3 dev-server start` boots a full dev3 instance on **your real board** — another task's "Branch Merged — mark completed?" dialog is live and clickable in your browser, and another task's terminal is reachable by navigation. It stays the default anyway, because it is the build the user runs; reach for the scoped board when the QA would touch real tasks, real accounts, or a live dialog — creating or launching a task from the New Task dialog counts.

The switch is an env var the `dev` script reads (`DEV3_QA_SCOPE`, see `scripts/dev.ts` and `scripts/qa-scope.ts`), and the dev-server passes caller-supplied variables straight through. So the scoped board is **the same dev-server**, one flag longer:

dev3 dev-server start --wait --env DEV3_QA_SCOPE=seeded    # or virgin

`seeded` = one fixture project, zero tasks; `virgin` = completely empty home, the first-run state. Steps 1, 3 and 4 of the flow above are unchanged — same port, same access code, same `stop`. The dev-server pane prints the scoped `DEV3_HOME` and an `rm -rf` reset line; the scoped root is stable per worktree, so the board survives a restart.

Three things worth knowing about the flag:

  • **A plain `dev3 dev-server restart` stays on the scoped board** — a restart with no `--env`

reuses the last start's env, which is also what the Dev Server button in the task UI does.

  • **A plain `dev3 dev-server start` goes back to the real board.** A start defines its

configuration whole, and a `stop` clears the remembered env — so there is nothing to delete and nothing lef

Read more
Ships withdev-30

Mission control for the One Person Studio — run a fleet of AI coding agents in parallel without losing your mind. Kanban + git worktrees + tmux for Claude Code, Codex, Gemini CLI, OpenCode and any shell agent. Not an IDE.

Get the whole plugin
Stats
260
Stars
34
Forks
Active
Maintenance
TypeScript
Language
Apache-2.0
License
6h ago
Last commit
6mo ago
Created

Repo: h0x91b/dev-3.0

Other skills on dev-30.