vibatchium

io.github.trueoriginlabs由 GitHub 帳號 trueoriginlabs 發布v0.21.0更新於 Nov 7, 2026

Stealth browser automation for AI agents — real Chrome, N parallel persistent logged-in sessions.

概覽

AI 產生的概覽

一款隱蔽式瀏覽器自動化 MCP 伺服器,驅動真實 Chrome,讓助理讀取、擷取並操作那些會阻擋一般 HTTP 請求的頁面。

可以做什麼
  • 管理瀏覽器工作階段:啟動、附加到既有 Chrome、停止、查看狀態、預先檢查網址
  • 導覽與讀取頁面:上一頁下一頁、重新載入、取得網址與標題、讀取文字、HTML、屬性與表單值
  • 擷取內容:整頁或子樹的乾淨 Markdown、依選擇器對應的結構化欄位擷取、表單結構圖、候選元素清單
  • 操作頁面:產生並比對可操作元素快照,點擊、雙擊、懸停、填寫、逐字輸入、選擇選項、勾選、按鍵、捲動、等待元素狀態
  • 驗證與截圖:對頁面狀態做斷言檢查,截圖回傳圖片或分塊 PNG 檔案,執行頁面內 JavaScript
適用情境
當一般抓取或搜尋回傳 403、機器人驗證、只有 JavaScript 的空殼頁面或登入牆,而助理仍需要頁面內容時適用。也適合需要登入的多步驟流程,例如表單與結帳,以及在同一台機器上並行執行多個已登入工作階段。
執行需求
以本機 Python 套件形式執行,透過 pipx 或 uvx 安裝,另需安裝 Chrome 並讓守護程序持續執行。官方支援 Linux,macOS 被描述為不支援。選用擴充提供抓取、搜尋、憑證保險庫與視覺讀取功能。MCP 伺服器本身未宣告需要 API 金鑰。
安裝前請注意
它的用途是繞過反爬阻擋,可能與網站條款衝突,且面對強驗證碼或行為偵測仍可能失敗。頁面文字不可信,可能夾帶提示注入;抓取與搜尋通道不做掃描。選用保險庫會保存憑證並依來源限定填入,但擁有 shell 權限的代理可繞過這些限制。工作階段會在真實網站上點擊、填寫與送出,付款或接受條款前應停下。軟體處於 alpha 階段,單一守護程序是單點故障。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 vibatchium,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

[vibatchium]

vibatchium

The browser layer for an always-on box. Many logged-in identities, running unattended, all at once — on real Chrome, with stealth on by default, and with a security model for letting an AI near the credentials.

One daemon, N persistent Chrome sessions, a vb CLI and an MCP server. Self-hosted, free, Apache-2.0.

pipx install 'vibatchium[all]'patchright install chromevb setup                     # register the MCP server + agent skill (Claude Code, Codex, Cursor)vb explore https://example.com

Is this for you?

You want…Use
An agent driving your signed-in browser while you watchClaude in Chrome, Chrome Auto Browse — first-party, free, better integrated
The stealthiest single browser you can buyCloakBrowser — fingerprints patched in Chromium's C++ (paid for concurrency)
The leanest driver for one agentbladebro — five tools, one Rust binary
Browser automation without anti-bot pressureplaywright-mcp, agent-browser — bigger, older, better tested
Many accounts on one box, running unattended, against sites that fight automationvibatchium

That last row is the whole wedge. Supervised agents hand control back to you at every login wall and CAPTCHA; a library leaves the fleet — sessions, budgets, crash recovery, credentials — for you to build. vibatchium is that fleet layer.

How it compares

As of 2026-10-06, from each project's own README, source and release notes (the MCP-cost row is our own measurement¹). Rows where we lose are included on purpose.

vibatchiumCloakBrowserbladebroagent-browserplaywright-mcp
N persistent logged-in sessions at onceyes, free, one daemon1 free (latest build) · more on Proone Chrome per agent sessionyes, one daemon per sessionone per profile dir
Unattended ops: crash self-heal, leases, budgets, idle freeze, goalsall of them—partial (crash relaunch, idle timeout)partial (idle timeout, restore)idle timeout
Agent can use a secret but not read it (origin-bound fill, read-back refused, TOTP)yes——vault, origin check--secrets redaction
Prompt-injection scanning of page contentyes——boundary markers (opt-in), no scanning—
Browserless HTTP on the session's own cookies, Chrome TLS fingerprint · keyless web searchyes————
Browserstock Chromeown Chromium buildstock ChromiumChrome for Testing defaultstock Chrome
Stealth layerCDP-level (Patchright)engine-level (87 C++ patches)CDP-level ("6-layer"), no Runtime.enablenone in core; via cloud providersnone
Published stealth scorenot yet30/30 on its own detector list68/80 Stealth Bench V1 (self-run)——
MCP startup cost in Claude Code¹~2.7k tokens (89 tools, 5 always loaded)n/a~3.4k tokens (5 tools)not measurednot measured
PlatformsLinux (macOS: CI probe, unsupported)Linux · macOS · WindowsLinux · macOS · Windowsallall

¹ bytes/4 of tools/list plus server instructions, measured over stdio. Clients without tool search load every tool: vb mcp --caps min is 12 tools, ~3.8k tokens. bladebro's own README says ~1.9k.

Where the others are genuinely better: CloakBrowser's engine-level patches go deeper than any CDP-level layer can — and vb start --browser-binary will drive a Chromium build you bring. bladebro has a stealth benchmark number and we don't; until we do, read our stealth claims as measured on scoreboards, below, not on production walls. Both run on more operating systems.

What only vibatchium does

1. A fleet of logged-in identities on one box. Each session is its own Chrome and profile, with its own proxy, timezone and GPU node, and — opt-in with vb persona set — its own screen and window, because by default every headless session on one machine reports the same 800×600 screen. vb fleet-check measures how alike your sessions still look. They run in parallel on one daemon that keeps them alive: a crashed renderer is relaunched on the same profile, parked sessions have their renderers stopped and thawed on the next call, leases stop two agents clobbering one session, and goals give a task a step/spend/time budget that survives a daemon restart.

vb --session alice start && vb --session alice go https://x.com      # log in once, stays logged invb --session bob   start && vb --session bob   go https://x.comvb --session alice act "open notifications" & vb --session bob extract & waitvb fleet-check --sessions alice,bob                                  # how twinned are they?

2. Credentials an agent can use but never see. The vault fills a password or a live TOTP code into the page without the value reaching the model's context, a screenshot or a log — and only into the site it belongs to. Over MCP, a prompt-injected agent can't type your GitHub password into a lookalike page, can't read it back with value or eval while it sits in the field, and can't edit the vault or pull a code. An agent with a shell is the operator — the CLI has deliberate escape hatches — so give agents MCP, not Bash, if that boundary matters to you.

printf %s "$GH_PASSWORD" | vb secret set github.com password --stdinprintf %s "$GH_TOTP_SEED" | vb secret set github.com totp-seed --stdinvb --session work fill @e7 --use-secret github.com:passwordvb --session work fill @e9 --use-secret github.com:totpvb wait-email-code github.com      # operator CLI: polls IMAP and prints the code; refused over MCP

3. Page text is treated as untrusted. Every session scans the page text it returns for instructions aimed at the agent and flags them by default; wrap fences them off and redact removes them. Caller-supplied file paths are confined too, so an injected agent can't upload ~/.ssh or write into .git/hooks.

4. A browserless lane on the same identity. vb fetch reuses a session's cookies and proxy with Chrome's TLS fingerprint and client hints — JSON endpoints behind your login at curl speed, and it tells you when it can't match the browser. vb search finds URLs with no API key and no per-session budget.

vb --session work fetch https://api.example.com/v1/mevb search "site reliability postmortem" -n 20 --urls

Status: alpha, active development. 2,331 tests green in CI (Linux, Python 3.11–3.14). Coding agents: read AGENTS.md first — the one-call recipes and the traps worth skipping.

Detector scores quoted below (bot.sannysoft, CreepJS, Cloudflare cold-launch) are manual observations, not CI-asserted — no test in the suite gates on them, and they are only as current as the last hand-run. The generated block under Measured scores is the one to trust.

Install

pipx install vibatchium             # core: browse / extract / screenshot / N parallel sessionspipx install 'vibatchium[all]'      # + fetch/search lanes, credential vault, VLM read, REST shim                                    #   (or pick extras: [fetch], [secrets], [llm], [rest])patchright install chromevb setup                            # register MCP + an auto-discoverable skill (idempotent)vb install                          # report which optional lanes are available

On a uv venv (no pip), add an extra with uv pip install --python <venv>/bin/python curl_cffi. Bleeding edge from master: pipx install 'git+https://github.com/trueoriginlabs/vibatchium#egg=vibatchium[all]'.

Install as a skill / plugin

vb setup wires up the agents on this machine. To pull just the agent skill into any agent skills.sh supports (Claude Code, Codex, Cursor, Gemini CLI, Copilot, …), or to install skill + MCP server as one Claude Code plugin:

npx skills add trueoriginlabs/vibatchium                  # skill only, any agent
/plugin marketplace add trueoriginlabs/vibatchium         # Claude Code: skill + `vb mcp`/plugin install vibatchium@vibatchium

Both still need the vb CLI on PATH (pipx install 'vibatchium[all]') — the skill drives it and the plugin's MCP server is vb mcp. On Claude Code, pick the plugin or vb setup, not both, or you register the server twice. The skill file is generated from vibatchium/setup_cmd.py; edit there and run python scripts/sync_skill.py.

Quick start

vb explore https://example.com                      # one call: text-first, auto-closesvb research --target https://example.com \          # parallel fan-out, N intents  --intent "pricing model" --intent "customers" --intent "tech stack"

Real Chrome vs fake Chrome

A wave of "headless browser for AI agents" tools rebuild the browser from scratch (Rust + V8, no Blink/Skia) to hit tiny memory and sub-100ms page loads. The catch is structural: with no rendering engine, they can't produce a real device's fingerprint — they synthesize one. And synthetic fingerprints don't hold still.

vibatchium drives real Google Chrome, so its fingerprints are real — and, more to the point, stable. The single test that separates the two is fingerprint stability across navigations. Run the same canvas + WebGL probe on two pages in one session:

vibatchium (real Chrome)synthesized-fingerprint engines
canvas hash, page A → page Bidenticalreseeded per navigation
WebGL readPixelsreal, deterministic pixelsoften Math.random()
WebGL renderera real ANGLE renderer¹stub / zeros

¹ Chrome's own software renderer (SwiftShader) by default — still a coherent, deterministic Chrome value, not a stub. A hardware-GPU string (e.g. ANGLE (Intel …)) needs the opt-in --gpu flag.

A real device returns the same fingerprint every page load; a fingerprint keyed off Date.now() does not — and that inconsistency is exactly what lie-detection fingerprinters (CreepJS and friends) flag. Measured: vibatchium's canvas hash and WebGL readback are byte-identical across navigations, and CreepJS reported 0 % stealth-tampering (no synthetic-environment signatures) when last run by hand. That figure is not regression-tested — treat it as an observation, not a guarantee.

This is not a claim of invisibility. The moat is fingerprint authenticity, not hiding that a browser is automated — vibatchium still reads as headless on the headless-specific tells (see Honest limits), and real-GPU WebGL (--gpu) is opt-in. But real, consistent fingerprints pass the consistency tier that synthetic ones fail by construction — and that tier is what stands between you and a login wall.

Multi-session in 10 lines

vb session new workvb --session work startvb --session work go https://github.com           # log in by hand oncevb session new bankingvb --session banking startvb --session banking go https://bank.example.comvb --session work click @e3 &                     # truly parallel —vb --session banking fill @e5 hi &                # separate Chromes, no cookie bleedwaitvb session list

Active-session resolution: --session FLAG → $VIBATCHIUM_SESSION env → ~/.config/vibatchium/active-session → default. Cap via VIBATCHIUM_MAX_SESSIONS=8 (default 8).

Multi-agent: shared sessions vs a private daemon

On one shared daemon, sessions are isolated in state (separate Chromes and profiles, no cookie bleed) but not automatically in fingerprint — on one box they report the same screen and, without --gpu --node, the same software GPU unless you set a vb persona; vb fleet-check measures it. They also share the host: the session count budget, the memory, and the blast radius of an OOM or a daemon bounce. Two models, pick per trust level:

  • Cooperating agents (your own fleet): the shared daemon is right — just give each concurrent agent a unique --session name so stateful flows don't collide on default. vb session lease coordinates a shared name.
  • A private blast radius: a per-agent daemon on its own socket + HOME — separate profiles/config/state, its own session budget, zero contact with the shared daemon. vb daemon start --isolated prints the XDG_RUNTIME_DIR/ HOME to export for subsequent calls; vb mcp --isolated runs the MCP server on its own private daemon directly. vb daemon reap cleans up abandoned ones. (Same UID = same trust domain — this bounds blast radius, not a security boundary between distrusting tenants; for that, separate UIDs/containers.)

Resource governance. The session cap bounds process count, not bytes. On a shared box, set VIBATCHIUM_SESSION_RAM_FLOOR_MB to refuse a new launch when free memory is low (a portable admission belt). For a hard ceiling, run the daemon under a cgroup — systemd-run --user --scope -p MemoryMax=4G vb daemon start puts the daemon and all its Chromes in one cgroup sharing the limit: an aggregate daemon-wide cap (not per-renderer), and a breach OOM-kills inside the scope, which can include the daemon. It's the only non-racy memory bound, so size it for the whole fan-out.

Idle CPU. Parked sessions can't burn cores either: the daemon SIGSTOPs a launched session's renderer processes after VIBATCHIUM_IDLE_FREEZE_AFTER seconds with no verb (default 90) and thaws them on the next call, so an idle WebGL / animation page drops to zero CPU without a teardown (default on; VIBATCHIUM_IDLE_FREEZE=0 disables).

Freezing rather than closing is a deliberate trade, and it cuts both ways. playwright-mcp's --idle-timeout (v0.0.81, 1 h default for headless) closes an idle browser: that reclaims its memory, and its persistent profile keeps the cookies, but the open tabs and in-page state are gone, and the next call pays a cold launch. A frozen session keeps its resident memory and resumes on the next verb with its tabs, page state and login intact — which is the behaviour a long-lived authenticated session mid-flow needs. Memory is bounded by the other two levers above, the RAM floor and the cgroup, rather than by teardown.

Stealth tiers — what clears what

Stealth is a ladder, not a boolean. Pick the lowest tier that clears your target (higher tiers cost more setup / a visible browser / a manual login). vibatchium does not claim cold-launch defeat of behavioral walls — those need a real human-driven session, and attach-mode is the honest answer.

Architecture caveat. Every tier below was measured on x86-64 Linux. Patchright has a known open arm64 / Apple-Silicon detection gap, so these results should not be assumed to carry to an ARM host. If you run there, measure before you rely on it.

TierHowClearsDoesn't clear
Standard (default)headless cold launch, real channel=chrome, de-Headless'd UACloudflare IUAM / managed challenge, bot.sannysoft 31/31, JS-runtime fingerprintingaggressive Turnstile, DataDome/Kasada, anything behind a login
Hardenedretry --headed; vb humanize on + humanize ambient on (pointer activity between actions); vb persona set (a per-identity screen); --backend nodriver (pip install vibatchium[nodriver], AGPL) for the hardest Cloudflare gatesaggressive Cloudflare/Turnstile, GPU/screen tells that headless leavesbehavioral biometrics, DataDome/Kasada sensor-fusion
Attachvb attach to a Chrome you launched and logged intoDataDome / Kasada / HUMAN behavioral walls, and any authenticated session — your real fingerprint + cookiesnothing here is automated cold; it needs the human login first

Measured scores

vb evals run --update-readme writes measured numbers into the block below, so what we publish is generated rather than asserted. It is empty until someone runs it — an empty block is honest; a number with no run behind it is not.

Run on x86-64 Linux, 25 Aug 2026, Chrome 150, --gpu (real render node). Pass --gpu yourself: headless Chrome falls back to SwiftShader when the GPU path doesn't take, and software GL is itself a detection signal, so numbers measured without it are a floor rather than what a GPU-backed deployment gets.

TargetBackendHumanizeGPUScoreStatusTime
sannysoftpatchrightoffreal100OK17.78s
creepjspatchrightoffreal44OK7.88s
brotectorpatchrightoffreal10OK7.13s
sannysoftnodriveroffreal100OK19.85s
creepjsnodriveroffreal44OK9.72s
brotectornodriveroffreal10OK7.73s

Read these honestly — two of the three are bad.

  • sannysoft 100 is the floor everyone in this category clears; it is not a differentiator.

  • creepjs 44 is mediocre. CreepJS is an adversarial lie-detector: it cross-checks main-thread against worker-thread claims and grades confidence, so a middling score means our environment is coherent but not indistinguishable.

  • brotector 10 is poor, and we know exactly why. The signal firing is UA_Override / HighEntropyValues.empty, and our own de-Headless fix causes it. Measured on Chrome 150, headless, same profile, with and without the --user-agent flag we set to strip HeadlessChrome:

    architecturebitnessuaFullVersionUA string
    without the flagx8664150.0.7871.114says HeadlessChrome
    with the flagemptyemptyemptysays Chrome

    Passing an explicit UA makes Chrome stop deriving high-entropy client hints, so we trade a UA-string tell for a UA-CH-emptiness tell. It is not fixed: the obvious repair (Emulation.setUserAgentOverride with userAgentMetadata) is target-scoped and would reintroduce a main-vs-worker mismatch that is a stronger tell than either leak alone. Publishing this rather than dropping the target is the point — a suite that only reports its wins is marketing.

  • nodriver scores identically to patchright on all three. The escalation tier buys nothing measurable on static scoreboards; its case rests on the automation-protocol axis these targets don't probe. An earlier run had nodriver slightly ahead on creepjs (50 vs 44) — but that run silently denied it the GPU while patchright got a real one, so it was scoring from behind. Once both arms get a real renderer the difference disappears. Worth knowing before reaching for the tier: upstream has not published since nodriver 0.50.3 (2026-05-13), so what the >=0.50.0,<1.0 pin resolves to is now several months old. The rung still works; it is no longer moving.

What these do and don't cover. These are fingerprint scoreboards — the static axis. Through 2026 the major anti-bot vendors moved to session-lifetime behavioural scoring, which none of these targets measure, and which we have not measured against any commercial vendor. Treat a good score here as evidence about environment coherence only.

For the behavioural axis itself, vb oracle run is a self-hosted probe: it drives a page with humanize off then on and grades trajectory curvature, dwell, keystroke cadence and scroll dynamics against a human-plausible band (vb oracle record captures a real-operator baseline; literature defaults until you do). It measures our model of human rather than a named vendor — but it turns "we humanize" into a measured on/off delta, and it's honest about the one axis synthetic input can't reach: CDP input emits no raw-pointer / coalesced events, which only attach-mode against real hardware closes.

Escalation ladder when a wall trips: headless → --headed → humanize on → --backend nodriver → attach-mode after a manual login. Patchright's CDP-layer patches apply in all tiers, including attach (connect_over_cdp).

The fetch verb is an orthogonal fast-path, not a tier: once you're past a wall in the browser, vb fetch reuses that session's cookies+proxy to hit JSON/API endpoints at TLS-fingerprint-correct speed — but it runs no JS, so it can't clear a JS challenge itself.

Captures — 2× screenshots of states you had to click to reach

vb --session shots start --scale 2          # devicePixelRatio 2 (1–4, persisted; --scale 1 clears)vb --session shots go https://example.comvb --session shots click @e3                # open the modal…vb --session shots screenshot -o card.png   # …then capture it at 2560×1600                                            # (2× the 1280×800 pin; vb viewport W H to resize)

The default session captures one image pixel per CSS pixel, so a crop meant for a retina asset lands at half the resolution it needs. chrome --force-device-scale-factor=2 --screenshot is faithful but can't click, so it can never capture a modal, a hover, or a logged-in view. --scale does both.

It's a capture posture, not a browsing one. Chromium only takes deviceScaleFactor at context creation and Playwright refuses it alongside no_viewport, so a scaled session pins a viewport and emulates device metrics — screen == viewport, and start says so with screen_coherent: false. Don't point a scaled session at a Cloudflare/DataDome wall; browse on a normal one and scale a separate session for the picture. Cold start only (scale_pending on a live session), Patchright only (scale_ignored on nodriver), and max_screenshot_px is denominated in device pixels — at 2× a tall page truncates at half the CSS height. Details in AGENTS.md, under Retina / 2× captures.

Search — find the URL, not just read it

Reading a walled page is only half a research loop; the other half is discovery, and search engines are anti-bot walled like everything else. vb search runs the SERP over the same curl_cffi lane — no browser, no session, no API key, and no per-session call budget to run out of mid-run.

vb search "playwright stealth detection" -n 5vb search "cdp leak" --site github.com -n 20vb search "postmortem" --urls | xargs -I{} vb fetch --no-cookies {}

Engines are tried as a ladder (ddg → ddg-lite → bing) until one answers, because reachability moves: the endpoint serving results now may rate-limit (HTTP 202) on the next call. --json returns an attempts array naming every engine that declined and why, and a reason separating all engines are walled from the web has nothing — different problems, different fixes, and the CLI exits non-zero only for the first.

It never reuses session cookies (a SERP needs no login, and attaching one deanonymises the request), which is why it gets its own search cap instead of riding on fetch. No date filter is exposed on purpose: DuckDuckGo's mislabels article dates badly enough to corrupt a timeline. Engines rate-limit per IP — see proxies, below.

Proxies — per-request egress on both stealth lanes

Egress is the axis most people get wrong, so it gets stated precisely rather than implied. Both curl_cffi lanes take --proxy scheme://[user:pass@]host:port:

vb fetch --no-cookies https://api.example/v1 --proxy http://user:pass@gw:12323vb search "site reliability postmortem" -n 20 --proxy http://user:pass@gw:12323vb --session work proxy set http://user:pass@gw:12323    # or per-session, for the browser

Measured, not asserted — same box, same command, only --proxy differing:

egress IP
direct115.70.50.70
--proxy (authenticated gateway)212.69.0.85

Four things worth knowing:

  • Unset means direct, and that is enforced. The daemon hands libcurl an explicit empty proxy, which is the only value that stops it reading HTTP(S)_PROXY / ALL_PROXY out of the environment it was spawned with. A long-lived daemon inherits whatever shell first started it, so without this a stray HTTPS_PROXY would silently reroute every request while the response claimed direct egress. (It did, until 0.19.0 — see the changelog.)
  • It matters most for search. Engines rate-limit per IP, so a wide research fan-out from one address is the fastest way to push every query onto the last rung of the engine ladder. The response reports proxied: true|false so you can tell which IP a thin result set came from.
  • The proxy address is SSRF-guarded like the target URL, with --allow-internal to opt in to a proxy on your own LAN. An unguarded proxy reaches internal services and returns their response bodies, not just connection errors.
  • A bad proxy is an error, never a fallback. Silently egressing from the host IP when you asked for a specific one is worse than failing, because the whole point of asking was that the host IP must not be used. Proxy URLs are redacted from the verb log; responses carry the boolean, never the URL.

With a browser session, vb proxy set also wires the WebRTC leak guard — a tunnelled HTTP request still leaks the real IP via STUN without it.

Attach mode — the practical Cloudflare workaround

For DataDome / Kasada / hardened auth that walls cold-launch automation:

google-chrome --remote-debugging-port=9222 \              --disable-blink-features=AutomationControlled \              --user-data-dir=/tmp/cdp-profile &# log into the walled site by handvb attach http://localhost:9222vb go https://target.example.com        # now reads as your real browser

Patchright's CDP-layer stealth still applies over connect_over_cdp — attach mode gets the same protocol-level patches as cold launch, plus your real-browser fingerprint and any cookies from the manual login.

Launch flags are yours on this tier. On cold launch the backend supplies --disable-blink-features=AutomationControlled for you. Attach connects to a Chrome that is already running, so nothing vibatchium does can add a launch flag after the fact — if you started Chrome without it, that tell is present for the whole session. Include it in the command above.

--remote-debugging-port is an open door. It grants full browser control to any process on the machine, and a page you visit can probe localhost to discover it. Use it on a machine you trust, and close Chrome when you're done.

Security model

vibatchium is built to drive real logins from an untrusted agent loop, so the threat model is "a credential must never reach the model, a screenshot, or a log":

  • Encrypted vault. Passwords and TOTP secrets live in an XSalsa20-Poly1305 vault keyed from the OS keyring or VIBATCHIUM_SECRETS_KEY. A resolved secret never appears in logs, HAR captures, the observe cache, or any agent-visible response field (grep-tested in CI).
  • Secrets are never rendered in the clear. fill --use-secret masks the field in the page (-webkit-text-security), applied before the value is written, so every path that turns the viewport into bytes — the screenshot verb, the 5 fps live-view stream, and VLM vision_* calls that ship the frame to a model — captures dots, not the value. The mask fails closed (no write if it can't be confirmed), covers password fields so a show-password toggle can't unmask, and the accessibility snapshot returned by map / diff_map strips masked values so the secret can't leak into the model's context as text either.
  • Secrets are origin-bound. fill --use-secret github.com:password only writes into a document on that site — https, github.com or a subdomain, judged by the frame that owns the field (so an iframe can't borrow the top page's origin) — or into the entry's explicit origins list. Anywhere else it refuses before the secret is resolved, so a prompt-injected agent can't type your password into a lookalike page. Framed login pages, about:blank frames and pages the agent already ran eval in are refused too; while the secret sits in a field, value / eval are refused so it can't be read back; and the write uses the field's own value setter, never focus + keyboard, so page script can't redirect it. If the field is swapped mid-fill, it's cleared and the call fails. The escape hatches (--allow-cross-origin, two daemon env vars) are shell-only; MCP refuses them, along with vault edits and secret totp.
  • Live-view is authenticated. The WebSocket requires a per-server token and rejects foreign-Origin connections (the CSWSH class), and driving the page is a separate token from watch-only — a read-only link can be shared without handing over the keyboard. Binds 127.0.0.1 by default (--insecure-public to override).
  • Scraped content is marked untrusted. MCP verbs that return page-derived text carry openWorldHint, so a host can taint the output against prompt injection instead of treating a scraped page as instructions; pure probes are readOnlyHint and mutating verbs (stop, secret_delete, storage_restore) are destructiveHint.
  • REST shim. Without --caps, the bearer token grants every verb including eval, secret_*, and file-writing verbs — local-code-equivalent, so always pass --caps=... in hosted mode. All vibatchium-written files are 0600; directories 0700.

Honest limits

  • 5+ concurrent sessions = 1-2GB RAM. Each persistent-context Chrome is ~200-400MB. Bump cap with VIBATCHIUM_MAX_SESSIONS=8.

  • Vision spend cap is process-wide. N fan-out agents share one daily/lifetime budget.

  • Init scripts don't work on patchright backend. chrome.runtime stays undefined — accepted trade for stealth wins.

  • Login walls (X, LinkedIn) require attach mode. Cold-launch fan-out can't defeat sites requiring authenticated sessions.

  • Synthetic input has a CDP coordinate signature. Every click/type/hover/scroll rides Playwright over CDP Input.dispatchMouseEvent/dispatchKeyEvent (pageX==screenX, no CoalescedEvents). Patchright patches the JS-context leaks, not the Input domain, and humanize on improves trajectory/timing realism but does not change the per-event signature. Behavioral walls that fingerprint it (DataDome/Kasada/HUMAN) want attach-mode against a real headful Chrome you drive — OS-level synthetic input (CDP-Patches) is headful + active-tab only and doesn't fit a headless, N-parallel daemon.

  • fetch is a static-fingerprint lane, not a browser. The curl_cffi fetch verb matches Chrome's JA3/HTTP2 but runs no JavaScript — it clears TLS-fingerprint gates, not DataDome/Kasada/Turnstile JS challenges. Fall back to go for those.

  • Single daemon = single point of failure. No HA built in.

  • Behavioural detection now targets the humanizer directly. Cloudflare's 2026 bot-detection work names mathematically ideal Bézier cursor paths and superhuman click precision as tells. humanize improves on nothing-at-all, but it is a pointer-trajectory model, not a physiological one — and it is off by default, which on a behaviourally-scored site is the louder of the two states.

  • One burned profile can taint every account that shares it. Vendors now link device telemetry across sessions and accounts. Use one profile per account, never share a profile between identities, and don't reuse a profile that has already been challenged.

  • The fetch and search lanes are outside prompt-injection scanning. The scanner covers page-content verbs (text, html, extract, map, …). SERP titles and fetched bodies are third-party text going straight into an agent's context and are not scanned today. Treat them as untrusted input.

  • Cloudflare's 2026-09-15 default is policy, not detection. For new domains and free-plan zones, Cloudflare now blocks Training and Agent crawlers by default on ad-monetized pages. It targets crawlers that declare themselves (user-agent or Web Bot Auth signature), so it doesn't change what a real Chrome session looks like — but the fingerprint and behavioural scoring above is a separate axis that moves independently of anything announced in a blog post.

Updating

bash
vb update                  # upgrade + bounce the daemon + refresh the agent skillvb update --version 0.19.0   # or pin a specific version

vb update detects how vibatchium was installed (pipx, uv tool install, a pip-less uv venv, or pip with a PEP-668 --break-system-packages fallback), stops the running daemon so the next command loads the new code, and rewrites the agent skill / docs blocks so a coding agent is actually told about the verbs the new version ships (--no-restart / --no-setup opt out). Manual equivalent:

bash
pipx upgrade vibatchium    # or: uv tool upgrade vibatchium / pip install -U vibatchiumvb shutdown                # bounce the daemon — it serves old code until you dovb setup                   # refresh the agent skill + docsvb --version               # confirm

The daemon-restart step is the one people miss: the long-running daemon keeps serving the old version until it's bounced. vb update does it for you; if you upgrade by hand, run vb shutdown (the next vb call auto-respawns the new version). Optional features upgrade via pipx install 'vibatchium[all]' --force.

Running from a git checkout

git pull updates the source; whether it updates what vb actually runs depends on the install, and two of the three ways it can fail are silent:

bash
vb --version && git describe --tags   # do they agree? if not, the install COPIED                                      # the source — reinstall editable:                                      #   uv pip install -e '.[all]'vb status                             # warns when the daemon predates the source                                      # ("stale_code") — bounce with `vb shutdown`

A version-string compare cannot catch a checkout: git pull changes the code without changing __version__. vb status compares the daemon's boot time against the newest source file instead, and vb update bounces the daemon only when it is provably behind — so it never drops live sessions for nothing.

New cap buckets need a re-register

The MCP server's --caps list is frozen into your agent's config at first registration, so a bucket added by a later release (0.19.0 added search) stays invisible no matter how many times you upgrade. Re-running vb setup reports the drift but deliberately won't overwrite a --caps you set by hand:

bash
vb setup                              # reports any cap drift, changes nothingvb setup --force --caps lean,search   # apply it — exposes `vb search` as a tool

Restart the agent session afterwards: the MCP tool list is read once, at start.

Server modes

ModeSurfaceAuth
vb mcpstdio JSON-RPC; defaults to the lean 89-verb profile (--caps min = 12 tools for clients without tool search; --caps=full/all = 165; --caps=... for a custom bucket set)n/a (stdio)
vb serveFastAPI on 127.0.0.1:8000; every verb at POST /v1/<verb>; WebSocket live-view at /v1/stream/<session>bearer token (~/.cache/vibatchium/rest-token, mode 0600)

REST capability gating: vb serve --caps=core,nav,input,vision restricts the HTTP surface the same way mcp --caps does. Without it, REST grants local-code-equivalent access (eval + secret_* + file-writing verbs all exposed) — safe for localhost dev, not for hosted/multi-tenant.

Documentation

  • AGENTS.md — coding-agent contract (Codex / Cursor / Claude Code)

Authorized use

vibatchium is built to drive sessions you own, with your credentials, on your machine — your accounts, your employer's, or a client's with their written permission. It is a tool for automating access you already have.

That boundary is not a formality, though the law around it moved in 2026. A US district court had granted a preliminary injunction against an AI agent that accessed password-protected pages through the user's own logged-in account, holding that the user's permission is not the platform's authorization. On 4 August 2026 the Ninth Circuit vacated that injunction and remanded (Amazon.com Services, LLC v. Perplexity AI, Inc., No. 26-1444, published), concluding that the operator had not "accessed" the plaintiff's computers under the CFAA at all — "it was the user who accessed [them], with the help of [the] AI agent." The California CDAFA claim failed for the same reason.

Read that narrowly. It decides who accessed a computer, not whether evading a technical block is access "without authorization"; the panel never reached circumvention. A vacated preliminary injunction on remand is not a merits ruling, and it leaves contract, terms-of-service, trespass and copyright theories entirely untouched. What it does support is the shape of the tool: the browser runs on your machine, under your login, and the reasoning leaned on exactly that — no operator computer ever touched the other side's servers.

Scraping a site's public pages, evading a wall you have no account behind, or automating an account whose terms forbid it remain decisions you are making, and the consequences are yours.

Check the terms of the site you are automating. If you are acting for someone else, get it in writing.

License

Apache-2.0 core. Every default-install extra is permissive too — the fetch lane's curl_cffi is MIT. The only copyleft option is the opt-in nodriver backend (AGPL-3.0) — consult licensing before integrating it commercially. Nothing GPL/AGPL ships in the base install or [all].

來源:README.md,提交 97f89e6

工具

89

start

Start a browser session (cold-launch real Chrome).

輸入參數leasescalebackendprofilesessionheadlessephemeral

attach

Attach to an existing Chrome via CDP (use after manual login on a Cloudflare-walled site).

輸入參數leasecdp_urlsession

stop

Stop the browser session.

輸入參數leasesession

status

Daemon + session status.

輸入參數leasesession

verify_url

Fast pre-check (DNS, optional HTTP HEAD) for a URL before `go` commits to a 30s navigation timeout. Catches typos and dead domains in ~50ms instead of 30s.

輸入參數url必填leasesessioncheck_httptimeout_ms

set_log_verbs

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.

輸入參數on必填leasesession

explore

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.

輸入參數url必填leaseintentsessionfull_pagekeep_openscreenshotskip_verifymin_text_chars

expect

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.

輸入參數leasestatetargetsessionscreenshottimeout_msallow_walledurl_containstext_contains

go

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.

輸入參數url必填leasesessiontimeout_mswait_until

back

Browser back.

輸入參數leasesession

forward

Browser forward.

輸入參數leasesession

reload

Reload current page.

輸入參數leasesession

url

Get current URL.

輸入參數leasesession

title

Get current page title.

輸入參數leasesession

text

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.

輸入參數leasesettletargetsessionmax_chars

html

Get HTML (whole page or a target — @eN, @text:Foo, @label:Email, CSS, etc.).

輸入參數leasetargetsessionmax_chars

extract

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. `mode`: markdown (default) | links (deduped {url,text}, absolute post-hydration URLs) | assets ({url,type,rel?}, data: dropped) | main (main-content only via density scorer).

輸入參數modeleasetargetsessionmax_charsmax_linksmax_assets

extract_fields

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: `name[]`=array, `sel@attr`=attribute, `sel@html`=innerHTML, bare=text. Optional `target` scopes selectors to a subtree. Returns {fields, matched, misses, errors} — `misses`/`errors` let you fix a selector without re-reading the page. Reads text/attr/innerHTML only, never input values.

輸入參數leasefields必填targetsessionnode_capmax_chars

detect_forms

Structured map of every <form> on the page (plus a formless-controls group for SPAs) — against our real authenticated Chrome DOM. Each field carries a ready-to-use `locator` string (pipe straight into fill/click), plus type, name, label, required, options and checked/filled state. A free-text field's typed value is withheld unless `values=true`, and even then it's redacted when a type/name/autocomplete heuristic flags it as a password/credential/payment secret (best-effort — don't pass values=true on untrusted pages). Returns {forms, count}.

輸入參數leasetargetvaluessessionmax_charsmax_formsmax_fieldsmax_options

candidates

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 `index=N`.

輸入參數leaselimittarget必填session

attr

Get an HTML attribute value from an element.

輸入參數name必填leasetarget必填session

value

Get the current value of an input/textarea/select.

輸入參數leasetarget必填session

eval

Evaluate a JS expression in the page (isolated context per Patchright default — `window.X = ...` mutations are NOT visible to page JS; use `eval_handle` to retain references).

輸入參數expr必填leasesessiontimeout_ms

map

Snapshot actionable elements and assign @eN refs (uses Playwright aria_snapshot mode='ai').

輸入參數depthleaseindentsessionmax_chars

diff_map

Diff current snapshot vs the previous one.

輸入參數leasesession

click

Click an element. Target: an @eN ref from map_compact, visible text (`Add to cart`), @text: / @label: / @role:button[name=Pay], or a CSS selector. If the page covers or disables the target the error says what is in the way.

輸入參數indexleasetarget必填sessiontimeout_msauto_dismiss_banners

dblclick

Double-click an @eN ref or CSS selector.

輸入參數indexleasetarget必填sessiontimeout_ms

focus

Focus an element (without clicking).

輸入參數leasetarget必填sessiontimeout_ms

select

Pick an option on a <select> by value/label/index. Also works on a custom dropdown: pass the button that opens it and the option's label.

輸入參數indexlabelleasevaluetarget必填session

fill

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 `origins`); otherwise refused.

輸入參數textindexleasetarget必填sessiontimeout_msuse_secret

type

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.

輸入參數text必填indexleasetarget必填sessiondelay_ms

hover

Hover over an element.

輸入參數indexleasetarget必填session

press

Press a key on a specific element (e.g. Enter on @e3).

輸入參數keys必填leasetarget必填session

keys

Press a key combination (e.g. 'Control+a', 'Enter').

輸入參數keys必填leasesession

check

Check a checkbox / radio.

輸入參數leasetarget必填session

uncheck

Uncheck a checkbox.

輸入參數leasetarget必填session

scroll

Scroll the page or a target element into view.

輸入參數dxdyleasetargetsession

is_state

Check element state (visible/enabled/checked/...).

輸入參數leasestate必填target必填session

screenshot

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.

輸入參數pathleasetilessessiontile_dirfull_pagemax_tilestile_heightmax_screenshot_px

wait_selector

Wait until an element reaches a state. Takes the same targets as click.

輸入參數leasestatesessionselector必填timeout_ms

wait_ref

Wait until an @eN ref reaches a state.

輸入參數ref必填leasestatesessiontimeout_ms

wait_url

Wait until the URL matches a glob/regex.

輸入參數leasepattern必填sessiontimeout_ms

wait_load

Wait for a page load state (load/domcontentloaded/networkidle).

輸入參數leasestatesessiontimeout_ms

wait_fn

Wait until a JS expression returns truthy.

輸入參數expr必填leasesessiontimeout_ms

pages

List all open browser tabs.

輸入參數leasesession

page_new

Open a new tab and switch to it.

輸入參數leasesession

page_switch

Switch to tab by index.

輸入參數index必填leasesession

page_close

Close the current tab; the next tab becomes active.

輸入參數leasesession

find

Locate elements by semantic strategy (text/label/placeholder/role/testid/xpath/alt/title/css).

輸入參數kind必填nameexactleasequery必填session

count

Count matching elements for a selector or @eN ref.

輸入參數leasetarget必填session

content

Replace the page HTML wholesale via page.set_content.

輸入參數html必填leasesession

frames

List all live frames with name + url + depth + active flag.

輸入參數leasesession

frame

Switch active frame by name or URL substring (omit both to clear).

輸入參數urlnameleasesession

mouse

Mouse control at pixel coordinates.

輸入參數xydxdyleasestepsaction必填buttonsession

upload

Set files on an input[type=file] target.

輸入參數files必填leasetarget必填session

upload_next

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.

輸入參數files必填leasesessiontimeout_s

upload_status

Whether the armed file chooser was filled (consumed), plus how many choosers were swallowed (no arm left) or foreign (from another tab while armed).

輸入參數leasewait_ssession

pdf

Save the current page as PDF.

輸入參數path必填leaseformatsession

highlight

Briefly outline an @eN ref or selector for visual debugging.

輸入參數msleasetarget必填session

screenshot_annotate

Screenshot with @eN bounding-box overlays (vision-LLM friendly).

輸入參數path必填leasesessionfull_page

map_compact

One-line-per-element rendering of the snapshot (token-efficient): `@eN role "name" [state…]`, preserving state ([checked]/[disabled]/[expanded]/[level=N]). `interactive`=only actionable roles; `bbox`=append real bounding_box() coords (bbox=x,y,w,h) — genuine layout geometry.

輸入參數bboxdepthleasesessionmax_charsinteractive

observe

Plan a verb + target for an intent without executing.

輸入參數llmforceleaseintent必填session

act

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: `click Add to cart`, `fill Email with [email protected]`, `select Victoria in State`, `tick Accept terms`. One action per call. Check `executed` and `error`.

輸入參數llmleaseintent必填session

profile_list

List all profiles and the active one (alias of session_list).

輸入參數leasesession

profile_new

Create a new named profile (alias of session_new).

輸入參數name必填leasesession

profile_use

Set the active profile (alias of session_use).

輸入參數name必填leasesession

profile_delete

Delete a profile directory (alias of session_delete).

輸入參數name必填leasesession

session_new

Create a new on-disk session/profile dir (does NOT launch Chrome).

輸入參數name必填leasesession

session_list

List every on-disk session + which are currently running.

輸入參數leasesession

session_use

Set the active session (persisted to active-session file).

輸入參數name必填leasesession

session_switch

Alias for session_use.

輸入參數name必填leasesession

session_close

Stop Chrome for one session (profile dir preserved).

輸入參數nameleasesession

session_close_all

Stop Chrome for every running session.

輸入參數leasesession

session_delete

Delete a session's profile dir on disk (not active/default).

輸入參數name必填leasesession

session_lease

Acquire/renew an exclusive advisory lease on a running session (0.7.0). Returns a token; present it as the `lease` arg on subsequent calls so other clients get a 'busy' error instead of clobbering the shared page.

輸入參數nameleaseownerstealttl_ssession

session_release

Release a session lease — present the token via the `lease` arg, or force=true to break it (operator override).

輸入參數nameforceleasesession

session_lease_info

Report the lease state for a session (never returns the token).

輸入參數nameleasesession

clean

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.

輸入參數keeplogsapplycacheleaselockssessionprofilesolder_thancache_mirrorlog_keep_bytes

humanize_on

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.

輸入參數leasesessionscroll_device

humanize_off

Disable humanize for current session.

輸入參數leasesession

humanize_status

Report whether humanize is on for current session.

輸入參數leasesession

humanize_ambient

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.

輸入參數modeleasescrollsessionhorizon_s

vision_click

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.

輸入參數leasebuttonintent必填sessionmax_per_minutemin_confidence

vision_find

Return coords + confidence for a described element (no click).

輸入參數leaseintent必填sessionmin_confidence

vision_type

vision_click the described field, then type the given text.

輸入參數text必填leaseintent必填sessionmin_confidence

vision_stats

Return cumulative vision API usage (calls, cache_hits, tokens, cost_usd) for session.

輸入參數leasesession

vision_clear_cache

Drop the on-disk vision coords cache.

輸入參數leasesession

vision_budget

Report today + lifetime vision spend vs VIBATCHIUM_VISION_MAX_*_USD caps. reset='today'|'lifetime'|'all' clears the spend log.

輸入參數leaseresetsession

dismiss_banners

Heuristically dismiss cookie/consent/newsletter banners.

輸入參數leasepreferdry_runsessionmax_clicks

版本歷史

5
  1. v0.21.0最新Nov 6, 2026
  2. v0.20.0Oct 7, 2026
  3. v0.19.5Oct 5, 2026
  4. v0.19.4Oct 5, 2026
  5. v0.19.2Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分