Files
loong-workflow/core/skills/browser-debug/SKILL.md
T

20 KiB

name, description, tools, triggers, role
name description tools triggers role
browser-debug Use ONLY when an agent must interact with a live browser to debug, verify, or iterate on Web UI work in packages/app. Triggers on UI bugs, visual regressions, layout/positioning issues, keyboard-focus problems, console-error reports, and any "open the page and check X" task. Uses the built-in unified browser tool surface (browser_open, browser_snapshot, browser_take_screenshot, browser_console_messages, browser_evaluate, browser_close) — contract shared/browser-tool-surface-v1 ([org-internal #4972]); the playwright MCP server is retired ([org-internal #4977]). Use ONLY for interactive browser work; for writing Playwright *test files* use the existing e2e/ suites under packages/app, not this skill.
browser_open
browser_close
browser_snapshot
browser_console_messages
browser_take_screenshot
browser_evaluate
browser_click
browser_type
browser_act_batch
browser_handle_dialog
browser_highlight
browser_generate_locator
browser debug
open the page
check the page
inspect element
console error
visual bug
visual regression
layout broken
alignment off
focus ring
tab order
浏览器调试
打开页面
布局错乱
对齐
焦点
控制台报错
Producer

Core 中立版(Increment 6a 改写,原 deferHard verbatimDir)。机制、结构与 frontmatter 保持;实例术语(工具名、路径、工单号)按 core/adapters/TERMINOLOGY.md 绑定到具体实例。

Browser Debug

Interactive browser automation for Web UI work in packages/app. This skill teaches the recipe for driving the unified browser tool surface — when to reach for it, which tool for which job, and how to capture evidence a reviewer can trust. The former playwright MCP server is retired ([org-internal #4977], Epic [org-internal #4972] N-05); the tools below are built-in and mount into the session tool face when this skill activates (default-off the LLM face for weight economy, [org-internal #5131]) — a user-configured tools_exclude vetoes the mounts.

When this skill applies

Reach for browser-debug when a task requires observing the live application, not just reasoning about code:

  • Reproducing a UI bug (focus lost, dropdown won't close, scroll jumps).
  • Verifying a visual change actually landed (computed style, layout box, dark-mode token).
  • Capturing console errors or failed network requests during a user flow.
  • Recording a screenshot / trace as evidence for a review or DoD entry.
  • Exercising a keyboard / screen-reader flow end-to-end.

Do not reach for it when:

  • You are writing Playwright test files — those live in packages/app/e2e/... and run via cd packages/app && bun run test:e2e (variant suites: test:e2e:perf, test:e2e:a11y, test:e2e:smoke, test:e2e:visual). This skill is for ad-hoc, agent-driven sessions, not for adding tests.
  • The question can be answered by reading code or running a unit test. Browser time is expensive; spend it only when the live DOM is the oracle.

Preconditions

  1. Unified browser tools are built-in and skill-mounted. browser_open, browser_snapshot, browser_console_messages, browser_take_screenshot, browser_evaluate, and browser_close are registered for every session (no MCP server needed) but default-off the LLM face — activating this skill mounts them onto the session tool face ([org-internal #5131]); a user tools_exclude vetoes the mounts config needed (the playwright MCP is retired, [org-internal #4977]). If the tools are not visible, the session runs a pre-[org-internal #4972] build — update.
  2. Dev server is running. The app under test must be reachable. For packages/app, run bash script/dev-fresh.sh --full for the dev server (Windows workstations: bash script/dev-fresh-windows.sh — dev-fresh.sh's stop path depends on setsid/ss, silently ineffective under Git Bash; see local-workstation-quirks.md §5); frontend is at http://localhost:4444 and backend at http://localhost:4096 (see AGENTS.md Dev services section).
  3. Chromium is installed. The headless backend drives an isolated Chromium; if a tool reports a missing browser, run bunx playwright install chromium once in any shell.

Tool selection recipe

The unified surface exposes focused read/navigation tools. Pick by what you need to observe, not by familiarity. Cost discipline applies: the snapshot answers structure/state questions, the screenshot only visual ones — take both in one cycle only when a visual verdict is itself the deliverable:

Need Tool Why
Open a URL browser_open Always the first call (opens the user-visible browser pane / isolated browser). Pass surface: "headless" when the intent is headless — the user's pane is never touched (no confirmation bar, no pane binding) and later browser_* tools operate on the isolated headless copy; if already bound to the pane, browser_pane_release first.
See the page structure (roles, names) browser_snapshot Returns the accessibility tree — stable across CSS refactors. Prefer this over browser_take_screenshot when asserting "does element X exist / is it labelled Y?".
See the page visually browser_take_screenshot For layout, spacing, color, overflow. Attach the PNG to your report. Vision-model guard (#screenshot-guard): the PNG is pixels, not text — a session model without vision CANNOT read it. If YOU cannot see images, you must delegate reading via Task(role: "Tool") per the image-interpret skill (returns a structured text spec); never attempt to interpret the PNG yourself. Pixel questions → image-interpret; DOM/state questions → browser_evaluate.
Read console errors / warnings browser_console_messages Filter by level (error, warn). The first stop for any "page is blank" bug.
Assert computed style / DOM state browser_evaluate Last resort. Snapshots cover 90%; reach for evaluate only when you need getComputedStyle, scroll positions, or arbitrary JS state.
Close the session browser_close Tear down when done; see the session cleanup section.

Pane-first recipe (prefer over headless)

Default to the user-visible browser pane unless the task explicitly needs an isolated headless Chromium (surface: "headless"). Pane agents now match or exceed Playwright for the hard cases:

Need Pane tool / pattern Notes
Open / bind pane browser_open (default surface) Never touch the user's pane from a headless-only intent — pass surface: "headless" or browser_pane_release first.
Structure + refs browser_snapshot Open shadow is pierced; closed shadow is CDP-merged (closedShadow:true, no e<n>). Cross-origin iframes expose f{seq}/e{n} synthetic refs — prefer those over attr ids when acting into child frames. Closed hosts inside stitched OOPIF subtrees carry closedShadow:true (CDP merge after stitch).
Act (click/type/…) browser_click / browser_type / browser_act_batch Locators (role= / text= / …) walk open shadow; after a JS miss, pane CDP pierces closed shadow for locate/wait/scroll (nested closed-in-open + same-origin iframe contentDocument + cross-origin OOPIF via Target.attachToTarget, including nested OOPIF-in-OOPIF host-offset chains; DOM.focus for type). css= stays light-DOM. Cross-origin click/type route through CDP trusted events.
Native dialogs browser_handle_dialog before the act Prefer mode: "arm" (or act_batch.dialog_prearm) so the pane parks the answer before the click that opens confirm/prompt — avoids the 1.5s auto-dismiss / widget-cancel race. Bind with messageIncludes when the page can raise multiple dialogs. Call mode: "disarm" if the trigger was cancelled.
Highlight / locator browser_highlight, browser_generate_locator Dual-leg: both pane and headless. Use highlight to confirm the ref before a write.
Failure recovery re-snapshot + path candidates Act/locator failures may return pathCandidates (frame/shadow path hints). Heal scores framePath so sibling iframes do not auto-heal across frames.

Headless remains the right tool for parallel CI-style isolation and when the user must not see the session. For interactive debug of packages/app, stay on the pane.

Standard recipe — reproduce a UI bug

Follow these steps in order. Do not skip the snapshot step: the ref it returns is the stable handle every subsequent tool needs.

  1. browser_open the page where the bug lives.
  2. browser_console_messages — record any errors before touching anything. Many "interaction bugs" are actually load-time errors.
  3. browser_snapshot — locate the target element; capture its accessible name.
  4. If the reproduction needs interaction beyond reading, use browser_evaluate sparingly to probe state — the unified surface is read-focused; drive deep flows via the e2e suites when needed.
  5. Re-read browser_console_messages — capture the delta introduced by the interaction / page state.
  6. browser_take_screenshot (or a second browser_snapshot) to freeze the broken state.
  7. Report: URL, the observation sequence, console delta, screenshot, and the suspected component path in packages/app/src/....

Standard recipe — verify a UI fix

  1. browser_open the affected page.
  2. browser_snapshot — confirm the fixed element is present with the expected accessible name.
  3. browser_take_screenshot — only when the fix is visual (layout, styling, rendering); full page and element-cropped if the fix is local. For non-visual fixes (logic, state, wiring) the snapshot plus console delta is the evidence — skip the screenshot.
  4. If the fix touched layout, browser_evaluate a getBoundingClientRect() or getComputedStyle() on the key node and paste the value into your report. Numbers beat adjectives.
  5. If the fix touched interaction, replay the original bug reproduction steps and assert the previous failure no longer fires.

Standard recipe — capture evidence for verify / DoD

When a verify work item has an E2E or UI DoD entry:

  1. Run the recipe above for each DoD line.
  2. Save each screenshot as .playwright-mcp/dod-{item-id}-{state}.png — the worktree's gitignored output dir. See "Screenshot output paths" below.
  3. In the verification report, cite the file names and tell the reviewer where to look: open the worktree as an octopus project → session side panel "Screenshots" tab (or the standalone screenshots page). Verify with GET /screenshots?directory={worktree} before citing. A screenshot the reviewer can open beats a paragraph of "I checked it".
  4. When the DoD row will cite the evidence as a BROWSER:{pack-ref} reference (UI-touching PRs, verify skill Phase 2.7 / contract browser-evidence-4486/shared/evidence-ref-v1), promote the captures into an evidence pack first — feed COPIES through writeEvidencePack (packages/octopus/src/browser/evidence-pack.ts, the single mandatory sanitize boundary; the .playwright-mcp/ layer keeps its current semantics, additive not replaced) and cite the pack directory. Evidence ladder: raw capture → .playwright-mcp/ working layer (gitignored) → sanitized Tier-1 pack → BROWSER: reference the verifier validates mechanically.

Rationalizations to refuse

Excuse Reality
"The unit test already covers it." Unit tests assert component logic, not what Chromium actually renders. Visual and focus bugs live in the gap.
"I can tell from the JSX that it's aligned." Computed layout depends on parent containers, fonts, and viewport. Screenshot the real page.
"Browser automation is overkill for a small change." A browser_open + browser_snapshot read is ~2 seconds — cheap. The cost is in not looking; add the screenshot only where the question is visual.
"I'll just run the whole e2e suite." The suite answers "did anything break?" — it does not answer "does this specific change look right?".
"Snapshot is enough, skip the screenshot." Depends on the claim. For a visual change it is backwards — accessibility trees hide overflow, clipping, and z-index bugs, so take the screenshot too. For a non-visual claim (presence, label, state) the snapshot alone IS the observation; don't pad it with pixels.

Boundaries

  • Read-only by default. This skill never writes files under packages/app/src/ — it observes. Edits flow through implement (bugfix/refactor/port mode).
  • One page at a time. Close tabs (browser_close) between scenarios so state doesn't leak.
  • Evidence lives in the worktree's .playwright-mcp/ dir. Any screenshot or trace you reference in a PR comment, verification report, or DoD entry must be copied into the workflow worktree's .playwright-mcp/ directory (gitignored) — never left in /tmp/, playwright-report/, or any machine-local path the reviewer cannot reach through octopus. Cite file names + the worktree project path; the reviewer opens the octopus screenshots UI (session panel tab or screenshots page) to view them.

Session cleanup (mandatory)

The unified surface's isolated backend is a real Chrome with a /tmp user-data-dir. It stays alive as long as its parent octopus backend runs. When a browser-debug session ends without an explicit browser_close, OR the octopus session times out mid-task, the Chrome is orphaned and accumulates across sessions — burning CPU and leaving dead profile dirs (issue [org-internal #1315]); in headed mode the orphan is a visible stray window.

Iron rule: every browser-debug session MUST close its browser before ending.

  1. Always close when done. The last action of any browser-debug task is browser_close. Treat it like a return — if you opened a browser, you close it. Do not rely on session teardown to do it for you; it doesn't.
  2. Close on error too. If the task aborts (bug not reproduced, tool error, user redirect), still call browser_close before moving on. An abandoned debugging session is the most common orphan source.
  3. If a browser was already orphaned (you spot a stale Chrome in ps, or a /tmp/playwright_chromiumdev_profile-* dir with no live session), do not leave it. bash script/dev-fresh.sh --full (Windows workstations: dev-fresh-windows.sh, same stop-path caveat as Preconditions §2) reaps orphan dev sessions and init-adopted browsers before restarting; run it to clean up. For a targeted clean without restarting the dev server, kill the Chrome by its profile: pkill -f 'playwright_chromiumdev_profile' (and any agent-browser harness reparented to init).

Why this matters: a single forgotten browser_close leaves a Chrome subtree (8+ processes) running indefinitely. Over days this is hundreds of orphaned processes and wasted CPU. Only an explicit browser_close (or process reaping) releases it.

Screenshot output paths

Screenshots from browser_take_screenshot land in .playwright-mcp/ in the process cwd (the worktree root), gitignored. An explicit filename can resolve against the cwd and drop the PNG into the repo root, where the /*.png gitignore backstop hides it from git status and nothing ever cleans it up.

Iron rule: 截图文件名必须写进 .playwright-mcp/。 Every filename passed to browser_take_screenshot (or any tool that writes a file) MUST resolve into .playwright-mcp/ — write it as .playwright-mcp/<name>.png, or use an absolute path under /tmp/octopus/. NEVER a bare relative name like 2202-after-models.png: it leaks a root-level PNG that gitignore masks but nobody deletes (the 2026-08 repo-root buildup — 40+ orphan PNGs — came from exactly this).

Two valid destinations for screenshots, by purpose:

Purpose Destination Why
Ad-hoc / throwaway (debug a layout, confirm a fix landed, never cited in any report) .playwright-mcp/<name>.png, or omit filename to auto-save into the same dir Survives across the session, auto-evicted at 100 MB, never pollutes the repo.
Evidence cited in a PR / report / DoD entry .playwright-mcp/<name>.png — the cwd is the worktree root, so no copy step is needed Zero repo bloat (gitignored, never committed); viewable by the reviewer through octopus's own screenshots UI (session panel "Screenshots" tab / standalone screenshots page, served by GET /screenshots?directory={worktree}); lifecycle bounded to the worktree = the review window.

Evidence publishing ladder (verified 2026-08-14 on this Gitea version):

  1. Copy into the workflow worktree's .playwright-mcp/ — primary path. Cite file names + worktree project path; reviewer views via the octopus screenshots UI. Verify reachability with GET /screenshots?directory={worktree} before citing. Never commit evidence binaries to git — screenshots accumulate per PR and git history is unreclaimable (measured ~80KB/PR today, unbounded growth). Do not put routine debug screenshots on the wiki either — base64-in-page bloats the wiki git repo equivalently; the wiki evidence namespace is reserved for the durable verify-stage evidence channel (rung 3).
  2. Issue attachments API (POST /api/v1/repos/{o}/{r}/issues/{n}/assets) — alternative when the reviewer cannot reach the worktree through the octopus UI. The endpoint exists but has returned 500 on this instance; verify before relying on it.
  3. Publish to the wiki evidence namespace {slug}/verify/evidence/{name} via git direct-push to octopus.wiki.git (_shared/gitea-write-patterns.md top-of-file, [org-internal #6180]) — last resort only, when no other channel works AND the evidence must outlive the worktree (this is the same durable channel verify mandates for DoD evidence entries — see .octopus/skills/verify/SKILL.md References). Keep it small: ≤5 images per PR, each ≤200KB (compress/downscale, prefer element crops over full-page).

Iron rule: never cite a machine-local path (/tmp/..., ~, project root) as evidence in a Tier-2 output (PR comment, issue comment, verification report). The reviewer must be able to open the evidence through octopus (.playwright-mcp/ + screenshots UI) or a repo/wiki URL (worktree files, or the {slug}/verify/evidence/{name} wiki pages). A citation they cannot reach is a fabricated citation.

Never write screenshots to the project root. The .gitignore rejects /*.png, /.playwright-mcp/, and /playwright-report/ only as a backstop — an ignored file is still an orphan on disk. The .playwright-mcp/ filename prefix is the real fix; rely on that, not on the backstop.

References

  • .octopus/skills/image-interpret/SKILL.md — REQUIRED when the session model has no vision: browser_take_screenshot writes a PNG the driving model cannot read. Delegate reading via Task(role: "Tool") (structured text spec back); never self-interpret pixel content. Pixel questions (layout, color, spacing) → image-interpret; DOM/state questions (form values, validation) → browser_evaluate.
  • .octopus/skills/frontend/SKILL.md — where UI changes are planned; invoke this skill during Phase 3 / Phase 4 to verify each state visually.
  • .octopus/skills/implement/SKILL.md — Frontend Mode; pair with browser-debug when the work item touches rendering.
  • .octopus/skills/implement/SKILL.md (Mode: bugfix) — Phase 1 reproduction; use this skill to capture the failing state before isolating root cause.
  • .octopus/skills/verify/SKILL.md — Phase 2 / DoD matrix; use this skill to generate screenshot evidence for UI-tagged DoD entries.
  • packages/app/e2e/ — permanent Playwright test suites; this skill is the ad-hoc complement, not a replacement.
  • rules/dev-server on the wiki — how to run the dev server for TUI work; consult packages/app/README.md for the web equivalent.