All skills
garrytan avatar

/browse

@dcaea52 official
by Garry Tangarrytan/gstack135k stars
20,051

Drive a real browser through Aside: open a page, read it, click through a flow, take screenshots, check console errors. (gstack)

Use this Skill: https://skilld.dev/gh/garrytan/gstack/browse

This session only. Nothing lands on disk.

PLAN-snapshot-dropdown-interactive.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Plan: Snapshot Dropdown/Autocomplete Interactive Element Detection

Problem

snapshot -i misses dropdown/autocomplete items on modern web apps. These elements:

  1. Are often <div>/<li> with click handlers but no semantic ARIA roles
  2. Live inside dynamically-created portals/popovers (floating containers)
  3. Don't appear in Playwright's accessibility tree (ariaSnapshot())

The -C flag (cursor-interactive scan) was designed for this but:

  • Requires separate flag — agents using -i don't get it automatically
  • Skips elements that HAVE an ARIA role (even if the ARIA tree missed them)
  • Doesn't prioritize popover/portal containers where dropdown items live

Root Cause

Playwright's ariaSnapshot() builds from the browser's accessibility tree. Dynamically-rendered popovers (React portals, Radix Popover, etc.) may not be in the accessibility tree if:

  • The component doesn't set ARIA roles
  • The portal renders outside the scoped body locator's subtree timing
  • The browser hasn't updated the accessibility tree yet after DOM mutation

Changes

1. Auto-enable cursor-interactive scan with -i flag

File: browse/src/snapshot.ts

When -i (interactive) is passed, automatically include the cursor-interactive scan. This means agents always see clickable non-ARIA elements when they ask for interactive elements.

The -C flag remains as a standalone option for non-interactive snapshots.

if (opts.interactive) {
  opts.cursorInteractive = true;
}

2. Add popover/portal priority scanning

File: browse/src/snapshot.ts (inside cursor-interactive evaluate block)

Before the general cursor:pointer scan, specifically scan for visible floating containers (popovers, dropdowns, menus) and include ALL their direct children as interactive:

Detection heuristics for floating containers:

  • position: fixed or position: absolute with z-index >= 10
  • Has role="listbox", role="menu", role="dialog", role="tooltip", [data-radix-popper-content-wrapper], [data-floating-ui-portal], etc.
  • Appeared recently in the DOM (not in initial page load)
  • Is visible (offsetParent !== null or position: fixed)

For each floating container, include child elements that:

  • Have text content
  • Are visible
  • Have cursor:pointer OR onclick OR role="option" OR role="menuitem"
  • Tag with reason popover-child for clarity

3. Remove the hasRole skip in cursor-interactive scan

File: browse/src/snapshot.ts

Currently: if (hasRole) continue; — skips any element with an ARIA role, assuming the ARIA tree already captured it.

Problem: if the ARIA tree MISSED the element (timing, portal, bad DOM structure), it falls through both systems.

Fix: Only skip if the element's role is in INTERACTIVE_ROLES AND it was actually captured in the main refMap. Otherwise include it.

Since we can't easily check the refMap from inside page.evaluate(), the simpler fix: remove the hasRole skip entirely for elements inside detected floating containers. For elements outside floating containers, keep the hasRole skip as-is (to avoid duplicates in normal page content).

4. Add dropdown test fixture and tests

File: browse/test/fixtures/dropdown.html

HTML page with:

  • A combobox input that shows a dropdown on focus/type
  • Dropdown items as <div> with click handlers (no ARIA roles)
  • Dropdown items as <li> with role="option"
  • A React-portal-style container (position: fixed, high z-index)

File: browse/test/snapshot.test.ts

New test cases:

  • snapshot -i on dropdown page finds dropdown items via cursor scan
  • snapshot -i on dropdown page includes popover-child elements
  • @c refs from dropdown scan are clickable
  • Elements inside floating containers with ARIA roles are captured even when ARIA tree misses them

Rollout Risk

Low. The -C scan is additive — it only adds @c refs, never removes @e refs. The change to auto-enable it with -i increases output size but agents already handle mixed ref types.

One concern: The -C scan queries ALL elements (document.querySelectorAll('*')) which can be slow on heavy pages. For the popover-specific scan, we limit to elements inside detected floating containers, which is fast (small subtree).

Testing

cd /data/gstack/browse && bun test snapshot

Files Changed

  1. browse/src/snapshot.ts — auto-enable -C with -i, popover scanning, remove hasRole skip in floating containers
  2. browse/test/fixtures/dropdown.html — new test fixture
  3. browse/test/snapshot.test.ts — new dropdown/popover test cases

Source: SKILL.md on GitHub

3 warnings2d4 checks · Risk SAFE
  • Gen Agent Trust Hub2d

    The 'browse' skill (gstack) provides a highly secure interface for browser automation. It features a robust security architecture including multi-layered prompt injection defenses, strict path and URL validation to prevent data exfiltration, and a least-privilege access model using scoped tokens and a default-deny CDP allowlist. The skill is designed to drive either a user's real browser (Aside) or a headless fallback ($B) while maintaining high security standards.

  • Socket2d

    8 alerts: gptAnomaly, gptSecurity

  • Snyk2d

    Risk: MEDIUM · 1 issue

  • ZeroLeaks5mo

    2 findings · Score: 71/100

Signed by skilld at dcaea52. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 17 hours ago.

Activeupdated 2 days ago
What it can do
Runs commands Reads files
preamble-tier
1
version
2.0.0
triggers
[
  "browse a page",
  "open this url",
  "take page screenshot"
]
All 3 allowed tools
BashReadAskUserQuestion
  • Testing
  • headless-browser
  • qa
  • web-automation
  • screenshot
  • interactive

README badge

README badge for garrytan/gstack/browse

Automates headless browsing for QA testing and site verification. Navigate any URL, interact with page elements, take screenshots, test forms, and assert element state — all with ~100ms command latency. Use it to dogfood user flows, verify deployments, or file bug reports with evidence.

Generated from the current SKILL.md.

What can I do with this skill?
Navigate URLs, interact with page elements, take screenshots, verify page state, test forms and uploads, handle dialogs, and check responsive layouts. Typical operations complete in ~100ms.
When should I invoke the browse skill?
Use it to test a feature, verify a deployment, dogfood a user flow, or file a bug with evidence. Invoke when asked to open a browser, test a site, take a screenshot, or dogfood a workflow.
What are the system requirements?
The skill requires Bash, Read, and AskUserQuestion tools to be available. It manages its own sessions and dependencies via the gstack binary.

Generated from the current SKILL.md. These answers refresh after source changes.