name: gstack
version: 1.1.0
description: |
Fast headless browser for QA testing and site dogfooding. Navigate any URL, interact with
elements, verify page state, diff before/after actions, take annotated screenshots, check
responsive layouts, test forms and uploads, handle dialogs, and assert element states.
~100ms per command. Use when you need to test a feature, verify a deployment, dogfood a
user flow, or file a bug with evidence.
allowed-tools:
#gstack browse: QA Testing & Dogfooding
Persistent headless Chromium. First call auto-starts (~3s), then ~100-200ms per command.
Auto-shuts down after 30 min idle. State persists between calls (cookies, tabs, sessions).
#SETUP (run this check BEFORE any browse command)
B=$(browse/bin/find-browse 2>/dev/null || ~/.claude/skills/gstack/browse/bin/find-browse 2>/dev/null)
if [ -n "$B" ]; then
echo "READY: $B"
else
echo "NEEDS_SETUP"
fi
If NEEDS_SETUP:
- Tell the user: "gstack browse needs a one-time build (~10 seconds). OK to proceed?" Then STOP and wait.
- Run:
cd <SKILL_DIR> && ./setup
- If
bun is not installed: curl -fsSL https://bun.sh/install | bash
#IMPORTANT
- Use the compiled binary via Bash:
$B <command>
- NEVER use
mcp__claude-in-chrome__* tools. They are slow and unreliable.
- Browser persists between calls — cookies, login sessions, and tabs carry over.
- Dialogs (alert/confirm/prompt) are auto-accepted by default — no browser lockup.
#QA Workflows
#Test a user flow (login, signup, checkout, etc.)
B=~/.claude/skills/gstack/browse/dist/browse
# 1. Go to the page
$B goto https://app.example.com/login
# 2. See what's interactive
$B snapshot -i
# 3. Fill the form using refs
$B fill @e3 "test@example.com"
$B fill @e4 "password123"
$B click @e5
# 4. Verify it worked
$B snapshot -D # diff shows what changed after clicking
$B is visible ".dashboard" # assert the dashboard appeared
$B screenshot /tmp/after-login.png
#Verify a deployment / check prod
$B goto https://yourapp.com
$B text # read the page — does it load?
$B console # any JS errors?
$B network # any failed requests?
$B js "document.title" # correct title?
$B is visible ".hero-section" # key elements present?
$B screenshot /tmp/prod-check.png
#Dogfood a feature end-to-end
# Navigate to the feature
$B goto https://app.example.com/new-feature
# Take annotated screenshot — shows every interactive element with labels
$B snapshot -i -a -o /tmp/feature-annotated.png
# Find ALL clickable things (including divs with cursor:pointer)
$B snapshot -C
# Walk through the flow
$B snapshot -i # baseline
$B click @e3 # interact
$B snapshot -D # what changed? (unified diff)
# Check element states
$B is visible ".success-toast"
$B is enabled "#next-step-btn"
$B is checked "#agree-checkbox"
# Check console for errors after interactions
$B console
#Test responsive layouts
# Quick: 3 screenshots at mobile/tablet/desktop
$B goto https://yourapp.com
$B responsive /tmp/layout
# Manual: specific viewport
$B viewport 375x812 # iPhone
$B screenshot /tmp/mobile.png
$B viewport 1440x900 # Desktop
$B screenshot /tmp/desktop.png
#Test file upload
$B goto https://app.example.com/upload
$B snapshot -i
$B upload @e3 /path/to/test-file.pdf
$B is visible ".upload-success"
$B screenshot /tmp/upload-result.png
$B goto https://app.example.com/form
$B snapshot -i
# Submit empty — check validation errors appear
$B click @e10 # submit button
$B snapshot -D # diff shows error messages appeared
$B is visible ".error-message"
# Fill and resubmit
$B fill @e3 "valid input"
$B click @e10
$B snapshot -D # diff shows errors gone, success state
#Test dialogs (delete confirmations, prompts)
# Set up dialog handling BEFORE triggering
$B dialog-accept # will auto-accept next alert/confirm
$B click "#delete-button" # triggers confirmation dialog
$B dialog # see what dialog appeared
$B snapshot -D # verify the item was deleted
# For prompts that need input
$B dialog-accept "my answer" # accept with text
$B click "#rename-button" # triggers prompt
#Test authenticated pages (import real browser cookies)
# Import cookies from your real browser (opens interactive picker)
$B cookie-import-browser
# Or import a specific domain directly
$B cookie-import-browser comet --domain .github.com
# Now test authenticated pages
$B goto https://github.com/settings/profile
$B snapshot -i
$B screenshot /tmp/github-profile.png
#Compare two pages / environments
$B diff https://staging.app.com https://prod.app.com
#Multi-step chain (efficient for long flows)
echo '[
["goto","https://app.example.com"],
["snapshot","-i"],
["fill","@e3","test@test.com"],
["fill","@e4","password"],
["click","@e5"],
["snapshot","-D"],
["screenshot","/tmp/result.png"]
]' | $B chain
#Quick Assertion Patterns
# Element exists and is visible
$B is visible ".modal"
# Button is enabled/disabled
$B is enabled "#submit-btn"
$B is disabled "#submit-btn"
# Checkbox state
$B is checked "#agree"
# Input is editable
$B is editable "#name-field"
# Element has focus
$B is focused "#search-input"
# Page contains text
$B js "document.body.textContent.includes('Success')"
# Element count
$B js "document.querySelectorAll('.list-item').length"
# Specific attribute value
$B attrs "#logo" # returns all attributes as JSON
# CSS property
$B css ".button" "background-color"
#Snapshot System
The snapshot is your primary tool for understanding and interacting with pages.
-i Interactive elements only (buttons, links, inputs) with @e refs
-c Compact (no empty structural nodes)
-d <N> Limit depth
-s <sel> Scope to CSS selector
-D Diff against previous snapshot (what changed?)
-a Annotated screenshot with ref labels
-o <path> Output path for screenshot
-C Cursor-interactive elements (@c refs — divs with pointer, onclick)
Combine flags: $B snapshot -i -a -C -o /tmp/annotated.png
After snapshot, use @refs everywhere:
$B click @e3 $B fill @e4 "value" $B hover @e1
$B html @e2 $B css @e5 "color" $B attrs @e6
$B click @c1 # cursor-interactive ref (from -C)
Refs are invalidated on navigation — run snapshot again after goto.
#Command Reference
#Navigation
| Command |
Description |
back |
History back |
forward |
History forward |
goto <url> |
Navigate to URL |
reload |
Reload page |
url |
Print current URL |
#Reading
| Command |
Description |
accessibility |
Full ARIA tree |
forms |
Form fields as JSON |
html [selector] |
innerHTML |
links |
All links as "text → href" |
text |
Cleaned page text |
#Interaction
| Command |
Description |
click <sel> |
Click element |
cookie |
Set cookie |
cookie-import <json> |
Import cookies from JSON file |
cookie-import-browser [browser] [--domain d] |
Import cookies from real browser (opens picker UI, or direct with --domain) |
dialog-accept [text] |
Auto-accept next alert/confirm/prompt |
dialog-dismiss |
Auto-dismiss next dialog |
fill <sel> <val> |
Fill input |
header <name> <value> |
Set custom request header |
hover <sel> |
Hover element |
press <key> |
Press key (Enter, Tab, Escape, etc.) |
scroll [sel] |
Scroll element into view |
select <sel> <val> |
Select dropdown option |
type <text> |
Type into focused element |
upload <sel> <file...> |
Upload file(s) |
useragent <string> |
Set user agent |
viewport <WxH> |
Set viewport size |
| `wait <sel |
--networkidle |
--load>` |
Wait for element/condition |
#Inspection
| Command |
Description |
| `attrs <sel |
@ref>` |
Element attributes as JSON |
| `console [--clear |
--errors]` |
Console messages (--errors filters to error/warning) |
cookies |
All cookies as JSON |
css <sel> <prop> |
Computed CSS value |
dialog [--clear] |
Dialog messages |
eval <file> |
Run JS file |
is <prop> <sel> |
State check (visible/hidden/enabled/disabled/checked/editable/focused) |
js <expr> |
Run JavaScript |
network [--clear] |
Network requests |
perf |
Page load timings |
storage [set k v] |
localStorage + sessionStorage |
#Visual
| Command |
Description |
diff <url1> <url2> |
Text diff between pages |
pdf [path] |
Save as PDF |
responsive [prefix] |
Mobile/tablet/desktop screenshots |
screenshot [path] |
Save screenshot |
#Snapshot
| Command |
Description |
snapshot [flags] |
Accessibility tree with @refs |
| Command |
Description |
chain |
Multi-command from JSON stdin |
#Tabs
| Command |
Description |
closetab [id] |
Close tab |
newtab [url] |
Open new tab |
tab <id> |
Switch to tab |
tabs |
List open tabs |
#Server
| Command |
Description |
restart |
Restart server |
status |
Health check |
stop |
Shutdown server |
#Tips
- Navigate once, query many times.
goto loads the page; then text, js, screenshot all hit the loaded page instantly.
- Use
snapshot -i first. See all interactive elements, then click/fill by ref. No CSS selector guessing.
- Use
snapshot -D to verify. Baseline → action → diff. See exactly what changed.
- Use
is for assertions. is visible .modal is faster and more reliable than parsing page text.
- Use
snapshot -a for evidence. Annotated screenshots are great for bug reports.
- Use
snapshot -C for tricky UIs. Finds clickable divs that the accessibility tree misses.
- Check
console after actions. Catch JS errors that don't surface visually.
- Use
chain for long flows. Single command, no per-step CLI overhead.