From compound-engineering-core
Validate frontend/browser behavior for qualifying PRs using gstack headless browser
npx claudepluginhub adam-badar/compound-engineering-system --plugin compound-engineering-core[PR number, PR url, branch name, or current]workflows/# Frontend Validate (Browser + State + Refresh) Use this command when a PR touches frontend, session, auth, routing, or client-state behavior. This command is the browser-validation gate for Compound Engineering. It uses gstack's persistent headless Chromium for browser inspection and writes auditable evidence. ## Inputs <frontend_validation_input> #$ARGUMENTS </frontend_validation_input> If empty, ask: "Which PR or branch should I validate?" Optional runtime flags in arguments: - `sha=<sha>` to pin validation to a specific revision (auto-supplied when invoked from `work`) - `env=aut...
Use this command when a PR touches frontend, session, auth, routing, or client-state behavior.
This command is the browser-validation gate for Compound Engineering. It uses gstack's persistent headless Chromium for browser inspection and writes auditable evidence.
<frontend_validation_input> #$ARGUMENTS </frontend_validation_input>
If empty, ask: "Which PR or branch should I validate?"
Optional runtime flags in arguments:
sha=<sha> to pin validation to a specific revision (auto-supplied when invoked from work)env=auto|local|staging (default auto)target_url=<url> to force a specific URL when auto-routing is insufficientcompound-engineering.local.md)require_frontend_validation_for_frontend_changes (default: true)frontend_validation_mode (default: gstack)frontend_local_url (default: http://localhost:3000)frontend_staging_url (default: "")frontend_validation_use_staging_fallback (default: false)frontend_local_revision_check_command (default: "")frontend_staging_revision_check_command (default: "")sha=<sha> is supplied and does not match current head SHA, stop with status: STALE.require_frontend_validation_for_frontend_changes: false, write an N/A artifact with rationale (policy disabled) and return status: N/A.Treat browser validation as required when any of the following changed:
If the change does not qualify:
N/A artifact with rationalestatus: N/ALocate gstack browse binary:
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
B=""
[ -n "$_ROOT" ] && [ -x "$_ROOT/.claude/skills/gstack/browse/dist/browse" ] && B="$_ROOT/.claude/skills/gstack/browse/dist/browse"
[ -z "$B" ] && B=~/.claude/skills/gstack/browse/dist/browse
If not found, fail with NEEDS_SETUP and instruct: run cd <skill-dir> && ./setup.
Verify gstack is healthy: $B status
Resolve target environment:
env=local: require frontend_local_urlenv=staging: require frontend_staging_urlenv=auto: prefer reachable frontend_local_url; if unreachable and fallback is enabled, use frontend_staging_urlEstablish target revision proof before browser validation:
env=local, prove the reachable target is serving code from the current worktree/reviewed SHA. Use frontend_local_revision_check_command when configured; otherwise inspect launch provenance/process context. If proof cannot be established, fail closed.env=staging, require frontend_staging_revision_check_command that proves the target URL is serving the reviewed SHA. If no such proof mechanism exists, fail closed instead of accepting staging as a current-SHA substitute.Fail closed if no reachable browser target exists.
gstack's browser persists cookies and sessions across calls. If the target requires authentication:
Check if already authenticated: $B goto <target_url> then $B url — if not redirected to a login page, auth is valid from a previous session.
If redirected to login:
$B snapshot -i to find form fields, then $B fill + $B click to log in.$B cookie-import-browser <browser> --domain <domain> to import from an existing browser session.frontend_test_email and frontend_test_password are configured in compound-engineering.local.md, use those.After login, verify: $B url should show the app, not the login page.
Auth persists for the gstack session lifetime (30 min idle timeout). Subsequent validation runs within the same session do not need to re-authenticate.
Choose 1-3 highest-risk URLs/flows from:
Selection rules:
target_url=<url> was supplied, use it.For each target flow, execute gstack commands directly via Bash:
# Navigate
$B goto "<target_url>"
# Capture baseline
$B screenshot /tmp/frontend-validate-<flow>.png
$B snapshot -i # interactive elements with @e refs
# Exercise the changed flow
$B click @eN # interact with changed elements
$B fill @eN "value"
$B snapshot -D # diff shows what changed
# Inspect for errors
$B console --errors # JS errors/warnings
$B network # failed requests
# Test refresh/rehydrate
$B reload
$B snapshot -D # verify state survives refresh
$B screenshot /tmp/frontend-validate-<flow>-refresh.png
# Verify session/auth continuity (when relevant)
$B url # still authenticated?
# Element assertions
$B is visible "<selector>"
$B is enabled "<selector>"
Collect results into structured findings:
screenshots: paths to captured screenshotsconsole_findings: errors/warnings from $B console --errorsnetwork_findings: failed requests from $B networkrefresh_resume_result: did state survive $B reload?session_result: did auth persist across navigation?blocking_findings: correctness-breaking issuesnon_blocking_findings: warnings, cosmetic issuesBefore returning PASS, re-resolve the current PR/branch head SHA. If it no longer matches the requested/current validation SHA, write a STALE artifact instead of PASS and instruct the caller to rerun on the new SHA.
If target revision proof is missing, mismatched, or cannot establish that the tested target is serving the reviewed SHA/current worktree, write FAIL instead of PASS.
Write to:
docs/reviews/frontend/pr-<number>-frontend-validate.md for PR-based runsdocs/reviews/frontend/YYYY-MM-DD-<branch>-<short-sha>-frontend-validate.md otherwiseIf a project overrides frontend_validation_command, the custom validator must still write the canonical PR artifact path above for PR-based runs so pr-review can consume the result.
Minimum sections:
Frontend validation is PASS only when:
Otherwise:
FAIL for open blockers or missing required validationSTALE if artifact SHA does not match current headN/A only when the change truly does not qualify or project policy explicitly disables this gateReturn:
PASS|FAIL|STALE|N/A)