Control UI
Use local browser automation to verify UI behavior with evidence. First reuse the repo's own Playwright, browser, or Electron harness if it exists; otherwise assemble a temporary local harness around the app's dev server or Chromium debug port.
What It Is Used For
- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering.
- Verifying visual or accessibility changes with screenshots and snapshots.
- Checking local web, IDE, or Electron behavior before shipping.
- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots.
- Creating before/after evidence for
verify-this.
Setup Pattern
- Start the app locally using the repo's documented dev command.
- Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools.
- For a web app, connect to the local URL with the existing browser tooling.
- For Electron/Chromium, enable a remote debugging port when supported.
- Select the correct page by stable app markers, not by tab order alone.
- Prefer accessibility roles, labels, and stable
data-* selectors over coordinates.
Generic Web Harness
Use the repo's installed browser tooling when possible. If the repo already has Playwright, a minimal one-off probe looks like:
import { chromium } from "playwright";
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto("http://127.0.0.1:<port>");
await page.getByRole("button", { name: /submit/i }).click();
await page.screenshot({ path: "/tmp/ui-harness-after.png", fullPage: true });
await browser.close();
Do not add Playwright as a project dependency just for this probe unless the user asks. Prefer existing dev dependencies or external browser tools already available in the environment.
Generic CDP Harness
For Electron or a Chromium app launched with --remote-debugging-port=<port>, connect over CDP:
import { chromium } from "playwright";
const browser = await chromium.connectOverCDP("http://127.0.0.1:<debug-port>");
const pages = browser.contexts().flatMap((context) => context.pages());
let page;
for (const candidate of pages) {
if (await candidate.locator("<app-root-selector>").count()) {
page = candidate;
break;
}
}
if (!page) {
console.log(
await Promise.all(
pages.map(async (p) => ({
title: await p.title(),
url: p.url(),
})),
),
);
throw new Error("No matching app page found");
}
await page.screenshot({ path: "/tmp/ui-harness-cdp.png", fullPage: true });
await browser.close();
Replace <app-root-selector> with a stable marker from the current repo, such as a root app node, landmark, or product-specific data-* attribute.
Interaction Loop
- Capture a page snapshot or screenshot before acting.
- Choose a target from the latest page structure.
- Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize.
- Capture a fresh snapshot/screenshot.
- Verify the expected state change.
- Save artifacts for before/after comparisons when the user asked for proof.
CDP Capabilities
Use raw CDP only when higher-level browser APIs are insufficient:
- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection.
- Memory: heap snapshots and forced GC for leak investigations.
- Network: request blocking, throttling, cache disablement, request/response logs.
- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks.
- Debugging: console streaming, exception capture, DOM snapshots.
Page Selection
When multiple app windows/tabs share a debug port:
- Prefer a positive marker for the surface under test, such as an app root selector.
- Use a negative marker to avoid the wrong surface when necessary.
- If no page matches, list available page titles and URLs instead of guessing.
Guardrails
- Do not rely on stale element references after navigation or structural changes.
- Avoid coordinate clicks unless a fresh screenshot was captured immediately before the click.
- Keep test data local and disposable.
- Do not store screenshots or heap snapshots from privacy-sensitive workspaces unless the user explicitly agrees.
- Do not hard-code selectors, ports, or script paths from another repository. Discover the current repo's local app markers.
- Clean up dev servers, debug sessions, and temp profiles when done.
1---2name: control-ui3description: Build or adapt a local browser/CDP harness to drive and inspect a web, IDE, or Electron UI. Use for local UI verification, screenshots, accessibility snapshots, perf profiles, visual diffs, or reproducing UI bugs.4---56# Control UI78Use local browser automation to verify UI behavior with evidence. First reuse the repo's own Playwright, browser, or Electron harness if it exists; otherwise assemble a temporary local harness around the app's dev server or Chromium debug port.910## What It Is Used For1112- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering.13- Verifying visual or accessibility changes with screenshots and snapshots.14- Checking local web, IDE, or Electron behavior before shipping.15- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots.16- Creating before/after evidence for `verify-this`.1718## Setup Pattern19201. Start the app locally using the repo's documented dev command.212. Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools.223. For a web app, connect to the local URL with the existing browser tooling.234. For Electron/Chromium, enable a remote debugging port when supported.245. Select the correct page by stable app markers, not by tab order alone.256. Prefer accessibility roles, labels, and stable `data-*` selectors over coordinates.2627## Generic Web Harness2829Use the repo's installed browser tooling when possible. If the repo already has Playwright, a minimal one-off probe looks like:3031```javascript32import { chromium } from "playwright";3334const browser = await chromium.launch();35const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });36await page.goto("http://127.0.0.1:<port>");37await page.getByRole("button", { name: /submit/i }).click();38await page.screenshot({ path: "/tmp/ui-harness-after.png", fullPage: true });39await browser.close();40```4142Do not add Playwright as a project dependency just for this probe unless the user asks. Prefer existing dev dependencies or external browser tools already available in the environment.4344## Generic CDP Harness4546For Electron or a Chromium app launched with `--remote-debugging-port=<port>`, connect over CDP:4748```javascript49import { chromium } from "playwright";5051const browser = await chromium.connectOverCDP("http://127.0.0.1:<debug-port>");52const pages = browser.contexts().flatMap((context) => context.pages());53let page;54for (const candidate of pages) {55 if (await candidate.locator("<app-root-selector>").count()) {56 page = candidate;57 break;58 }59}6061if (!page) {62 console.log(63 await Promise.all(64 pages.map(async (p) => ({65 title: await p.title(),66 url: p.url(),67 })),68 ),69 );70 throw new Error("No matching app page found");71}7273await page.screenshot({ path: "/tmp/ui-harness-cdp.png", fullPage: true });74await browser.close();75```7677Replace `<app-root-selector>` with a stable marker from the current repo, such as a root app node, landmark, or product-specific `data-*` attribute.7879## Interaction Loop80811. Capture a page snapshot or screenshot before acting.822. Choose a target from the latest page structure.833. Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize.844. Capture a fresh snapshot/screenshot.855. Verify the expected state change.866. Save artifacts for before/after comparisons when the user asked for proof.8788## CDP Capabilities8990Use raw CDP only when higher-level browser APIs are insufficient:9192- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection.93- Memory: heap snapshots and forced GC for leak investigations.94- Network: request blocking, throttling, cache disablement, request/response logs.95- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks.96- Debugging: console streaming, exception capture, DOM snapshots.9798## Page Selection99100When multiple app windows/tabs share a debug port:101102- Prefer a positive marker for the surface under test, such as an app root selector.103- Use a negative marker to avoid the wrong surface when necessary.104- If no page matches, list available page titles and URLs instead of guessing.105106## Guardrails107108- Do not rely on stale element references after navigation or structural changes.109- Avoid coordinate clicks unless a fresh screenshot was captured immediately before the click.110- Keep test data local and disposable.111- Do not store screenshots or heap snapshots from privacy-sensitive workspaces unless the user explicitly agrees.112- Do not hard-code selectors, ports, or script paths from another repository. Discover the current repo's local app markers.113- Clean up dev servers, debug sessions, and temp profiles when done.