How Ego-Lite Manages CDP Session Attachment and Caching

Ego-lite implements a TTL-based caching mechanism with automatic re-attachment to handle Chrome DevTools Protocol sessions, storing session IDs for 2000ms and transparently recovering from session loss errors.

Ego-lite, developed by Citrolabs, provides a robust runtime for browser automation that abstracts away the complexity of Chrome DevTools Protocol (CDP) session management. Understanding how ego-lite manages CDP session attachment and caching is essential for developers building reliable browser agents that can recover from target crashes and network interruptions without manual intervention.

Core Session Management in browser-runtime.ts

The heart of ego-lite's CDP handling resides in package/ego-browser/src/browser-runtime.ts. This module implements a three-phase workflow for session acquisition, maintenance, and recovery.

TTL-Based Caching with ensureSession()

When any helper requires a page-level CDP session, the ensureSession() function serves as the primary entry point. The implementation checks a cached session ID stored in state.sessionId and validates its freshness against SESSION_TTL_MS, set to 2000 milliseconds (2 seconds).

If the cached session has exceeded this TTL or does not exist, ensureSession() initiates a new attachment process. This short TTL ensures that sessions remain fresh without forcing excessive re-attachments during rapid successive calls. To prevent race conditions during concurrent access, the function uses an inflight guard (state.sessionInflight) that allows multiple callers to share a single pending promise.

Attaching to Browser Targets

The attachment logic queries the browser for available tabs using ego.listTabs(), selects a preferred or active tab, and executes the Target.attachToTarget CDP command in flattened mode. This operation returns a session ID that, along with the target ID, is stored in the global state object maintained in state.ts.

This process occurs within lines 16-36 of browser-runtime.ts, where the runtime establishes the bi-directional communication channel required for subsequent CDP commands.

Enabling Page Events and Idempotency

After successful attachment, the runtime calls enablePageEvents(sessionId) to activate Page-level events such as JavaScript dialogs and screencast frames. This function maintains a pageEnabledSessions Set to ensure idempotency—calling it multiple times with the same session ID will not send redundant Page.enable commands.

If the target does not support Page.enable (common for internal browser pages), the runtime gracefully swallows the error and continues operation, ensuring maximum compatibility across different browser contexts.

Automatic Re-Attachment on Session Loss

All CDP commands route through the browserCdp() function, which implements a self-healing mechanism for handling session failures. When a request returns an error matching the SESSION_LOST regex pattern (/Session (?:with given id )?not found|Target closed|No session/i), the runtime automatically triggers invalidateSession() to clear the stale cache.

The workflow then executes:

  1. Clear cached session ID and target ID via invalidateSession()
  2. Obtain a fresh session through ensureSession()
  3. Retry the original command transparently

This recovery process, implemented in lines 95-103 of browser-runtime.ts, ensures that transient target closures or session expirations do not propagate as errors to the calling code.

Session Cleanup and Dialog Tracking

The runtime monitors Target.detachedFromTarget and Target.targetDestroyed events to detect when the current target becomes unavailable. Upon receiving these events, invalidateSession() clears not only the cached IDs but also any pending dialog trackers stored in pendingDialogs.

This cleanup prevents memory leaks and ensures that stale dialog state does not persist across session boundaries. The dialog tracking system maps session IDs to active JavaScript dialogs, automatically clearing entries when dialogs close or sessions invalidate.

Practical Implementation Examples

The following examples demonstrate how to leverage ego-lite's automatic session management in your automation scripts.

Automatic Session Handling

import { browserCdp } from "./browser-runtime.js";

async function goTo(url: string) {
  // No explicit session ID required—ego-lite manages attachment
  await browserCdp("Page.navigate", { url });
}

Explicit Session Control

import { state, ensureSession, browserCdp } from "./browser-runtime.js";

async function screenshot() {
  const session = await ensureSession();          // attach if needed
  const { data } = await browserCdp("Page.captureScreenshot", {}, session);
  return Buffer.from(data, "base64");
}

Both patterns rely on browserCdp() to handle the underlying ensureSession() call and automatic retry logic when SESSION_LOST errors occur.

Summary

  • TTL-based caching: Sessions remain valid for 2000ms (SESSION_TTL_MS) to balance freshness with performance.
  • Automatic attachment: The ensureSession() function in browser-runtime.ts handles tab selection and Target.attachToTarget transparently.
  • Self-healing connections: browserCdp() detects session loss via regex matching and automatically re-attaches using invalidateSession() and retry logic.
  • Concurrent safety: An inflight guard prevents multiple simultaneous attachment attempts when concurrent callers request sessions.
  • Graceful degradation: Page event enabling fails silently on unsupported targets, and dialog tracking cleans up automatically on session loss.

Frequently Asked Questions

How long does ego-lite cache a CDP session before requiring re-attachment?

Ego-lite caches CDP sessions for 2000 milliseconds (2 seconds) as defined by the SESSION_TTL_MS constant in browser-runtime.ts. After this TTL expires, the next call to ensureSession() will trigger a fresh attachment to the browser target, ensuring the session remains valid while minimizing unnecessary re-attachment overhead.

What happens when a CDP session is lost during command execution?

When browserCdp() detects a session loss error matching the SESSION_LOST regex pattern (including messages like "Session not found" or "Target closed"), it automatically calls invalidateSession() to clear the stale state. The runtime then acquires a new session via ensureSession() and retries the original command transparently without throwing an error to the caller, as implemented in lines 95-103 of browser-runtime.ts.

Can multiple concurrent operations share the same CDP session attachment process?

Yes. Ego-lite implements an inflight guard using state.sessionInflight to ensure that concurrent callers share a single pending promise during the attachment process. This prevents race conditions where multiple simultaneous calls to ensureSession() would otherwise create redundant sessions, ensuring only one Target.attachToTarget operation executes at a time.

Where does ego-lite store the active session and target IDs?

The runtime maintains mutable state in package/ego-browser/src/state.ts, which holds sessionId, sessionAt (timestamp for TTL validation), preferredTargetId, and other runtime metadata. The browser-runtime.ts module imports this state object to check cache validity and store new attachment credentials.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →