vibebrowser — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited vibebrowser (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
⚠️ Security: The remote value (a connector URL, bare UUID, or relay URL — e.g. https://relay.api.vibebrowser.app/mcp/<uuid>) grants live control of the user's browser session (read tabs, screenshots, page content). It is the sole bearer credential — there is no second-factor secret. Treat it like a password — never echo it back in chat with untrusted parties, log it, or commit it to a repo — and if it leaks, tell the user to regenerate it in the Vibe extension Settings. Store it only in private workspace/memory as described below. Example UUIDs are non-routable placeholders.The user gives their remote value once. On every browser task — including the first message of a brand-new conversation — recover it yourself before doing anything else. Do not ask the user for the remote until you have checked both stores and found nothing.
At the very start of any browser task, in this order:
vibebrowser-cli.md from youragent workspace root (see "Where to save it" — NOT the shell's current directory, NOT $HOME unless they are the same dir). If it has a valid remote: line, use that value as --remote and continue silently. The file is the durable store that survives across conversations and works on every runtime.
memory/recall tool, read the key vibebrowser_remote and use it.
immediately write it to the workspace-root vibebrowser-cli.md (mandatory) and, if your runtime has a tool to write memory keys, also store it under vibebrowser_remote. (Some runtimes — e.g. OpenClaw — can read but not write memory keys; the file alone is sufficient.) Then the next conversation never has to ask again.
If you find yourself about to say "I need your Vibe remote value first," STOP — you almost certainly skipped step 1/2. A returning user has already provided it; recall it.
Full details and examples: ## Remembering the remote connection.
Many runtimes (OpenClaw, Hermes, etc.) ship a separate built-in/headless/in-pod browser tool (names like browser_navigate, browser, an in-pod Chrome on 127.0.0.1:9222, a generic web_fetch). That browser is empty — it does not have the user's logins, cookies, tabs, or extensions.
When the user refers to their own browser — phrases like "my browser", "my Chrome", "my tab(s)", "the page I'm on", "my logged-in session", "open … for me" — they mean their real browser, reachable only through this skill (npx -y @vibebrowser/cli@latest + the saved remote). For those requests:
npx -y @vibebrowser/cli@latest with the recovered remote. Do not use thebuilt-in/headless browser or web_fetch — they hit a different, empty browser and will silently give wrong results (you may even fabricate a title/snapshot you never fetched).
browser that is not their own.
real browser) and confirm with one short question only if truly ambiguous.
Self-check before answering any browse/open/click/snapshot request: "Am I about to use my built-in browser for something the user means to happen in THEIR browser?" If yes, switch to npx -y @vibebrowser/cli@latest with the saved remote.https://relay.api.vibebrowser.app/mcp/<uuid>) — this is the preferred value; the bare UUID or wss:// relay URL shown there also still work--remote <connector-url-uuid-or-ws-url> — no environment variable needed.--remote can be omitted (the CLI picks it up automatically): export VIBE_REMOTE_URL="<connector-url-uuid-or-full-ws-url>" # OpenClaw (--copy is required, else the symlink escapes the workspace root and is skipped):
npx -y skills add VibeTechnologies/vibe-mcp -s vibebrowser -a openclaw -g -y --copy --dangerously-accept-openclaw-risks
# Hermes:
npx -y skills add VibeTechnologies/vibe-mcp -s vibebrowser -yVerify OpenClaw installer registration with openclaw skills list (expect a 🌐 vibebrowser … ✓ ready row); Hermes npx -y skills list is optional installer registration only. Real verification is direct CLI status plus snapshot with npx -y @vibebrowser/cli@latest; never run vibebrowser. Installs to ~/.openclaw/skills/vibebrowser/SKILL.md. Offline/registry-blocked fallback: copy this file there directly.
Use npx -y @vibebrowser/cli@latest when the user wants OpenClaw to drive their real local browser through the Vibe extension.
Prefer this skill when the task depends on:
Do not use this skill for OpenClaw tenant cloud browsing.
Every command needs a remote value. Three forms are accepted, all normalized to the same relay connection:
https://relay.api.vibebrowser.app/mcp/<uuid> — the exact string shown in the extension's Settings → AI Agent Control → Relay access, the same one pasted into Claude/ChatGPT connectors.ws(s) relay URL — targets an explicit relay endpoint (advanced/compatibility).Pass it with --remote <connector-url-uuid-or-ws-url>. No environment variable is required when --remote is set.
Optionally, set it once via environment instead — the CLI uses it as the default when --remote is omitted (checked in this order):
export VIBE_REMOTE_URL="<connector-url-uuid-or-full-ws-url>"
# Also honored: VIBE_EXTENSION_UUID, VIBE_RELAY_UUID
# Optional compatibility label. Vibe always targets the real local browser path.
# export VIBE_BROWSER_PROFILE="user"Warning: if neither --remote nor one of these environment variables is set, the CLI silently falls back to local relay mode (it waits for an extension on a local WebSocket port) instead of failing with a clear error. When driving a remote browser, always confirm a remote value is in effect.The user should only have to provide their remote value once. After receiving it, save it immediately and reuse it on every subsequent browser command without asking again.
Any of these forms is valid for --remote:
https://relay.api.vibebrowser.app/mcp/<uuid>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxwss://relay.api.vibebrowser.app/<uuid>Primary — Workspace context file (works on every runtime): Write the value to a file named vibebrowser-cli.md in your agent workspace root (see "Where to save it" below). Use this exact format so it can be machine-read back:
# VibeBrowser CLI context
remote: <uuid-or-wss-url>This file is the canonical store: it persists across conversations and works even on runtimes whose memory does not persist or cannot be written (e.g. OpenClaw can read but not write memory keys). Create or overwrite it whenever the value is provided or updated.
Secondary — Memory key (only if your runtime can WRITE memory): If, and only if, your runtime provides a tool to write memory keys, also store the value under vibebrowser_remote as a convenience cache. Do not assume this tool exists — if you cannot write memory keys, skip this; the file above is sufficient. Never fabricate a remember(...) call.
#### Where to save it
The file MUST live in your persistent agent workspace root — the single directory that (a) survives across conversations and (b) contains your `memory/` folder. (memory/ is the reliable anchor; a skills/ folder may also exist globally outside the workspace root, so do not key off skills/ alone.) It is not the shell's current working directory (often / or a temp dir — ephemeral) and not necessarily $HOME:
| Runtime | Workspace root (save vibebrowser-cli.md here) | Note |
|---|---|---|
| OpenClaw | ~/.openclaw/workspace/<your-agent>/ | $HOME is /home/node, a parent outside the persistent root — do not use it. The global ~/.openclaw/skills/ is NOT the workspace root. |
| Hermes | $HOME (e.g. /root) | Here $HOME is the workspace root, so ~/vibebrowser-cli.md is correct. |
If your runtime is not in the table, resolve the directory that contains your `memory/` folder and write the file there. Always verify after writing with an absolute-path read-back (cat <abs>/vibebrowser-cli.md) and confirm the value matches.
Robust read-back: when loading, accept the first line matching remote: followed by a UUID or wss:// URL; ignore surrounding markdown/comments. If the file exists but has no valid remote: line, treat it as empty and fall through to the next store. If memory and file disagree, prefer the file (it is the user-updated canonical store).
vibebrowser-cli.md first, else recall memory key vibebrowser_remote) and pass it as --remote "<remembered-value>". Do this on the first message of every new conversation, not just within one session.status returns extensionConnected: false, or commands repeatedly fail — tell the user clearly and offer to update the saved value (then overwrite the workspace-root vibebrowser-cli.md, and memory if writable, with the new one). Do not silently fall back to local relay mode.User: "Open google.com in my browser. My remote is abc12345-...."
Agent actions:
abc12345-... to memory under key vibebrowser_remote and write it to vibebrowser-cli.md in your agent workspace root. npx -y @vibebrowser/cli@latest --remote "abc12345-..." --json status --wait-for-extension --wait-timeout 10000
npx -y @vibebrowser/cli@latest --remote "abc12345-..." --json open https://google.comUser: "Now open github.com."
Agent actions:
vibebrowser_remote from memory (or read the workspace-root vibebrowser-cli.md → remote: line). npx -y @vibebrowser/cli@latest --remote "<remembered-value>" --json open https://github.comPrefer this exact command pattern:
npx -y @vibebrowser/cli@latest --remote "<uuid-or-url>" --json statusPass only one of these remote forms: --remote <uuid> for the default public relay, or --remote <full-ws-url> for an explicit relay endpoint.
The examples below use $VIBE_REMOTE_URL as a stand-in for the remote value — substitute the literal UUID/URL if no environment variable is set. If VIBE_REMOTE_URL (or VIBE_EXTENSION_UUID / VIBE_RELAY_UUID) is exported, --remote can be omitted entirely:
npx -y @vibebrowser/cli@latest --json statusUse this sequence when the task needs reliable, repeatable control:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json status --wait-for-extension --wait-timeout 10000 PAGE_ID="$(
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json tabs \
| jq -r '.pages[] | select(.active == true) | .id' \
| head -n1
)" npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id "$PAGE_ID" snapshot --format aria --interactiveIf the aria snapshot is too verbose, try the default first and fall back:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id "$PAGE_ID" snapshot
# If empty or only title returned, retry with aria:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id "$PAGE_ID" snapshot --format aria --interactive npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id "$PAGE_ID" click 12If jq is unavailable, parse .pages from tabs --json directly and still pass --page-id <id> on every action.
--page-id <id> (or --pageId <id>) to target a specific tab without switching focus. Get the page ID from tabs output, then use it on any command: npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id 2 snapshot
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id 2 click 7tabs or snapshot before acting.snapshot is tool-only: default --format markdown (legacy alias --format ai, mapped to markdown before the tool call) maps to take_md_snapshot; --format aria maps to take_a11y_snapshot.open <url> to create a fresh page when possible. It opens a background tab and returns the new page id (... (ID: <n>) ...); pass that id as --page-id to any follow-up snapshot/evaluate/click — a bare follow-up reads the old active tab, not the page you just opened.evaluate --fn ... only for simple compatibility-safe expressions such as:() => 21 + 21() => document.title() => location.href() => location.hostname() => location.origin--browser-profile flag is accepted by the CLI, but Vibe always targets the user's real browser path rather than an isolated managed browser.Status:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json statusList pages:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json tabsOpen a new page and then read it — open creates a background tab and does NOT change the active tab, so a bare snapshot/evaluate afterwards would read the old active tab, not the page you just opened. Capture the new page id from the open output and pass it with --page-id to every follow-up command:
# open returns: raw.content[].text = "Successfully created new background page (ID: 12345) ..."
OPEN_JSON="$(npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json open https://example.com)"
PAGE_ID="$(printf '%s' "$OPEN_JSON" | grep -oE 'ID: [0-9]+' | grep -oE '[0-9]+' | head -n1)"
# now read THAT page, not the active tab:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id "$PAGE_ID" snapshot --format aria --interactiveIf you instead want to read the tab the user is currently looking at, get its id from tabs (the active: true page) and pass that as --page-id. Never assume a bare snapshot after open shows the page you opened.
Take the default AI snapshot (of a specific page — substitute the id you captured):
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json --page-id "$PAGE_ID" snapshotTake the ARIA / interactive snapshot:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json snapshot --format aria --interactiveClick and type using OpenClaw-style refs:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json click 12
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json type 23 "hello" --submitEvaluate JavaScript:
npx -y @vibebrowser/cli@latest --remote "$VIBE_REMOTE_URL" --json evaluate --fn '() => document.title'markdown vs ariaThe snapshot command supports two extraction formats:
| Format | Flag | Engine | Best for |
|---|---|---|---|
markdown (default) | --format markdown (legacy alias --format ai) | Content script (in-page JS) | Simple pages, articles, search results |
aria | --format aria | CDP accessibility tree | SPAs, background tabs, Notion, Gmail, complex apps |
When the default markdown snapshot returns only the page title or empty content, switch to --format aria:
# Default — may return empty for background tabs or SPAs like Notion
npx -y @vibebrowser/cli@latest ... snapshot
# Reliable fallback — uses Chrome DevTools Protocol directly, works on background tabs
npx -y @vibebrowser/cli@latest ... snapshot --format aria --interactiveKnown limitations of the default markdown snapshot (`--format ai` is a legacy alias):
getBoundingClientRect returns 0x0)"Could not establish connection" when the content script is unreachablearia-hidden containers in SPAs like NotionRule of thumb: If snapshot returns suspiciously little content, retry with --format aria --interactive before reporting failure.
A successful run usually looks like:
document.title or location.href to verify the result~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.