- 01The Command You Type Is Not the Process That Does the Work
- 02One Daemon, Reached Over a Unix Socket
- 03Nothing Running? It Launches Itself
- 04Every Session Gets Its Own Chrome, Its Own Profile
- 05The Protocol Underneath: BiDi, Not Raw CDP
- 06And Back Again — the Full Round Trip
- 07What This Actually Costs
You type a command. A button gets clicked somewhere inside a headless Chrome window you can't see. Then, roughly two hundred milliseconds later, your terminal prints a result and hands control back to you.
That gap is where six separate things happen, in order, every single time. I know because I watched them happen — using ps -eww process inspection, daemon status checks, and a loop of performance.now() calls. Not from reading documentation. From tracing an actual CLI session, process by process, on a live machine.
01 — The Command You Type Is Not the Process That Does the Work
The first surprise: vibium click "button" spins up a brand-new OS process every time you run it. It is not a long-lived client sitting around between calls — it launches, does one thing, prints a result, and exits. Every invocation, from scratch.
That sounds wasteful, and in a narrow sense it is: process spawn is real overhead, paid on every command. But it buys something in exchange — no client-side state to corrupt, no zombie connections, no wondering whether last session's context leaked into this one. Each call starts clean.
02 — One Daemon, Reached Over a Unix Socket
The ephemeral CLI process's first job is to find the thing that actually holds state: a background daemon, listening on a Unix domain socket at ~/Library/Caches/vibium/vibium.sock. This isn't a metaphor — vibium daemon status shows a single PID, and both the CLI and an MCP server connect to that exact same process.
The daemon is a dispatcher, not a shared browser. It routes; it doesn't merge sessions.
03 — Nothing Running? It Launches Itself
Stop the daemon. Stop the browser. Run a command cold. I tested this directly: kill everything, then issue vibium go <url> from a clean slate. The daemon spins up. Chrome spins up. No explicit start command required — the whole stack is lazy by design. You ask for a browser action, and the infrastructure required to perform it materializes on demand.
04 — Every Session Gets Its Own Chrome, Its Own Profile
This is the one I didn't expect going in. Each session — whether launched from the CLI or from an MCP browser_start call — spins up a distinct Chrome-for-Testing process, each with its own freshly-generated temporary --user-data-dir.
I didn't take this on faith. I set a cookie in one session and tried to read it from a second, concurrent one. Empty. No leak, no shared state — verified, not assumed. It's a deliberate isolation boundary: real test isolation for free, and a real cost — a full browser process — for every distinct session you open.
Cross-session cookie leakage was tested directly on this machine, not inferred from behavior. A cookie set in session A read back empty from concurrent session B. See the related session-isolation investigation for the full methodology.
05 — The Protocol Underneath: BiDi, Not Raw CDP
Once the daemon has a live browser, it doesn't poke at Chrome's DevTools Protocol directly. It speaks WebDriver BiDi, a bidirectional WebSocket protocol built for exactly this. The daemon translates the parsed command into a BiDi message, ships it over the socket, and Chrome executes it against the live page: the click dispatch, the JS evaluation, the navigation.
06 — And Back Again — the Full Round Trip
The result retraces the whole path in reverse. Here's the full round trip, laid flat:
07 — What This Actually Costs
Measured, not estimated, from a loop of vibium eval 'performance.now()' against an already-warm daemon and browser:
If you're measuring something with a tight timing window — the exact millisecond gap during which a page silently swallows a click before its JS finishes wiring up — and your own instrumentation contributes two or three unaccounted-for round trips, your measurement is lying to you before you've started. Splitting “read the clock” and “fire the click” across two separate round trips once ate a full trip's worth of latency inside a window that was only ~500ms wide to begin with.
The Takeaway
None of this is in a README. It's what you get from watching the machinery — process tables, socket paths, timing loops — instead of trusting the mental model you'd otherwise assume. The CLI looks like one command hitting one browser. It's actually six hops through a dispatcher, a lazily-launched daemon, and an isolated Chrome process, every time.
If you're building anything that automates a browser and cares about when, not just whether, something happened — that gap between “looks instant” and “is actually six round trips” is exactly where your flaky tests and bad timing data will come from.
This trace has a companion diagram with the full sequence rendered visually: What happens when a vibium CLI call is sent ↗ — and its counterpart for the MCP-driven path, which spends its extra cost on reasoning turns instead of process spawns: the 8-step test case, command by command ↗, walking one real flow through both interfaces side by side.
I welcome comments and contributions on this topic. Find me here: