What Components Does the ego‑browser Runtime Own? A Deep Dive into ego‑lite's Core CDP Layer
The ego‑browser runtime owns the Chrome DevTools Protocol (CDP) transport, session management, event buffering, and runtime-wide services that higher-level automation helpers depend on.
The ego‑browser runtime is the foundational layer of the ego‑lite agent-automation stack. It sits below navigation, pointer actions, and site-specific learning systems, providing deterministic low-level browser control through CDP. Understanding what the ego-browser runtime owns helps you extend the codebase or debug protocol-level issues.
CDP Transport and Message Plumbing
At its core, the runtime manages all raw CDP communication. This happens through two key functions in src/browser-runtime.ts:
rawCdp()– Sends arbitrary CDP messages viaglobalThis.ego.sendCDPMessageand returns parsed JSON responsesbrowserCdp()– A wrapped variant that injects the current session ID automatically
import { browserCdp } from "./browser-runtime.js";
// Execute a raw CDP command through the runtime
const version = await browserCdp("Browser.getVersion", {}, sessionId);
The transport layer handles WebSocket-level framing, message correlation via id fields, and error conversion through handleSendError() (lines 24–33). When globalThis.ego.sendCDPMessage fails, the runtime produces standardized EgoError objects with consistent wording.
Session Management and Lifecycle
The ego-browser runtime owns session attachment and caching. The ensureSession() function (lines 107–154):
- Checks
state.tsfor a cached session ID with 2-second TTL - Attaches to the current target via
Target.attachToTargetif needed - Returns a valid session for subsequent CDP calls
When sessions detach unexpectedly—whether from target crashes or navigation—the runtime automatically re-attaches. Call invalidateSession() to force a fresh attachment on the next call.
import { ensureSession, invalidateSession } from "./browser-runtime.js";
async function robustOperation() {
try {
const session = await ensureSession();
return await browserCdp("Runtime.evaluate", { expression: "1+1" }, session);
} catch (err) {
invalidateSession(); // Force re-attachment for next attempt
throw err;
}
}
Session state lives in src/state.ts, which exports a singleton storing the current ID, TTL timestamp, and runtime overrides.
Event Buffering and Subscription System
The runtime maintains a ring buffer of 10,000 CDP events for all messages not explicitly subscribed to. This enables retrospective inspection and race-condition-free event handling.
| Component | Purpose | Location |
|---|---|---|
events array |
Circular buffer storage | Lines 8–11 |
MAX_BUFFERED_EVENTS |
10,000 entry limit | Constant definition |
drainBrowserEvents() |
Consume buffered events in chronological order | Lines 58–66 |
For targeted event handling, the runtime provides:
subscribeBrowserEvent(method, listener)– Register persistent listeners for specific CDP methods (e.g.,Target.detachedFromTarget)waitForBrowserEvent(predicate, timeout)– Promise-based wait that resolves when incoming events match a condition
import { waitForBrowserEvent, subscribeBrowserEvent } from "./browser-runtime.js";
// One-off wait for navigation completion
const loaded = await waitForBrowserEvent(
(ev) => ev.method === "Page.loadEventFired",
30_000
);
// Persistent subscription for target detachments
subscribeBrowserEvent("Target.detachedFromTarget", (ev) => {
console.warn("Target lost:", ev.params.targetId);
});
The eventSubscribers set (lines 88–96) tracks persistent listeners, while eventWaiters holds transient promise resolvers matched in handleMessage() (lines 69–84).
JavaScript Dialog Tracking
Page dialogs (alerts, confirms, prompts) require special tracking because they block execution. The runtime owns pendingDialogs, a Map keyed by targetId that stores:
Page.javascriptDialogOpeningevents when dialogs appearPage.javascriptDialogClosedevents when they dismiss
Drivers query this map to detect and handle blocking dialogs without polling CDP repeatedly.
Snapshot Reference Mapping
After accessibility tree snapshots, the runtime converts backend node IDs to a workable RefMap via browserSnapshotRefsToRefMap() (lines 293–326). This utility bridges CDP's Accessibility.getFullAXTree responses with the higher-level element resolver in src/element-resolver.ts.
What the Runtime Explicitly Does NOT Own
The ego-browser runtime is deliberately thin. Per the source architecture, these responsibilities live elsewhere:
| Responsibility | Owner Module |
|---|---|
| Navigation and history | src/driver/nav.ts |
| Pointer actions (clicks, drags) | src/driver/pointer.ts |
| Keyboard input | src/driver/keyboard.ts |
| Element resolution from selectors | src/element-resolver.ts |
| Site-specific learning data | Learning subsystem (separate package) |
| Public helper API surface | src/helpers.ts and src/help-runtime.ts |
These modules import from the runtime but the runtime has no reverse dependencies—maintaining clean layer separation.
Key Files and Their Roles
src/browser-runtime.ts– Core runtime implementation with all components abovesrc/state.ts– Singleton state storage consumed by the runtimesrc/cdp-eval.ts– Thincdp()andjs()wrappers built on runtime primitivessrc/driver/*.ts– High-level automation building on the runtime APIsrc/helpers.ts– Public-facing helpers that agents import; forwards to runtime internally
Summary
- The ego-browser runtime owns CDP transport, session lifecycle, and event infrastructure in ego-lite
- Key functions:
browserCdp(),ensureSession(),waitForBrowserEvent(),subscribeBrowserEvent(),browserSnapshotRefsToRefMap() - Core file:
src/browser-runtime.tswith supporting state insrc/state.ts - 10,000-entry ring buffer enables retrospective event inspection
- Explicitly excludes navigation, pointer actions, and site logic—those live in
src/driver/*
Frequently Asked Questions
How does the runtime handle session expiration?
The runtime caches session IDs with a 2-second TTL in state.ts. ensureSession() checks this cache before attaching; invalidateSession() clears it to force re-attachment. Automatic re-attachment also triggers on detected session loss.
Can I use the runtime directly without the driver helpers?
Yes. Import from browser-runtime.ts for full control over CDP commands, event waiting, and session management. The driver helpers in src/driver/* are optional conveniences built atop these primitives.
What's the difference between subscribeBrowserEvent and waitForBrowserEvent?
subscribeBrowserEvent() registers persistent listeners for specific CDP methods that fire repeatedly. waitForBrowserEvent() creates one-time promise-based waits that resolve when a predicate matches any incoming event, then auto-cleanup.
How large is the event buffer and can it be configured?
The buffer holds 10,000 events via MAX_BUFFERED_EVENTS (line 9). This is currently a compile-time constant; adjust it in src/browser-runtime.ts and rebuild if your use case demands different retention.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →