4 changed files with 150 additions and 85 deletions
+37
View File
@@ -0,0 +1,37 @@
# GENERATED by script/coord-init.sh — DO NOT EDIT BY HAND (machine-table-v1).
# Regenerate: bash script/coord-init.sh --table <machine-table.tsv> --out <dir>
# Cross-machine coordination wake channel — parameterized rendering of the
# hand-written #6590 wake.yml (semantic parity: machine:<X> dual-shape label
# guard + status= comment guard + from:<X>, per-machine runner label,
# concurrency group with cancel-in-progress, constant local payload file).
# Iron invariants (wiki rules/cross-machine-agent-ops §0): events contribute
# TIMING only, never content — the payload is a constant file local to the
# target machine; the workflow references no Gitea secret.
name: wake
on:
issues:
types: [labeled]
issue_comment:
types: [created]
permissions: {}
jobs:
wake:
if: |
(github.event_name == 'issues' &&
((github.event.label != null && github.event.label.name == 'machine:wf-mac01') ||
(github.event.changes != null && contains(github.event.changes.added_labels.*.name, 'machine:wf-mac01')))) ||
(github.event_name == 'issue_comment' && startsWith(github.event.comment.body, 'status=') && contains(github.event.issue.labels.*.name, 'from:wf-mac01'))
runs-on: [self-hosted, wf-mac01]
concurrency:
group: wake-wf-mac01
cancel-in-progress: true
steps:
- name: wake local dispatcher via prompt_async (constant local payload)
# shell: default (POSIX runner)
run: |
curl -sS --fail-with-body --max-time 30 -X POST http://127.0.0.1:4097/prompt_async \
-H 'content-type: application/json' \
-d @/Users/zhusihong/workspaces/Octopus/octopus-coord-n06-external-verify/.n06-tmp/wf-4097/wake-payload-wf-mac01.json
+13
View File
@@ -84,6 +84,19 @@ and the provision wrapper (adds the worktree + Tier-1 runs scaffold). The
manual 3-step is the fallback where the scripts are unavailable, same
re-verification.
**Human-only tickets ([org-internal #6617]-P1).** A ticket marked
human-only in ANY of three machine-readable forms — title `[人工执行]`
(ASCII/【】 fullwidth variants), label `executor/human-only`, or a body
line `executor: human` / `executor: human-only` (line-anchored,
blockquote-tolerant) — is NOT claimable by an agent: the claim script
refuses (exit 4, stage=precheck; takeover mode too — taking over a dead
claim is not taking over execution rights). The title channel keeps the
`--allow-human-only` override (explicit human instruction only, visible in
the invoking transcript); the label/body channels have NO override — an
explicit marker is a hard refusal for agents ([org-internal #6617] merged
ruling). Never claim, execute, self-accept or close such a ticket on agent
initiative.
**Merge-time equivalence check.** Before merging, scan the remote main
branch's recent commits for `#<ticket>` — surfacing an equivalent
implementation already on main *before* the merge rejection.
+98 -83
View File
@@ -1,21 +1,33 @@
---
name: browser-debug
description: >
Use ONLY when an agent needs to interact with a live browser to debug, verify,
or iterate on Web UI work in packages/app — navigate to the dev server, snapshot
the DOM/accessibility tree, capture console and network errors, screenshot
component states, and exercise user flows end-to-end. Triggers on UI bugs,
visual regressions, layout/positioning issues, keyboard-focus problems,
console-error reports, and any "open the page and check X" task. Loads the
Playwright MCP toolset (browser_navigate, browser_snapshot,
browser_take_screenshot, browser_console_messages, browser_evaluate, etc.).
Use ONLY for interactive browser work; for writing Playwright *test files*
use the existing e2e/ suites under packages/app, not this skill.
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.
tools:
- 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
triggers:
- browser debug
- open the page
- check the page
- screenshot the
- inspect element
- console error
- visual bug
@@ -26,8 +38,6 @@ triggers:
- tab order
- 浏览器调试
- 打开页面
- 截图
- 视觉
- 布局错乱
- 对齐
- 焦点
@@ -36,13 +46,15 @@ role: 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 Playwright MCP toolset — when to reach
for it, which tool for which job, and how to capture evidence a reviewer can
trust.
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
@@ -68,37 +80,41 @@ Do **not** reach for it when:
## Preconditions
1. **Playwright MCP is configured.** The project `octopus.jsonc` carries a
`mcp.playwright` block launching `@playwright/mcp`. If the MCP tools are
not visible, run `/kickoff` or follow the `codegraph-setup` skill's
recipe (the closest analog for debugging missing MCP servers).
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.** First run of `@playwright/mcp` downloads it
automatically; if the tool reports a missing browser, run
`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 Playwright MCP exposes many tools. Pick by *what you need to observe*,
not by familiarity:
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_navigate` | Always the first call. |
| 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. |
| 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. |
| Read failed network calls | `browser_network_requests` | Locate 4xx/5xx, CORS failures, hanging fetches. |
| Click, type, hover, select | `browser_click`, `browser_type`, `browser_hover`, `browser_select_option` | Drive the flow. Always `browser_snapshot` first to get the `ref` for the target element. |
| 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. |
| Keyboard navigation | `browser_press_key` | For tab order, focus rings, escape-to-close. |
| Record a video / trace | `browser_start_tracing`, `browser_stop_tracing` | Heavy; use only when a bug is timing-sensitive and console+snapshot can't catch it. |
| Close the session | `browser_close` | Tear down when done; see the session cleanup section. |
## Pane-first recipe (prefer over headless)
@@ -109,8 +125,8 @@ 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; cross-origin iframes expose `f{seq}/e{n}` synthetic refs — prefer those over attr ids when acting into child frames. |
| Act (click/type/…) | `browser_act` / `browser_act_batch` | Locators (`role=` / `text=` / …) walk open shadow. Cross-origin click/type route through CDP trusted events. |
| 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. |
@@ -124,28 +140,30 @@ on the pane.
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_navigate` to the page where the bug lives.
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 `ref` and
accessible name.
4. Drive the interaction with `browser_click` / `browser_type` /
`browser_press_key` until the bug reproduces.
5. Re-read `browser_console_messages` and `browser_network_requests` —
capture the *delta* introduced by the interaction.
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 minimal interaction sequence, console delta, network
delta, screenshot, and the suspected component path in
`packages/app/src/...`.
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_navigate` to the affected page.
1. `browser_open` the affected page.
2. `browser_snapshot` — confirm the fixed element is present with the
expected accessible name.
3. `browser_take_screenshot` — full page **and** element-cropped if the fix
is local.
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.
@@ -169,7 +187,7 @@ When a `verify` work item has an E2E or UI DoD entry:
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` (`<harness-package>/src/browser/evidence-pack.ts`,
`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
@@ -182,9 +200,9 @@ When a `verify` work item has an E2E or UI DoD entry:
| --- | --- |
| "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_navigate` + `browser_take_screenshot` pair is ~2 seconds. The cost is in *not* looking. |
| "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." | Accessibility trees hide overflow, clipping, and z-index bugs. Take both for visual changes. |
| "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
@@ -203,18 +221,12 @@ When a `verify` work item has an E2E or UI DoD entry:
## Session cleanup (mandatory)
A Playwright MCP browser is a real Chrome with a `/tmp` user-data-dir — its
mode follows `mcp.playwright.headless` (`headless-field-v1`, [org-internal #4393]): the repo
default `auto` spawns headed on desktop (win32/darwin; linux only with
DISPLAY/WAYLAND_DISPLAY set) and headless otherwise; an explicit `true`/`false`
or `OCTOPUS_MCP_HEADLESS=1|0` pins it. The mode is fixed per new session —
switching the config does not hot-switch a running browser. It
stays alive as long as its MCP server runs, and the MCP server 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 + its MCP server are orphaned and accumulate across sessions —
burning CPU and leaving dead profile dirs (issue [org-internal #1315]); in headed mode the
orphan is a visible stray window.
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.**
@@ -236,19 +248,16 @@ orphan is a visible stray window.
**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. The MCP server does not auto-close its
browser on disconnect — only an explicit `browser_close` (or process reaping)
releases it.
orphaned processes and wasted CPU. Only an explicit `browser_close` (or
process reaping) releases it.
## Screenshot output paths
The Playwright MCP server is launched WITHOUT `--output-dir` (see
`octopus.jsonc` → `mcp.playwright.command`): its default output location is
`.playwright-mcp/` in the process cwd (the worktree root), gitignored and
auto-evicted at 100 MB via `--output-max-size`. Auto-named output (no
`filename`) lands there — but 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.
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
@@ -281,10 +290,10 @@ Two valid destinations for screenshots, by purpose:
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 `wiki 读写 API(见 TERMINOLOGY)`** — last resort only, when no other channel
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
`core/skills/verify/SKILL.md` References). Keep it small:
`.octopus/skills/verify/SKILL.md` References). Keep it small:
≤5 images per PR, each ≤200KB (compress/downscale, prefer element
crops over full-page).
@@ -302,13 +311,19 @@ prefix is the real fix; rely on that, not on the backstop.
## References
- `core/skills/frontend/SKILL.md` — where UI changes are planned; invoke
- `.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.
- `core/skills/implement/SKILL.md` — Frontend Mode; pair with
- `.octopus/skills/implement/SKILL.md` — Frontend Mode; pair with
`browser-debug` when the work item touches rendering.
- `core/skills/implement/SKILL.md` (Mode: bugfix) — Phase 1 reproduction; use this skill
- `.octopus/skills/implement/SKILL.md` (Mode: bugfix) — Phase 1 reproduction; use this skill
to capture the failing state before isolating root cause.
- `core/skills/verify/SKILL.md` — Phase 2 / DoD matrix; use this skill
- `.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.
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "octopus-workflow",
"version": "0.1.7",
"version": "0.1.8",
"description": "Standalone workflow core: provider-neutral agent workflow corpus (skills / rules / checklists / templates / schemas) with drift guards, extracted from the octopus agent platform.",
"license": "MIT",
"private": false,
@@ -16,4 +16,4 @@
"type": "git",
"url": "https://eightarms.net/Octopus/octopus-workflow"
}
}
}