Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
zerodom_parse_urlA

Navigate to a URL and return its interaction graph.

Returns the compact text graph: [03] button 'Sign In'. CSS selectors are kept server-side and resolved by node id, so they never cost context — pass verbose=True for the full JSON including selectors. Nodes sharing a repeated-list-item ancestor (<article>/<li>/<tr>, e.g. a feed or Hacker-News-style table) are grouped under @card "title": whenever a card holds 2+ controls — twenty identical button 'Upvote' lines are meaningless without knowing which story each belongs to.

Set frames=True when the controls you need are inside an iframe — embedded editors, payment fields, consent gates. Off by default because it costs a read per frame and most frames on a commercial page are advertising.

Set viewport_only=True on long feed/infinite-scroll pages (a social feed, a video site's homepage) where most of the graph is scrolled off-screen and you only need what's currently visible — this can cut node count by more than half on pages like that. On by default for interactive agents; costs a getBoundingClientRect() per element. Sticks for the rest of this session (every click/fill re-read honors it too) until the next zerodom_parse_url call changes it — same lifetime as frames. When nodes are being skipped, the graph's first line says how many; scroll and re-read to see them.

Set check_occlusion=True when clicks keep failing with Playwright's "element intercepts pointer events" — a modal backdrop, an open dropdown, or a cookie banner is covering nodes that are still in the DOM and still listed. This filters them out at parse time instead of at click time, same sticky-for-the-session lifetime as viewport_only. Off by default: the cost of an elementFromPoint() hit-test per node on a large page is unmeasured, so it isn't imposed on every caller by default.

zerodom_read_pageA

Re-read the current page without navigating.

Use after an action changed the page, or when node ids look stale. Unlike zerodom_parse_url this does not reload, so anything typed into the page stays. Honors whatever frames/viewport_only/check_occlusion zerodom_parse_url last set.

zerodom_findA

Search the current page's graph for nodes matching query.

Case-insensitive substring match over each node's label and type. Prefer this over re-reading the whole page when you already know what you are looking for: "checkout" costs three lines, the full graph costs every node on the page.

zerodom_hidden_fieldsA

List hidden <input type="hidden"> fields on the current page.

Hidden inputs are deliberately NOT graph nodes — an agent acting on a page has no reason to click them, so listing them as nodes would be noise. But they carry the payload a form submission needs (CSRF tokens, per-view state like a draft id or a sort order), which is exactly what an agent re-submitting a POST after a stale parse is missing. Returns each field's name, value and CSS selector, so the values can be fed straight into a zerodom_fill_node call if the target form expects them.

zerodom_crawlA

BFS-walk an app's in-scope routes and return one JSONL record per page: final URL, forms, in-scope links, the XHR/fetch API calls it fired, hidden fields, and blocked when the route is a challenge interstitial.

Recon, not action: it navigates and reads, never clicks or submits. A link matching deny (logout/delete/… default) is never followed; a blocked route is recorded but not descended into; session scope (zerodom_set_scope) is enforced per navigated URL, including its max_rps rate limit. Runs in the active tab, so on an attached session the walk resolves authenticated routes the way the human's own Chrome does (CLI: zerodom crawl --relay). scope adds extra in-scope hosts (comma-separated, beside the start URL's host); deny overrides the link-follow regex. The crawl leaves the active tab on the last crawled page and re-reads the graph to match — call zerodom_read_page to see it.

zerodom_scanA

Run zerodom's surface rules over the ACTIVE page and return findings as JSONL: the interaction-graph rules, DOM-XSS sinks and the callable API surface (method + body shape) read from the page's same-origin JS (js=True), and CSP/CORS response-header posture. Recon over the page you are on — navigate first with zerodom_parse_url. (Cookie-flag and CSRF correlation are CLI zerodom scan only: a page cannot read its own Set-Cookie header.)

zerodom_repeatB

Send one request over the active authenticated session (in-page fetch) and return {status, body} — the Repeater for crafting or verifying a request by hand, e.g. replaying a crawl-discovered POST with a tweaked body.

zerodom_raceA

Fire a concurrent burst over the active session — the TOCTOU probe, run as the browser's own multiplexed fetch (the tightest client-side engine). bodies is one or more request bodies, each fired n times and interleaved (a mix of operations on one record widens a read-modify-write window); setup is a list of prep requests [{url|path, method?, body?}]; check is a URL GET-ed after the burst. Returns the status spread, per-body breakdown, and a race-condition finding when a single-use action over-applies.

zerodom_probeA

Replay an endpoint with a tampered body over the active session and diff vs baseline — the mass-assignment / tampering check. tamper (JSON) is merged over body; an injected field accepted (2xx) and reflected in the tampered response but absent from baseline is flagged. Returns baseline/tampered responses and any finding.

zerodom_click_nodeA

Click a node and return what changed on the page.

Returns a diff — + appeared, - gone, ~ value changed — because most clicks alter a handful of nodes and re-listing the page would cost hundreds. A navigation renumbers everything, so that returns the full graph instead.

A same-page click reporting "no structural change" shortly after navigation is ambiguous — could be a real no-op, could be a server- rendered control (Next.js/Remix/Nuxt) whose framework hasn't finished attaching its handler yet. Flagged, not retried automatically: a false retry risks a real double-submit on a control that did fire. Suppressed when the click triggered a network request even without a DOM change yet — an in-flight fetch/GraphQL mutation (auth actions routinely take 800ms-2s to resolve) is itself evidence the handler did fire, just hasn't finished.

zerodom_fill_nodeA

Type text into a node and return what changed on the page.

The text is echoed back in the first line; the diff below it reports structural change — a validation error appearing, an autocomplete list opening.

zerodom_hoverA

Hover over a node and return what changed on the page.

Reveals hover-triggered menus and tooltips — content that a click alone would never surface, and that isn't in the graph until this fires.

zerodom_press_keyA

Press a key while a node is focused and return what changed.

key uses Playwright's key names ("Enter", "Escape", "Tab", "ArrowDown", ...). For "press Enter to submit" forms, "Escape to close a modal", and keyboard-only widgets a click/fill can't drive.

zerodom_upload_fileA

Set a file input's value to a local file path and return what changed.

path is resolved on the machine driving the browser — the same trust boundary as zerodom_eval_js, not a new one.

zerodom_dragA

Drag source onto target and return what changed.

Drag-to-reorder lists, drag-and-drop upload zones, sliders — anything a click/fill pair can't express because the gesture itself is the input.

zerodom_scrollA

Scroll the page and return what's newly visible.

direction: "up" or "down". amount: pixels, roughly one screenful is 800. Dispatches a real wheel event at the viewport center rather than window.scrollBy, so it scrolls whatever scrollable container is actually under the cursor — a nested feed/sidebar, not just the document body, matching what a real scroll gesture would do.

zerodom_new_tabA

Open a new tab and make it the active one — every other tool (read, click, fill, scroll) then acts on it until you zerodom_switch_tab away.

In an attached (real-browser) session the new tab lands in the same "zerodom" tab group as every other tab this session touches.

zerodom_list_tabsA

List every open tab, marking the active one with *.

zerodom_switch_tabA

Make another open tab active and return its interaction graph.

Node ids are per-tab, so re-read (this returns the graph already) before clicking or filling anything on the tab you just switched to.

zerodom_close_tabA

Close a tab — the active one by default. Refuses to close the last tab.

zerodom_screenshotA

Full-page screenshot of the active tab, saved to disk; returns the path.

