npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@subtextdev/subtext-cli

v0.8.2

Published

CLI and SDK for Subtext — FullStory's agent browser testing tool

Downloads

3,048

Readme

@subtextdev/subtext-cli

Browser automation that knows your app. Subtext gives AI agents semantic understanding of your UI through sightmaps — project-specific component definitions that make agents measurably better at working with your application.

Two Modes

| | Local Mode | Hosted Mode | |---|---|---| | How | Headless Playwright on your machine | Cloud browser via API | | Setup | npx @subtextdev/subtext-cli --mcp | Set SUBTEXT_API_KEY | | Best for | Autonomous testing, CI, benchmarking | Collaborative visual QA, live sharing | | Tools | 57 tools (all local + shared) | 33 tools (shared + comments/review) | | Dependencies | Playwright (~150MB, auto-installed) | None (HTTP calls) |

No API key = local mode. Set SUBTEXT_API_KEY for hosted mode.

Most of this README focuses on local mode, which includes assertions, evidence bundles, macro authoring, and sightmap bootstrapping. Hosted mode adds live viewer URLs, session comments, and session review — see Hosted Mode at the bottom.


Quick Start (Local Mode)

As an MCP Server (for AI agents)

Add to your MCP config (Claude Code, Cursor, etc.):

{
  "mcpServers": {
    "subtext": {
      "command": "npx",
      "args": ["@subtextdev/subtext-cli", "--mcp"]
    }
  }
}

The agent gets 57 tools. It connects to a URL, sees a sightmap-enriched component tree, and interacts using component names instead of CSS selectors.

As a CLI

npm install -g @subtextdev/subtext-cli

subtext connect http://localhost:3000
subtext snapshot <connection_id>
subtext click <connection_id> LoginButton
subtext fill <connection_id> EmailInput [email protected]
subtext disconnect <connection_id>

CLI commands auto-start a persistent background server — the browser stays alive across invocations. No setup needed. The server idles out after 5 minutes of inactivity.

For explicit control: subtext serve (foreground with logs), subtext serve --daemon, subtext serve stop.

Run subtext --help for the full command reference.


Breaking Changes in v0.8.0

Local MCP tool parameter names now match hosted MCP. If you call tools via subtext raw <tool> '{...}', directly over MCP, or from agent code that constructs MCP payloads, you need to update the parameter names below. CLI subcommands (subtext click <id>, subtext fill <id> <value>, etc.) are unchanged — only the underlying MCP tool params were renamed.

| Tool(s) | Old param | New param | |---|---|---| | live-act-click, live-act-hover, live-act-fill, live-act-keypress, live-act-drag, live-act-upload, live-act-scroll, live-act-select, live-act-check, live-act-uncheck, live-act-dblclick, live-act-focus | component | component_id | | live-act-drag | offset_x, offset_y | delta_x, delta_y | | live-act-upload | files | file_path | | live-act-wait-for | component | selector | | live-eval-script | script | expression | | live-net-list | pattern | url_pattern | | live-act-fill (multi-field mode) | fields[].component | fields[].component_id |

Unchanged (still use component):

  • Assertion tools — assert-visible, assert-value, assert-count (local-only)
  • Macro tools — macro, macro-mark, macro-record, macro-save (local-only)
  • Macro step action items within macro definitions

Agents and tooling calling via subtext raw or MCP clients must update their param names to match. Example:

# Before v0.8.0
subtext raw live-act-click '{"connection_id":"c1","component":"LoginButton"}'

# v0.8.0+
subtext raw live-act-click '{"connection_id":"c1","component_id":"LoginButton"}'

Why Subtext

Generic browser tools see raw DOM. Subtext sees your components.

Agent + Playwright MCP:  "Click the button with class .btn-primary"
Agent + Subtext:         "Click LoginButton"  (sightmap-enriched)

A sightmap teaches agents what your UI means: "this is the LoginButton," "fill EmailInput then press Enter," "hover the row before clicking Delete." The result is fewer errors, fewer turns, and verifiable proof that the workflow completed correctly.

What You Get

  • Sightmap-enriched snapshots — Accessibility tree annotated with component names, memory hints, and interaction tips
  • 42 MCP tools — Connect, interact, assert, verify, and generate evidence bundles
  • Assertion toolsassert-text, assert-url, assert-visible, assert-value, assert-count, assert-network with polling, timeout, and screenshot-on-fail
  • Evidence bundles — Portable proof directories with screenshots, snapshots, action logs, assertion results, network captures, and a quality score
  • Verify & replay — Re-run an evidence bundle to confirm assertions still pass
  • Macro authoring — Record, parameterize, and save reusable action sequences from live sessions
  • Sightmap bootstrap — Auto-generate a skeleton sightmap from any live URL
  • Structured errors — Categorized error responses with suggestions, not stack traces

Component Resolution

Every interaction tool accepts a component_id parameter (see Breaking Changes in v0.8.0 — previously component). Three resolution strategies, tried in order:

  1. Sightmap name"LoginButton", "EmailInput". Defined in .sightmap/*.yaml. Best: stable, semantic.
  2. UID"e55". From snapshot output (uid=e55). Ephemeral — valid until next snapshot. Good for exploration.
  3. CSS selector"button.btn-primary". Fallback when no sightmap or UID available.

Prefer sightmap names when available. Use UIDs for quick exploration. CSS selectors as a last resort.

Note: Assertion tools (assert-visible, assert-value, assert-count) and macro tools still use the component parameter name. Only the live-act-* and a few other live tools were renamed in v0.8.0.


Sightmaps

A sightmap is a .sightmap/*.yaml file that defines your app's components. Subtext auto-discovers it by walking up from the working directory.

version: 1

memory:
  - "Fill input, press Enter or click Add to create a todo."
  - "Hover a todo item to reveal the Delete button."

components:
  - name: TodoApp
    selector: ".todo-app"
    source: components/TodoApp.tsx
    description: Root container for the Todo application.
    children:
      - name: NewTodoInput
        selector: ".new-todo"
        memory:
          - "Fill text, press Enter to add. Input clears automatically."
      - name: AddButton
        selector: ".add-btn"
        memory:
          - "Disabled when input empty."
      - name: TodoItem
        selector: ".todo-item"
        memory:
          - "Checkbox toggles done. Delete only visible on hover."

views:
  - name: TodoList
    route: "/todos"
    description: Main view. Load scenarios via ?scenario= URL param.

Bootstrap a Sightmap

Don't want to write YAML by hand? Bootstrap one from a live page:

subtext sightmap init https://myapp.com -o .sightmap/app.yaml

This crawls the page, extracts interactive elements from the accessibility tree, and generates a skeleton sightmap. Review and refine the output — add memory hints for complex interactions.


MCP Tools (Local Mode)

Connection & Navigation

| Tool | Description | |------|-------------| | live-connect | Launch browser, navigate to URL, return enriched snapshot. Waits for network+DOM stability by default. Pass storage_state to restore session (cookies, localStorage, IndexedDB). Pass init_scripts to inject JS before page load (MSW, mocks, flags). | | live-disconnect | Close browser and free resources. Pass save_storage to save session state (cookies, localStorage, IndexedDB) for later re-use. | | live-view-navigate | Navigate to a new URL | | live-view-back | Go back in browser history | | live-view-forward | Go forward in browser history | | live-view-reload | Reload the current page |

Inspection

| Tool | Description | |------|-------------| | live-view-snapshot | Screenshot + sightmap-enriched component tree (UIDs are ephemeral — valid until next snapshot) | | live-view-screenshot | Screenshot only (PNG) |

Interaction

| Tool | Description | |------|-------------| | live-act-click | Click a component | | live-act-dblclick | Double-click a component | | live-act-fill | Fill text input (single or multi-field) | | live-act-select | Select an option from a dropdown (<select>) by value, label, or index | | live-act-check | Check a checkbox or radio button | | live-act-uncheck | Uncheck a checkbox | | live-act-hover | Hover over a component | | live-act-focus | Focus a component without clicking | | live-act-keypress | Press a keyboard key | | live-act-scroll | Scroll page or element (direction + amount, or scroll component into view) | | live-act-drag | Drag a component by pixel offset | | live-act-wait-for | Wait for visibility, URL, or load state | | live-act-dialog | Accept or dismiss browser dialogs | | live-act-upload | Upload files to a file input |

All interaction tools return lightweight confirmations (~15 tokens), not full snapshots. Batch multiple actions per turn for efficiency — only call live-view-snapshot when you need to verify state.

Assertions

| Tool | Description | |------|-------------| | assert-text | Verify text is visible on page | | assert-url | Verify current URL matches or contains substring | | assert-visible | Verify a component is visible | | assert-value | Verify an input field's value | | assert-count | Verify number of matching elements | | assert-network | Verify a network request was made |

All assertion tools poll with configurable timeout (default 5s), return structured PASS/FAIL verdicts, and capture a screenshot on failure. Use assertions instead of eyeballing snapshots — they're faster, produce structured output, and feed into evidence bundles.

Evidence & Verification

| Tool | Description | |------|-------------| | report | Package evidence bundle (screenshots, snapshots, logs, manifest with quality score) | | verify | Replay a bundle — re-run actions and assertions, report divergences | | extract | Convert a bundle into a replayable macro with auto-parameterization |

Macro Engine

| Tool | Description | |------|-------------| | macro | Execute a sequence of actions with {{param}} substitution | | macro-mark | Set recording start point ("macro starts here") | | macro-record | Capture actions since mark as a named macro with auto-parameterized values | | macro-save | Persist macro to .sightmap/macros.yaml and optionally to a JSON file |

Macro steps: navigate, click, fill, keypress, hover, wait_for, snapshot, dialog, eval_script.

Recording flow: explore the app → macro-mark → drive the clean path → macro-record → review steps → macro-save.

Sightmap Tools

| Tool | Description | |------|-------------| | sightmap-init | Auto-generate skeleton sightmap YAML from a live URL (standalone, launches its own browser) | | sightmap-init-from-session | Bootstrap sightmap from an active connection (no extra browser launch) | | sightmap-bootstrap | Analyze current page DOM and generate sightmap components | | sightmap-update | Detect broken selectors, propose fixes, discover new elements |

Debugging & Inspection

| Tool | Description | |------|-------------| | live-view-inspect | Full DOM tree with CSS selectors (for sightmap authoring — expensive, use sparingly) | | live-eval-script | Execute JavaScript in the page context | | live-log-list | List captured console messages | | live-log-get | Get console message details | | live-net-list | List captured network requests | | live-net-get | Get network request/response details |

Sessions

| Tool | Description | |------|-------------| | session-save | Save current session (cookies, localStorage, IndexedDB) under a named profile | | session-restore | Get file path for a saved session profile (pass to connect's storage_state) | | session-list | List all saved session profiles |

Downloads

| Tool | Description | |------|-------------| | download-list | List file downloads captured during the session | | download-save | Save a captured download to a specified file path |

View Management

| Tool | Description | |------|-------------| | live-view-new | Open a new tab | | live-view-list | List all open tabs | | live-view-select | Switch active tab | | live-view-close | Close a tab | | live-view-resize | Resize viewport | | live-emulate | Emulate device (mobile: 375x667, tablet: 768x1024, desktop: 1280x720) |


Evidence Bundles

The report tool packages everything from a session into a portable directory:

my-test/
  manifest.json       # Metadata, summary, evidence score (0-100)
  report.md           # Human-readable narrative with tables and screenshots
  001-final.png       # Screenshots
  snapshot-final.txt  # Sightmap-enriched component tree
  actions.jsonl       # Every action with timing
  assertions.jsonl    # Every assertion with pass/fail
  network.jsonl       # Network requests
  console.jsonl       # Console messages

Verify a Bundle

Re-run the actions and assertions to confirm results still match:

subtext verify ./my-test/
# Verify: ./my-test/
# Assertions: 5 total, 5 passed, 0 diverged
# Result: PASS

Extract a Macro

Convert a session into a reusable macro with auto-parameterized values:

subtext extract ./my-test/ -o login-flow.json
# Macro written to login-flow.json
# 8 steps, 2 parameters

Email addresses and password fields are automatically converted to {{param}} placeholders.


Benchmarking

Compare Subtext against other browser automation tools on your own app:

cd bench
npx tsx build/harness/cli.js run \
  --url https://myapp.com \
  --task "Log in and create a new project" \
  --accept "Project appears in the list" \
  --runner subtext \
  --json

Built-in runner shorthands: subtext, playwright, stagehand, browser-use.


CI Integration

Subtext is designed to work as the browser automation layer in CI pipelines.

Structured Responses

Every tool returns JSON with machine-readable metadata:

{
  "ok": true,
  "command": "live-connect",
  "durationMs": 1234,
  "content": [...]
}

Exit Codes

CLI commands return distinct exit codes per error category:

| Code | Meaning | |------|---------| | 0 | Success | | 1 | Generic error | | 10-14 | Target errors (not found, stale, not interactive, obscured, offscreen) | | 20 | Timeout | | 30 | Navigation blocked | | 40 | Browser disconnected | | 50 | Auth required |

Init Scripts

Inject JavaScript before page load for mock setup, feature flags, or service worker initialization:

{"url": "https://myapp.com", "init_scripts": ["window.__MOCK_AUTH = true"]}

Session Persistence

Save and restore full session state (cookies, localStorage, IndexedDB) across CI runs:

# Login once, save session
subtext connect https://myapp.com/login
subtext fill <id> EmailInput [email protected]
subtext fill <id> PasswordInput secret
subtext click <id> LoginButton
subtext disconnect <id> --save_storage auth.json

# Restore in subsequent runs
subtext connect https://myapp.com --storage_state auth.json

Named sessions for multi-user scenarios: session-save, session-restore, session-list.


Hosted Mode

When SUBTEXT_API_KEY is set, Subtext uses a cloud browser with additional features not available in local mode:

  • Auto-tunneling — localhost URLs are automatically tunneled so the cloud browser can reach your dev server
  • Viewer URLs — live session sharing links for teammates
  • Session comments — structured feedback with intents (bug, tweak, looks-good)
  • Session review — replay and diff recorded sessions

Hosted-Only Tools

| Tool | Description | |------|-------------| | comment-list | List comments on a session | | comment-add | Add comment with intent + optional screenshot | | comment-reply | Reply to a comment | | comment-resolve | Resolve a comment thread | | review-open | Open a session for review | | review-view | View page at timestamp | | review-diff | Diff between timestamps | | review-close | Close review session |

See the install guide for hosted mode setup.


Environment Variables

| Variable | Description | |----------|-------------| | SUBTEXT_API_KEY | API key for hosted mode. Omit for local Playwright mode. | | SUBTEXT_SIGHTMAP_ROOT | Override sightmap search root directory | | SUBTEXT_SCREENSHOT_DIR | Auto-save directory for screenshots | | SUBTEXT_API_URL | Override hosted MCP endpoint |

Project Structure

cli/
  src/engine/       Playwright engine, snapshot pipeline, assertions, evidence
  src/mcp/          MCP server (stdio transport)
  src/cli/          CLI commands (yargs)
  src/sdk/          SDK client and transport
bench/              Benchmark harness and test apps
skills/             Agent skill definitions

License

MIT