vibatchium
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| VIBATCHIUM_SESSION | No | Active session resolution: `--session FLAG` → `$VIBATCHIUM_SESSION` env → `~/.config/vibatchium/active-session` → `default`. | default |
| VIBATCHIUM_IDLE_FREEZE | No | Set to '0' to disable freezing of idle session renderer processes. Default is enabled. | 1 |
| VIBATCHIUM_SECRETS_KEY | No | Optional key for the encrypted credential vault. If not set, the OS keyring is used. | |
| VIBATCHIUM_MAX_SESSIONS | No | Cap on number of parallel browser sessions. Default is 8. | 8 |
| VIBATCHIUM_IDLE_FREEZE_AFTER | No | Seconds with no verb before a launched session's renderer processes are SIGSTOPped. Default is 90. | 90 |
| VIBATCHIUM_SESSION_RAM_FLOOR_MB | No | Minimum free memory required to launch a new session, in MB. If set, daemon refuses to launch a new session when free memory is low. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
When WebFetch / WebSearch / curl comes back with any of these, the page is NOT unreachable — it's behind a wall a plain HTTP client can't pass:
403 / 429 / "Access Denied" / generic bot-block
a Cloudflare / DataDome / PerimeterX challenge ("Just a moment...", "Checking your browser")
an empty JS-shell ("JavaScript is required", blank SPA, content only after scripts run)
a login wall or paywall
DO NOT report failure and stop. Do not answer the user "I couldn't access that page" — a block is the SIGNAL to switch, not a final result. Call explore(url). vibatchium ('vb') is a real stealth browser (patchright/Playwright fork) on this server; it clears most such walls cold. Not every one — a hard CAPTCHA or interactive click-gate can still fail — so try it, don't pre-assume it won't work.
Cheap default still wins: for plain static HTML, Google, or a news/general lookup, keep using WebFetch/WebSearch — it's faster. Reach for vb when normal fetch FAILS, or the page needs a real browser (SPA, login/session, multi-step flow).
Concurrency: this daemon may be SHARED with other agents. A one-shot lookup (explore) is safe — it runs on its own throwaway session. But for STATEFUL multi-step work (go → click → fill across calls), pass a unique session name on every tool call (e.g. your task id) so you don't collide with another agent on the implicit 'default' session; use session_lease to coordinate if you must share one. For a fully private blast radius, an operator can run a per-agent daemon (vb daemon start --isolated).
Entry points (this server's current tool surface):
explore(url) — START HERE. One call: stealth session → navigate → clean page text (off-budget ephemeral, auto-deleted). The 80% case.
go(url) then extract — lower-level navigate, then LLM-ready Markdown (flags structure_loss).
screenshot(tiles=true) — full page as PNG tiles on disk; read with your own vision when extract flags loss.
Covering many sites: find the URLs with WebSearch first, then explore each one. Don't guess URLs, and prefer a product or article page over a site's own search page. On 8 retailers that found 6 prices; guessing URLs found 3, and WebFetch alone 3. Parallel explores are fine: extra ones wait for a free slot.
Forms and checkouts: go(url), map_compact for refs, then fill / select / check / click, passing one session throughout. After each step read with text(settle=true) rather than a timed wait in page script. Stop before anything the user hasn't approved, such as paying or accepting terms. Finish with session_close: open sessions count against a shared cap.
(Other verbs may exist behind opt-in caps.)
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| startB | Start a browser session (cold-launch real Chrome). |
| attachA | Attach to an existing Chrome via CDP (use after manual login on a Cloudflare-walled site). |
| stopB | Stop the browser session. |
| statusB | Daemon + session status. |
| verify_urlA | Fast pre-check (DNS, optional HTTP HEAD) for a URL before |
| set_log_verbsA | Toggle the daemon's per-verb DEBUG audit log at runtime. Useful for non-trivial runs where you want a full call trail; the toggle's response returns the daemon-log path to tail. |
| exploreA | USE THIS WHEN WebFetch/WebSearch/curl GOT BLOCKED — a 403, a Cloudflare/DataDome "Just a moment..." challenge, a login/paywall, or an empty "JavaScript is required" shell: don't report failure, use this — patchright clears most such walls cold. ONE-CALL 'look at this URL', TEXT-FIRST. Does a DNS pre-check → auto-start a session if needed (headless) → navigate → extract the text. It does NOT screenshot by default: read and navigate with the returned text/selectors, and a screenshot is captured only as a FALLBACK when the page yields no usable text (canvas/image/blank SPA). This is the 80% case of 'just show me what's on this page' — use it instead of separate start / navigate / read calls unless you need multi-step interaction. Pass screenshot='always' to force a screenshot, 'never' to suppress even the fallback; when one is captured it comes back as a viewable image, not base64 text. Without an explicit session it runs on an OFF-BUDGET transient ephemeral session (0.7.0) — it never competes with persistent sessions for a slot and is auto-deleted afterward, so it won't touch your 'default' session. |
| expectA | ONE-CALL verification gate. Assert the page reached an expected state — composes element-state / page-text / URL checks plus a native challenge-wall check into a single {passed, failures[]} verdict. Use after an action to confirm it landed (or that you got soft-blocked) instead of stitching several wait and read calls together. Every check is optional. |
| goA | Navigate to a URL in the stealth browser, then read the page with a content tool. Reach for this when WebFetch/curl was blocked — a 403, a Cloudflare/DataDome "Just a moment..." challenge, a login/paywall, or a JavaScript-only page that returns no usable HTML — or when the page needs a real browser. |
| backC | Browser back. |
| forwardD | Browser forward. |
| reloadB | Reload current page. |
| urlA | Get current URL. |
| titleA | Get current page title. |
| textA | Get inner text (whole page or a target — @eN, @text:Foo, @label:Email, CSS, etc.). After a click or form step, pass settle=true: it waits for the page to stop changing, then reads, and returns the url too. Use that instead of a timed wait in page script. |
| htmlC | Get HTML (whole page or a target — @eN, @text:Foo, @label:Email, CSS, etc.). |
| extractA | Clean, LLM-ready Markdown of the page (or a target subtree) — boilerplate (nav/footer/aside/scripts) stripped, headings/links/lists/code preserved. A drop-in for Crawl4AI/Firecrawl-style scraping on the AUTHENTICATED pages those stateless tools can't reach. Returns markdown TEXT (never a base64 screenshot), capped by max_chars. |
| extract_fieldsA | Declarative STRUCTURED extract: pass a {name: selector} map and get back ONE JSON object of values in a single call — against our real authenticated Chrome DOM (a login-walled / SPA page stateless scrapers can't reach). Grammar: |
| detect_formsA | Structured map of every on the page (plus a formless-controls group for SPAs) — against our real authenticated Chrome DOM. Each field carries a ready-to-use |
| candidatesA | List EVERY element a target resolves to, so an ambiguous locator can be disambiguated instead of failing strict mode. Returns {target, count, candidates:[{index, tag, role, name, text, bbox}], truncated}. Act on one with click/fill/type/hover passing |
| attrB | Get an HTML attribute value from an element. |
| valueB | Get the current value of an input/textarea/select. |
| evalA | Evaluate a JS expression in the page (isolated context per Patchright default — |
| mapB | Snapshot actionable elements and assign @eN refs (uses Playwright aria_snapshot mode='ai'). |
| diff_mapC | Diff current snapshot vs the previous one. |
| clickA | Click an element. Target: an @eN ref from map_compact, visible text ( |
| dblclickC | Double-click an @eN ref or CSS selector. |
| focusA | Focus an element (without clicking). |
| selectA | Pick an option on a by value/label/index. Also works on a custom dropdown: pass the button that opens it and the option's label. |
| fillB | Clear an input and fill it with text. With use_secret, value comes from the encrypted vault — and is only written into a page on the secret's own site (https, same host or a subdomain, or the entry's |
| typeA | Type text key by key into an element. Use this rather than fill when the field offers suggestions as you type, such as an address box. |
| hoverC | Hover over an element. |
| pressA | Press a key on a specific element (e.g. Enter on @e3). |
| keysB | Press a key combination (e.g. 'Control+a', 'Enter'). |
| checkC | Check a checkbox / radio. |
| uncheckB | Uncheck a checkbox. |
| scrollC | Scroll the page or a target element into view. |
| is_stateC | Check element state (visible/enabled/checked/...). |
| screenshotA | Capture a screenshot. With no path it returns a viewable image (not base64 text); with a path it saves the PNG and returns the path. With tiles=true it slices a full-page capture into fixed-height tiles written to DISK (returns their paths + count, never base64) — for layout-heavy pages a vision-capable caller then reads tile-by-tile. Prefer reading the page text/selectors first — only screenshot when you actually need the pixels. |
| wait_selectorB | Wait until an element reaches a state. Takes the same targets as click. |
| wait_refC | Wait until an @eN ref reaches a state. |
| wait_urlB | Wait until the URL matches a glob/regex. |
| wait_loadB | Wait for a page load state (load/domcontentloaded/networkidle). |
| wait_fnB | Wait until a JS expression returns truthy. |
| pagesC | List all open browser tabs. |
| page_newA | Open a new tab and switch to it. |
| page_switchC | Switch to tab by index. |
| page_closeA | Close the current tab; the next tab becomes active. |
| findC | Locate elements by semantic strategy (text/label/placeholder/role/testid/xpath/alt/title/css). |
| countB | Count matching elements for a selector or @eN ref. |
| contentC | Replace the page HTML wholesale via page.set_content. |
| framesA | List all live frames with name + url + depth + active flag. |
| frameB | Switch active frame by name or URL substring (omit both to clear). |
| mouseC | Mouse control at pixel coordinates. |
| uploadC | Set files on an input[type=file] target. |
| upload_nextA | Arm the NEXT native file chooser of the active tab with files, for upload buttons that have no input[type=file] in the DOM. Then click the button (any verb). One shot; expires after timeout_s. Choosers are intercepted only while armed. Check with upload_status. |
| upload_statusC | Whether the armed file chooser was filled (consumed), plus how many choosers were swallowed (no arm left) or foreign (from another tab while armed). |
| pdfC | Save the current page as PDF. |
| highlightB | Briefly outline an @eN ref or selector for visual debugging. |
| screenshot_annotateB | Screenshot with @eN bounding-box overlays (vision-LLM friendly). |
| map_compactA | One-line-per-element rendering of the snapshot (token-efficient): |
| observeB | Plan a verb + target for an intent without executing. |
| actA | Do one action from a short instruction, without naming a selector. It matches the words against element names, with no reasoning, so use the page's own wording: |
| profile_listB | List all profiles and the active one (alias of session_list). |
| profile_newB | Create a new named profile (alias of session_new). |
| profile_useB | Set the active profile (alias of session_use). |
| profile_deleteB | Delete a profile directory (alias of session_delete). |
| session_newA | Create a new on-disk session/profile dir (does NOT launch Chrome). |
| session_listB | List every on-disk session + which are currently running. |
| session_useB | Set the active session (persisted to active-session file). |
| session_switchC | Alias for session_use. |
| session_closeB | Stop Chrome for one session (profile dir preserved). |
| session_close_allC | Stop Chrome for every running session. |
| session_deleteA | Delete a session's profile dir on disk (not active/default). |
| session_leaseA | Acquire/renew an exclusive advisory lease on a running session (0.7.0). Returns a token; present it as the |
| session_releaseA | Release a session lease — present the token via the |
| session_lease_infoB | Report the lease state for a session (never returns the token). |
| cleanA | Housekeeping — reclaim disk from stale profile dirs, superseded Chrome cache dirs, leftover Chrome lock files, regenerable caches, and the daemon log. DRY-RUN by default; pass apply=true to actually delete. Never touches the default/active/running sessions. Returns a per-category {count, bytes} report. |
| humanize_onA | Enable humanlike mouse (Bezier paths, gaussian dwell, sin scroll) for current session. With a recorded swipe library installed, the wheel replays the operator's swipes on one device per session. |
| humanize_offB | Disable humanize for current session. |
| humanize_statusA | Report whether humanize is on for current session. |
| humanize_ambientA | Opt-in AMBIENT activity between verbs (default off): while the session idles, emit low-rate human-plausible pointer drifts + rare reading scrolls (never clicks/types/selects/navigates, yields to every verb, stops horizon_s after the last verb or at idle-freeze). Targets are best-effort: it avoids elements that look interactive but can't see script-attached hover handlers, so a page may still observe a mouseover. Fills the zero-mouse-events silence behavioural scorers flag. mode=on|off|status. |
| vision_clickA | Find a UI element by verbal description (via Claude vision) and click it. Fallback for canvas/Flutter/Unity pages where AX-tree fails. Requires [llm] extra. |
| vision_findA | Return coords + confidence for a described element (no click). |
| vision_typeB | vision_click the described field, then type the given text. |
| vision_statsB | Return cumulative vision API usage (calls, cache_hits, tokens, cost_usd) for session. |
| vision_clear_cacheA | Drop the on-disk vision coords cache. |
| vision_budgetC | Report today + lifetime vision spend vs VIBATCHIUM_VISION_MAX_*_USD caps. reset='today'|'lifetime'|'all' clears the spend log. |
| dismiss_bannersB | Heuristically dismiss cookie/consent/newsletter banners. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 89 tools
Many tools overlap heavily: go and explore both navigate-and-read, while extract, text, html, content, extract_fields, and detect_forms all retrieve page data. Session/profile aliases and element-location tools like find, candidates, map, and map_compact further blur boundaries, making misselection likely.
Most names use lowercase snake_case, but the set mixes bare verbs/nouns (go, start, map, fill, click) with prefixed groups (session_*, vision_*, upload_*, humanize_*). The casing is consistent, but naming style and specificity vary enough to feel mixed.
At 89 tools, the surface is very heavy for an MCP server, even a capable browser-automation one. Several tools are aliases or near-duplicates, so many tools do not clearly earn a distinct place.
The surface is extensive: sessions, tabs, frames, navigation, waits, extraction, forms, screenshots, uploads, vision fallback, and humanization are all covered. Some browser-automation areas such as cookies/storage, dialogs, downloads, and network interception appear absent, but most core workflows are supported.