report.py has a screenshot path already, but it's wired to the CLI's own throwaway sync browser (playwright_wrapper.py's sync/async split), not this attached async session — this is that same capability for here. Pass path to choose where it's saved; omitted, a temp file is used.

zerodom_set_viewportA

Resize the active tab's viewport for responsive-design testing.

Not the real browser window — that's zerodom_resize_window. This is Emulation.setDeviceMetricsOverride: the page's own rendered layout at a given width, without touching the chrome around it. Use this one for "how does this render at width X"; use zerodom_resize_window for an actually different-sized window on screen.

zerodom_resize_windowA

Resize the real browser window (not just the page's viewport).

chrome.debugger's CDP surface has no browser-level window-management grant, but chrome.windows.update is a plain extension API, entirely unrelated to chrome.debugger — so this genuinely works despite that. Sent as Browser.setWindowBounds (a real CDP method name Playwright's own driver will actually transmit — a made-up method name gets rejected client-side before reaching the relay at all) and repurposed server-side; see docs/DECISIONS.md D16. Only meaningful for an attached (real-browser) session; a launched headless session has no window to resize.

On a tiling window manager (i3/sway/Hyprland/bspwm-style setups), this call succeeds but the window won't visibly move or resize — on Wayland compositors specifically this isn't a WM being uncooperative, it's the protocol itself: clients are deliberately not allowed to force their own geometry. Works normally on a floating window. Confirmed live on Hyprland.

zerodom_get_stylesA

Computed styles and box-model dimensions for a node — for design/CSS review, not just interaction.

Runs getComputedStyle() in the real page over the same chrome.debugger connection everything else here uses (also reachable ad hoc via zerodom_eval_js; this is the purpose-built version with a curated property list instead of getComputedStyle()'s full ~300-property dump).

zerodom_get_cookiesA

List cookies visible to the active tab's origin.

Reads via CDP's Network domain (Playwright's context.cookies()), which sees httpOnly cookies too — unlike a content script's document.cookie, which httpOnly exists specifically to hide them from.

zerodom_get_storageA

List localStorage and sessionStorage keys the active tab's page holds.

Session state that never touches the network — an issued draft id, a collapsed sidebar preference, a half-typed form — lives here. Same trust boundary as zerodom_eval_js (page context), but purpose-built and read-only, so it returns keys + values without the power of the eval tool. Values that look like a JWT (three base64url segments) get their claims (sub/role/exp/iss/aud) decoded into a second line.

zerodom_eval_jsA

Run arbitrary JavaScript in the active tab's real page context and return the result — Runtime.evaluate over the same chrome.debugger connection everything else here uses, the same power as typing into DevTools' own console.

zerodom_network_logA

Requests/responses the active tab has made since it opened (or since this was last called with clear=True) — method or status, and URL.

Passive visibility only, capped at the most recent 200 entries — not interception or modification of traffic (that needs page.route(), a bigger, stateful feature; zerodom_eval_js can already override window.fetch/XMLHttpRequest from the page side for ad hoc cases).

zerodom_set_scopeA

Constrain the hunt to authorized targets — enforced in code, not on trust.

hosts: comma-separated in-scope host globs (app.example.com,*.example.com). Navigation, replay and clicks to any other host are then refused. deny: a regex of destructive URLs/labels to refuse (default covers logout/delete/ remove/deactivate/revoke) so an unattended agent can't take an irreversible action. max_rps: throttle to at most N requests/second (program rate limits).

An operator can instead lock scope before the agent starts by setting the ZERODOM_SCOPE env var to a YAML file; a locked scope can't be widened here.

zerodom_create_groupA

Create a named, colored tab group the agent is sandboxed to, and make it the target for new tabs. Persists across a browser restart (stored by the extension).

Once any agent group exists the agent may ONLY drive tabs inside its groups — attaching to any other tab is refused. color is a Chrome tab-group color: grey, blue, red, yellow, green, pink, purple, cyan or orange. Relay mode only (the extension drives your real Chrome).

zerodom_list_groupsA

List the agent's named tab groups (its sandbox), as remembered across restarts. No groups → the sandbox is off and the agent can drive any tab.

zerodom_use_groupA

Make name the active group — subsequent new tabs join it.

zerodom_close_groupB

Close an agent group: ungroup its tabs and forget it. If it was the last one, the sandbox turns off (the agent can drive any tab again).

zerodom_adopt_groupB

Hand an existing Chrome tab group (that you created yourself, by title) to the agent: it joins the agent's sandbox and becomes the active group. Lets you pre-arrange tabs and then scope the agent to exactly them.

zerodom_restore_groupsA

Reopen the remembered tabs of every agent group (best-effort) after a browser restart, re-grouping them under their saved name and color. A tab whose URL now hits a login wall or is otherwise unreachable is skipped, not fatal.

zerodom_add_identityA

Register a second identity (e.g. user B) for cross-tenant IDOR testing.

storage_state is a Playwright storage_state JSON file (cookies + origins) — capture one per account. header is an optional extra request header ('Authorization: Bearer …') for token-auth APIs, repeatable via comma isn't supported; call again to add more. The current logged-in session is always available as identity 'live' without registering.

Once two identities exist, zerodom_compare_identities(url) fetches the same URL as each and flags a byte-identical response — the cross-tenant IDOR tell.

zerodom_replayA

Replay an HTTP request under a chosen identity — Burp Repeater for the agent.

Sends method url (with optional body and one extra header 'K: V') through as_identity (default the live logged-in session). Returns the response status, size and a body preview. Use it to probe an endpoint, tamper with a request, or check an object reference — then change the id/body and replay again. Pair with zerodom_compare_identities for the A-vs-B diff.

zerodom_compare_identitiesA

Fetch one URL as each identity and diff — the cross-tenant IDOR check.

Sends method url through every identity in identities (default: the live session plus every registered one) and reports each response's status and size. A byte-identical response under two identities on a per-user resource is a cross-tenant IDOR. The live identity leaves through Chrome's own network stack (in-page fetch), so a fingerprinting WAF sees your real browser there; registered identities go through Playwright's HTTP client — cookies included, Chrome's TLS fingerprint not.

zerodom_statusA

Diagnose the current connection: relay reachability, whether a browser session is attached yet, which tab is active, and the tail of the relay's own log — the single-call version of the manual WebSocket-probing and log- tailing this project's own debugging needed before this tool existed.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.6/5.0

Scored across 39 tools

Disambiguation3/5

Most tools are well differentiated by their descriptions (parse_url vs read_page vs find, set_viewport vs resize_window are explicitly contrasted). However, zerodom_repeat ('send one request over the active session') and zerodom_replay ('replay an HTTP request under a chosen identity') are near-duplicates that an agent could easily misselect, and the probe/race/compare_identities cluster requires careful reading to separate. Overlap exists but the verbose descriptions mostly rescue it.

Naming Consistency4/5

All 39 tools share the zerodom_ prefix and mostly follow a verb_noun pattern (click_node, fill_node, switch_tab, close_group, compare_identities). Minor deviations exist: bare-verb tools (scan, crawl), noun-only names (status, screenshot, hidden_fields), and a get_ prefix subset (get_styles, get_cookies, get_storage) mixed with direct verbs like network_log.

Tool Count2/5

39 tools is well past the comfortable range, and while the domain is broad, several clusters could be consolidated — six tab-group tools, four tab tools, and five overlapping HTTP-replay/security tools could each collapse into a single parameterized tool. The surface is genuinely large but not all of it earns a distinct endpoint.

Completeness4/5

The surface is unusually thorough: interaction (click/fill/hover/drag/press/upload/scroll), navigation, tab and group management, and a deep security recon set (scan, crawl, repeat, race, probe, replay, compare_identities, set_scope). Gaps are minor but real: no explicit wait_for or select-option tool for native <select>, and cookie/storage are read-only with network interception explicitly absent.

Maintenance

ActivityActive
ResponsivenessUnresponsive