control-ui

A preserved method from https://github.com/cursor/plugins at f5bdd6826fd0, path cursor-team-kit/skills/control-ui, MIT. 20 of 109 source lines differ (18%), every difference claimed by an entry of the ledger with its reason. Entries: baseline-copies-2026-09-11, pull-2026-09-11, fold-2026-09-11, roster-keepers-2026-09-15, roster-keepers-fix-2026-09-15.

  • harness 1
  • lifecycle 2
  • location 4

Files

Every difference, as it stands

SKILL.md

---
---
harnesschangedbaseline-copies-2026-09-11

greenline renders its own frontmatter: quoted name and description, the description from the manifest override where one existed, no upstream activation flag

name: control-ui
name: "control-ui"
description: 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.
description: "Build or adapt a local browser harness to drive and inspect a web, IDE, or Electron UI. Use to click through the app, check it in the browser, take screenshots or accessibility snapshots, capture perf profiles, or reproduce a UI bug."
---
---
 
 
# Control UI
# Control UI
 
 
lifecyclechangedroster-keepers-fix-2026-09-15

the opening paragraph and the Handoff name the same three dispatchers, verify-this, diagnosing-bugs and product-description, and the stages the capture returns to, so the chain closes; carried from roster-keepers-2026-09-15 (J-8's fix, 2026-09-15)

verify-this, diagnosing-bugs or product-description dispatches this method when its verdict needs a screenshot, an accessibility snapshot, a trace or a profile; the capture goes back to that stage as evidence, and the verdict stays there. Reuse an existing local UI harness before assembling one. Screenshots and traces support a verdict; they do not decide it.
 
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.
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
## What It Is Used For
24 unchanged lines
 
 
- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering.
- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering.
- Verifying visual or accessibility changes with screenshots and snapshots.
- Verifying visual or accessibility changes with screenshots and snapshots.
- Checking local web, IDE, or Electron behavior before shipping.
- Checking local web, IDE, or Electron behavior before shipping.
- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots.
- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots.
- Creating before/after evidence for `verify-this`.
- Creating before/after evidence for `verify-this`.
 
 
## Setup Pattern
## Setup Pattern
 
 
1. Start the app locally using the repo's documented dev command.
1. Start the app locally using the repo's documented dev command.
2. Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools.
2. Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools.
3. For a web app, connect to the local URL with the existing browser tooling.
3. For a web app, connect to the local URL with the existing browser tooling.
4. For Electron/Chromium, enable a remote debugging port when supported.
4. For Electron/Chromium, enable a remote debugging port when supported.
5. Select the correct page by stable app markers, not by tab order alone.
5. Select the correct page by stable app markers, not by tab order alone.
6. Prefer accessibility roles, labels, and stable `data-*` selectors over coordinates.
6. Prefer accessibility roles, labels, and stable `data-*` selectors over coordinates.
 
 
## Generic Web Harness
## 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:
Use the repo's installed browser tooling when possible. If the repo already has Playwright, a minimal one-off probe looks like:
 
 
```javascript
```javascript
import { chromium } from "playwright";
import { chromium } from "playwright";
 
 
const browser = await chromium.launch();
const browser = await chromium.launch();
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
const page = await browser.newPage({ viewport: { width: 1280, height: 800 } });
await page.goto("http://127.0.0.1:<port>");
await page.goto("http://127.0.0.1:<port>");
await page.getByRole("button", { name: /submit/i }).click();
await page.getByRole("button", { name: /submit/i }).click();
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

await page.screenshot({ path: "/tmp/ui-harness-after.png", fullPage: true });
await page.screenshot({ path: ".greenline/tmp/control-ui/ui-harness-after.png", fullPage: true });
await browser.close();
await browser.close();
```
```
 
 
24 unchanged lines
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.
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
## Generic CDP Harness
 
 
For Electron or a Chromium app launched with `--remote-debugging-port=<port>`, connect over CDP:
For Electron or a Chromium app launched with `--remote-debugging-port=<port>`, connect over CDP:
 
 
```javascript
```javascript
import { chromium } from "playwright";
import { chromium } from "playwright";
 
 
const browser = await chromium.connectOverCDP("http://127.0.0.1:<debug-port>");
const browser = await chromium.connectOverCDP("http://127.0.0.1:<debug-port>");
const pages = browser.contexts().flatMap((context) => context.pages());
const pages = browser.contexts().flatMap((context) => context.pages());
let page;
let page;
for (const candidate of pages) {
for (const candidate of pages) {
if (await candidate.locator("<app-root-selector>").count()) {
if (await candidate.locator("<app-root-selector>").count()) {
page = candidate;
page = candidate;
break;
break;
}
}
}
}
 
 
if (!page) {
if (!page) {
console.log(await Promise.all(pages.map(async (p) => ({
console.log(await Promise.all(pages.map(async (p) => ({
title: await p.title(),
title: await p.title(),
url: p.url(),
url: p.url(),
}))));
}))));
throw new Error("No matching app page found");
throw new Error("No matching app page found");
}
}
 
 
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

await page.screenshot({ path: "/tmp/ui-harness-cdp.png", fullPage: true });
await page.screenshot({ path: ".greenline/tmp/control-ui/ui-harness-cdp.png", fullPage: true });
await browser.close();
await browser.close();
```
```
 
 
6 unchanged lines
Replace `<app-root-selector>` with a stable marker from the current repo, such as a root app node, landmark, or product-specific `data-*` attribute.
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
## Interaction Loop
 
 
1. Capture a page snapshot or screenshot before acting.
1. Capture a page snapshot or screenshot before acting.
2. Choose a target from the latest page structure.
2. Choose a target from the latest page structure.
3. Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize.
3. Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize.
4. Capture a fresh snapshot/screenshot.
4. Capture a fresh snapshot/screenshot.
5. Verify the expected state change.
5. Verify the expected state change.
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

6. Save artifacts for before/after comparisons when the user asked for proof.
6. Save artifacts under `.greenline/tmp/control-ui/` for before/after comparisons when the user asked for proof, and promote the ones the requesting verdict relies on to the owner's evidence home.
 
 
## CDP Capabilities
## CDP Capabilities
 
 
20 unchanged lines
Use raw CDP only when higher-level browser APIs are insufficient:
Use raw CDP only when higher-level browser APIs are insufficient:
 
 
- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection.
- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection.
- Memory: heap snapshots and forced GC for leak investigations.
- Memory: heap snapshots and forced GC for leak investigations.
- Network: request blocking, throttling, cache disablement, request/response logs.
- Network: request blocking, throttling, cache disablement, request/response logs.
- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks.
- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks.
- Debugging: console streaming, exception capture, DOM snapshots.
- Debugging: console streaming, exception capture, DOM snapshots.
 
 
## Page Selection
## Page Selection
 
 
When multiple app windows/tabs share a debug port:
When multiple app windows/tabs share a debug port:
 
 
- Prefer a positive marker for the surface under test, such as an app root selector.
- 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.
- Use a negative marker to avoid the wrong surface when necessary.
- If no page matches, list available page titles and URLs instead of guessing.
- If no page matches, list available page titles and URLs instead of guessing.
 
 
## Guardrails
## Guardrails
 
 
- Do not rely on stale element references after navigation or structural changes.
- 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.
- Avoid coordinate clicks unless a fresh screenshot was captured immediately before the click.
- Keep test data local and disposable.
- Keep test data local and disposable.
- Do not store screenshots or heap snapshots from privacy-sensitive workspaces unless the user explicitly agrees.
- 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.
- Do not hard-code selectors, ports, or script paths from another repository. Discover the current repo's local app markers.
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

- Keep a new disposable instrument and its captures in `.greenline/tmp/control-ui/`. That directory is not durable proof: promote a relied-on capture and its instrument to the owner's evidence home before closing. A read-only request keeps them outside the repository.
- Clean up dev servers, debug sessions, and temp profiles when done.
- Clean up dev servers, debug sessions, and temp profiles when done.
lifecyclechangedroster-keepers-2026-09-15

The Handoff section names what this support skill consumes, the evidence it produces, its scratch and promoted homes, and the stages it returns to, product-description among them since it dispatches the verification pass, so the chain closes; carried from fold-2026-09-11 (J-8, 2026-09-15)

 
## Handoff
 
Consumes: the surface under test and the question the requesting stage needs answered
Produces: screenshots, snapshots, logs, traces or profiles with the instrument that made them, as evidence for the requester's verdict
Evidence at: .greenline/tmp/control-ui/, promoted to .greenline/work/evidence/<work-id>/ or .greenline/ledger/evidence/<contribution>/ when the result relies on it
Returns to: verify-this, diagnosing-bugs or product-description

The timeline

Each entry that touched this method, with the differences it claimed as they stood at its commit, read from the repository's history.

2026-09-11 baseline-copies-2026-09-11

the cutover to an edited copy (ADR 0039): the composed output written as the copy, every difference from upstream claimed with the reason of the overlay that produced it

SKILL.md

harnesschangedbaseline-copies-2026-09-11

greenline renders its own frontmatter: quoted name and description, the description from the manifest override where one existed, no upstream activation flag

name: control-ui
name: "control-ui"
description: 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.
description: "Build or adapt a local browser harness to drive and inspect a web, IDE, or Electron UI. Use to click through the app, check it in the browser, take screenshots or accessibility snapshots, capture perf profiles, or reproduce a UI bug."
lifecyclechangedbaseline-copies-2026-09-11

greenline prelude, to fold: screenshots and traces under .greenline/tmp/control-ui/ instead of /tmp; browser and privacy rules untouched

**greenline prelude: scoped UI capture.** Reuse an existing local UI harness.
For an authorized workspace write, replace the samples' `/tmp/ui-harness-after.png`
and `/tmp/ui-harness-cdp.png` paths with files under `.greenline/tmp/control-ui/`;
put a new disposable instrument there too. A read-only request uses external
temporary paths instead. Promote relied-on captures and their instruments to
the owner's evidence home before closing. These replacements change storage
locations, not the browser interaction or privacy rules below.
 
lifecyclechangedbaseline-copies-2026-09-11

greenline completion, to fold: captures support a verdict, they do not decide it; retain them in the owner's evidence home

 
 
## greenline completion: the screenshot is evidence
 
Screenshots, accessibility snapshots, traces, and profiles support the requesting diagnosis or verification; they do not decide its verdict. Retain relied-on instruments and results in the owner's evidence home through the common work and ledger contracts. Disposable probes can use `.greenline/tmp/control-ui/` during authorized writes; a read-only task keeps capture outside the repository. Respect the task's data boundaries and return the evidence to the requesting method.

2026-09-11 pull-2026-09-11

pin advance to f5bdd68: upstream moved with no change under the vendored paths

2026-09-11 fold-2026-09-11

The prelude and completion are folded into the body: the scope opens the method, the sample screenshot paths and the save step name greenline's scratch home with promotion, a guardrail states the home once, and a Handoff section returns the captures as evidence to the requesting stage.

SKILL.md

scopechangedfold-2026-09-11

The skill's scope opens the body in its own voice: verify-this or diagnosing-bugs dispatches it when a verdict needs a screenshot, snapshot, trace or profile, the capture returns as evidence while the verdict stays with the requester, and an existing local harness comes first.

verify-this or diagnosing-bugs dispatches this method when its verdict needs a screenshot, an accessibility snapshot, a trace or a profile; the capture goes back to that stage as evidence, and the verdict stays there. Reuse an existing local UI harness before assembling one. Screenshots and traces support a verdict; they do not decide it.
 
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

await page.screenshot({ path: "/tmp/ui-harness-after.png", fullPage: true });
await page.screenshot({ path: ".greenline/tmp/control-ui/ui-harness-after.png", fullPage: true });
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

await page.screenshot({ path: "/tmp/ui-harness-cdp.png", fullPage: true });
await page.screenshot({ path: ".greenline/tmp/control-ui/ui-harness-cdp.png", fullPage: true });
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

6. Save artifacts for before/after comparisons when the user asked for proof.
6. Save artifacts under `.greenline/tmp/control-ui/` for before/after comparisons when the user asked for proof, and promote the ones the requesting verdict relies on to the owner's evidence home.
locationchangedfold-2026-09-11

Upstream's /tmp screenshot paths become greenline's scratch home in place: the two sample probes write under .greenline/tmp/control-ui/, the interaction loop saves before/after artifacts there, and one guardrail states that a new disposable instrument and its captures live there, are promoted to the owner's evidence home when the requesting verdict relies on them, and stay outside the repository for a read-only request; browser interaction and privacy rules are untouched.

- Keep a new disposable instrument and its captures in `.greenline/tmp/control-ui/`. That directory is not durable proof: promote a relied-on capture and its instrument to the owner's evidence home before closing. A read-only request keeps them outside the repository.
lifecyclechangedfold-2026-09-11

The Handoff section (ADR 0039) names what this support skill consumes, the evidence it produces, its scratch and promoted homes, and the stages it returns to, so the chain closes.

 
## Handoff
 
Consumes: the surface under test and the question the requesting stage needs answered
Produces: screenshots, snapshots, logs, traces or profiles with the instrument that made them, as evidence for the requester's verdict
Evidence at: .greenline/tmp/control-ui/, promoted to .greenline/work/evidence/<work-id>/ or .greenline/ledger/evidence/<contribution>/ when the result relies on it
Returns to: verify-this or diagnosing-bugs

2026-09-15 roster-keepers-2026-09-15

The Returns line omitted product-description, which dispatches this skill in its verification pass (the audit J-5, finding 10; found again by J-10); the chain now closes with the router's support section as keeper. The earlier claim is carried forward.

SKILL.md

lifecyclechangedroster-keepers-2026-09-15

The Handoff section names what this support skill consumes, the evidence it produces, its scratch and promoted homes, and the stages it returns to, product-description among them since it dispatches the verification pass, so the chain closes; carried from fold-2026-09-11 (J-8, 2026-09-15)

 
## Handoff
 
Consumes: the surface under test and the question the requesting stage needs answered
Produces: screenshots, snapshots, logs, traces or profiles with the instrument that made them, as evidence for the requester's verdict
Evidence at: .greenline/tmp/control-ui/, promoted to .greenline/work/evidence/<work-id>/ or .greenline/ledger/evidence/<contribution>/ when the result relies on it
Returns to: verify-this, diagnosing-bugs or product-description

2026-09-15 roster-keepers-fix-2026-09-15

The review REV-J-8 (Prose 1) found the opening scope paragraph naming two dispatchers while the Handoff names three; the opening now names product-description as well. The earlier claim is carried forward.

SKILL.md

lifecyclechangedroster-keepers-fix-2026-09-15

the opening paragraph and the Handoff name the same three dispatchers, verify-this, diagnosing-bugs and product-description, and the stages the capture returns to, so the chain closes; carried from roster-keepers-2026-09-15 (J-8's fix, 2026-09-15)

verify-this, diagnosing-bugs or product-description dispatches this method when its verdict needs a screenshot, an accessibility snapshot, a trace or a profile; the capture goes back to that stage as evidence, and the verdict stays there. Reuse an existing local UI harness before assembling one. Screenshots and traces support a verdict; they do not decide it.