Hands-off, diff-scoped browser QA of the active branch: maps user flows, drives a real browser, autonomously fixes small breakages with regression tests and commits, judges experience against product personas, and writes a durable dogfood report. Manual invocation only.
agent-browser Only For Browser Automationagent-browser CLI. Do not use Chrome MCP tools (mcp__claude-in-chrome__*), any browser MCP integration, or other built-in browser-control tools. If the platform offers multiple ways to control a browser, always choose agent-browser. Use the direct binary, never npx agent-browser (the direct binary uses the fast Rust client).bin/dev, rails server, npm run dev, etc.).agent-browser installed. Check:command -v agent-browser >/dev/null 2>&1 && echo "Ready" || echo "NOT INSTALLED"
agent-browser (run /ce-setup to print the current install command), then re-run this skill — this workflow cannot function without it.ce-dogfood is an orchestrator. Prefer delegating to existing CE skills over re-deriving their behavior:| When | Skill | Why |
|---|---|---|
| Phase 0 isolation | ce-worktree | Run the dogfood in an isolated worktree so the main checkout stays clean. |
| A failure's root cause is non-obvious | ce-debug | Systematic root-cause analysis instead of guess-and-check. |
| Committing each fix | ce-commit | Consistent, well-scoped commit messages. |
| A bug reveals a reusable lesson | ce-compound | Capture the learning so the team compounds knowledge. |
0. Scope Pick the branch, get onto it (offer worktree), never touch the trunk
1. Analyze Diff branch vs trunk, understand every change
2. Map+Matrix Map user flows as Mermaid flowcharts, then derive the test matrix as a task list
3. Serve Detect port, start dev server, open agent-browser
4. Execute Work the matrix one item at a time with agent-browser
5. Fix loop On failure: fix -> add regression test -> commit -> continue
6. Report Write durable doc to docs/dogfood-reports/ (flows, matrix, fixes, learnings, verdict)
$ARGUMENTS: a PR number, a branch name, or blank (use current branch). Strip --port PORT if present.gh pr view <number> --json headRefName,isCrossRepository), but do not reduce it to a bare branch name: a fork PR's head can even be named main/master. Do not check out yet.main/master/the detected default), stop — there is no diff to dogfood. A PR is always diffable (it has a base), so this check never applies to a PR target; never refuse /ce-dogfood <number> just because the PR's head branch happens to be named main.ce-worktree own the worktree mechanics. Do not re-derive worktree detection or creation here — ce-worktree handles existing-isolation detection, the harness-native tool, attaching to a ref, and the "already checked out" constraint, and reports its decision back. The only call this skill makes is whether to ask for isolation at all:
ce-worktree to isolate that target ref — it attaches a worktree to the ref (or, if already isolated, checks it out in place; or reports "already checked out at <path> — work there" when the ref is live elsewhere). Act on ce-worktree's verdict; the primary checkout is never switched. On no, check the target out in place (gh pr checkout <number> for a PR, git checkout <branch> for a branch), confirming first if uncommitted changes would be disturbed.docs/dogfood-reports/*-<branch-slug>-dogfood.md (see the branch-slug rule under Resumability). If one is found with unfinished scenarios, ask whether to resume it or start fresh. To resume, re-hydrate the task list from its matrix: Pass/Fixed/Skipped stay done; Pending and in_progress become the remaining auto-runnable work. The two Blocked states are not auto-runnable — Blocked (needs human verify) and Blocked (human decision) are waiting on a person, so surface them to the user and ask how to proceed rather than silently re-queuing them.TaskCreate/TaskUpdate on Claude Code, update_plan on Codex, or the equivalent elsewhere) is the live to-do — one task per matrix scenario. Mark each in_progress when you start it and completed only when it genuinely passes.docs/dogfood-reports/<YYYY-MM-DD>-<branch-slug>-dogfood.md is the durable checkpoint that survives across sessions. <branch-slug> is the branch name lowercased with every run of non-alphanumeric characters (slashes included) collapsed to a single - (e.g. feature/Foo_Bar -> feature-foo-bar). Create it as soon as the matrix exists (end of Phase 2) by instantiating references/dogfood-report-template.md (read that template now if you haven't) so the checkpoint carries the template-owned section shape from the start — then fill in every scenario at Pending, and update it incrementally — after each scenario is judged and after each fix is committed — not only at the end. An interrupted run must leave a template-shaped checkpoint, not a bare matrix.main — a repo whose default branch is master (or anything else) would fail with fatal: ambiguous argument 'main...HEAD'.# Resolve the trunk to a ref that actually exists. Start from the detected
# default name (origin/HEAD, then gh), then fall back to common names. For each
# candidate prefer a local branch; else use the remote-tracking ref QUALIFIED as
# origin/<branch> — an unqualified name resolves via refs/remotes/<name>, NOT
# refs/remotes/origin/<name>, so a remote-only trunk would otherwise miss. This
# qualification applies to the detected default too (PR/CI checkouts often have
# only origin/main, no local main).
DEFAULT=$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')
DEFAULT=${DEFAULT:-$(gh repo view --json defaultBranchRef -q .defaultBranchRef.name 2>/dev/null)}
TRUNK=""
for cand in "$DEFAULT" main master; do
[ -n "$cand" ] || continue
if git show-ref --verify --quiet "refs/heads/$cand"; then
TRUNK=$cand; break
elif git show-ref --verify --quiet "refs/remotes/origin/$cand"; then
TRUNK="origin/$cand"; break
fi
done
TRUNK=${TRUNK:-main}
git diff --name-only "$TRUNK...HEAD" # what changed
git diff "$TRUNK...HEAD" # how it changed
STRATEGY.md (its "Who it's for" section names the primary persona and their job-to-be-done), VISION.md, and any persona docs (e.g. docs/personas/, PERSONAS.md). Capture the 1-3 primary personas and what each cares about. If none exist, infer a reasonable primary persona from the product and the diff, and say so in the report.flowchart so the journey is explicit and reviewable before any testing happens — entry point, each user action, branch points (success / validation error / empty / permission-denied), side effects (emails, jobs, notifications), and the true end state.Email example: it's not enough that "an email sends." Does it go to the right recipient? When the user clicks through, does the app land on and scroll to the right message? Does the content make sense? Does the whole flow align with the product's vision and UX? The flowchart must carry the click-through and its destination, not stop at "email sent."
references/test-matrix-taxonomy.md for the full set of dimensions (journeys, functional checks, experiential checks, edge/error/empty states, accessibility, responsiveness). Cover both functional ("does it work?") and experiential ("does it feel right and align with the product?").--port > a port explicitly stated in your in-context project instructions > package.json dev script > .env* PORT= > default 3000). If a server is already listening on it, reuse it. Otherwise start the project's dev command (bin/dev, rails server, npm run dev, etc.) in the background and poll the port until it accepts connections before opening the browser. This skill is hands-off, so start the server automatically without asking — do not block on a confirmation.agent-browser open "http://localhost:${PORT}"
agent-browser snapshot -i
in_progress, then:agent-browser open "http://localhost:${PORT}/<route>"
agent-browser snapshot -i
agent-browser click @e1
agent-browser fill @e2 "value"
agent-browser screenshot "$(mktemp -d)/<scenario>.png" # scratch dir, not the repo root
agent-browser errors # check console/page errors
mktemp -d), never the repo root. Only copy a screenshot into the report's location if you intend to embed it in the final report.Pass yet still carry paper cuts. Note each paper cut, which persona feels it, and its severity.completed only when it genuinely passes. Paper cuts do not block a Pass, but a sharp paper cut (one severe enough to fix now) is routed into the Phase 5 fix loop just like a failure — apply the same auto-fix-vs-escalate judgment to it. Log the rest in the report.Blocked (needs human verify) until they confirm. Then continue.ce-debug.ce-commit). One logical fix per commit.ce-compound.Blocked (human decision) in the matrix, then continue with the rest. Never make a large, irreversible, or product-altering change just to clear a matrix item.completed or in a terminal Blocked state — Blocked (human decision) (escalated here) or Blocked (needs human verify) (set in Phase 4 for external-interaction legs). Both are terminal for the loop: they wait on a person, so do not re-queue them. Re-test anything a fix might have affected (watch for regressions in adjacent journeys).docs/dogfood-reports/<YYYY-MM-DD>-<branch-slug>-dogfood.md in the repo under test, then surface a short summary in chat with the file path.references/dogfood-report-template.md — the same template the Phase 2 checkpoint was instantiated from, which owns the required sections and what each must carry. Confirm every template-owned section is present and complete; do not reconstruct the section list from memory, as that drifts from the template. Carry forward the cross-phase obligations this skill produced: the Mermaid flowcharts from Phase 2a, a matrix row per scenario with its commit SHA, each fix's root cause and the regression test added (or why none was meaningful), paper cuts attributed by persona, learnings worth feeding to ce-compound, and a final readiness verdict that records the Phase 5 automated-suite result.