| 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. |
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. |
| 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
| "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. |
| "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. |
**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).
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