# How Ego-Lite Manages CDP Session Attachment and Re-Attachment

> Discover how ego-lite manages CDP session attachment and re-attachment with TTL caching, auto-retry, and self-healing for seamless debugging. Learn more!

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: internals
- Published: 2026-07-31

---

**Ego-Lite automates Chrome DevTools Protocol (CDP) session lifecycle management through TTL-based caching, automatic retry logic, and self-healing re-attachment when sessions expire or targets close.**

The `citrolabs/ego-lite` runtime provides a robust abstraction over Chrome DevTools Protocol (CDP) interactions by handling session attachment and re-attachment automatically. By implementing intelligent caching and error recovery mechanisms in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts), ego-lite ensures that agents can execute CDP commands without manually managing session state or handling transient connection failures.

## Session Acquisition with TTL-Based Caching

When a helper requires a page-level CDP session, the runtime calls `ensureSession()` to validate or create a connection. This function implements a **TTL-based caching strategy** that considers a session valid for only `2000` milliseconds (`SESSION_TTL_MS`).

In [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) (lines 7-12), the implementation first checks `state.sessionId` and its freshness against the TTL threshold. If the cached session is stale or missing, the runtime proceeds to create a new attachment rather than reusing the expired connection.

To prevent race conditions during concurrent access, ego-lite employs an **inflight guard** mechanism. The `state.sessionInflight` promise ensures that multiple simultaneous callers share a single pending attach operation, preventing duplicate session creation requests.

## Attaching to CDP Targets

When a new session is required, the attachment logic queries the browser environment through `ego.listTabs()` to enumerate available targets. The runtime selects a preferred or active tab, then transmits a `Target.attachToTarget` CDP command in flattened mode to obtain a fresh session identifier.

This attachment workflow, implemented in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) (lines 16-36), stores both the returned `sessionId` and `targetId` in the global `state` object defined in [`state.ts`](https://github.com/citrolabs/ego-lite/blob/main/state.ts). These values persist in memory to satisfy subsequent CDP commands without re-negotiating the connection.

## Enabling Page Events Idempotently

After successful attachment, the runtime immediately invokes `enablePageEvents(sessionId)` to activate `Page`-level events such as dialogs and screencast frames. This function, located in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) (lines 5-11), maintains idempotency through a `pageEnabledSessions` Set that tracks which sessions have already been initialized.

If the browser rejects the `Page.enable` command—such as when attaching to internal chrome pages that do not support page events—the runtime gracefully swallows the error and continues execution. This defensive programming ensures that unsupported targets do not crash the automation workflow.

## Automatic Re-Attachment on Session Loss

All CDP commands flow through the `browserCdp()` wrapper function, which implements transparent retry logic for 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 triggers `invalidateSession()` to clear the stale state and immediately calls `ensureSession()` to establish a fresh connection.

This re-attachment logic in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) (lines 95-103) automatically retries the original command with the new session, making session loss invisible to the calling code. The error normalization relies on helpers from [`ego-errors.ts`](https://github.com/citrolabs/ego-lite/blob/main/ego-errors.ts) to classify transient failures versus permanent errors.

## Session Lifecycle Cleanup

Ego-lite monitors for target destruction events to prevent memory leaks and stale state accumulation. When the browser emits `Target.detachedFromTarget` or `Target.targetDestroyed` for the current active target, the cleanup handler in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) (lines 52-64) invokes `invalidateSession()`.

This cleanup routine clears the cached `sessionId`, `targetId`, and any entries in the `pendingDialogs` Map, which tracks JavaScript dialog openings per session. By purging these references immediately upon target destruction, the runtime ensures that subsequent CDP calls trigger fresh attachment rather than attempting to use dead sessions.

## Practical Implementation Examples

The following patterns demonstrate how to leverage ego-lite's automatic session management in agent code:

```typescript
// Navigate using auto-managed session
import { browserCdp } from "./browser-runtime.js";

async function goTo(url: string) {
  // Runtime automatically calls ensureSession() internally
  await browserCdp("Page.navigate", { url });
}

```

```typescript
// Explicit session handling for custom commands
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 examples rely on `browserCdp()` to handle the underlying `ensureSession()` call and automatic retry logic when `SESSION_LOST` errors occur.

## Summary

- **TTL-based caching** (`SESSION_TTL_MS = 2000`) keeps sessions fresh while minimizing re-attachment overhead.
- **Inflight guards** prevent duplicate attach operations during concurrent access through shared promises.
- **Automatic retry logic** in `browserCdp()` detects session loss via regex matching and transparently re-attaches.
- **Graceful degradation** allows the runtime to continue when `Page.enable` fails on unsupported targets.
- **Proactive cleanup** responds to `Target.detachedFromTarget` and `Target.targetDestroyed` events to invalidate stale state.

## Frequently Asked Questions

### How does ego-lite prevent duplicate CDP sessions when multiple operations run concurrently?

Ego-lite uses an inflight guard pattern where `state.sessionInflight` stores a shared Promise during the attachment process. Concurrent callers awaiting `ensureSession()` all receive the same Promise instance, ensuring that only one `Target.attachToTarget` command executes while others wait for the result.

### What happens when a CDP session expires while a command is executing?

If `browserCdp()` detects a `SESSION_LOST` error—matching patterns like "Session not found" or "Target closed"—it automatically calls `invalidateSession()` to clear the stale cache, invokes `ensureSession()` to create a fresh attachment, and retries the original command without throwing an error to the caller.

### Why does ego-lite use a 2000ms TTL for session caching instead of indefinite caching?

The `SESSION_TTL_MS = 2000` constant balances performance against reliability. Short TTLs prevent the runtime from attempting to use sessions that may have been invalidated by browser-side events (such as target crashes or page navigations) while avoiding the overhead of re-attaching for every single CDP command.

### Where does ego-lite store session state between CDP commands?

Mutable session state—including `sessionId`, `sessionAt` timestamp, `preferredTargetId`, and `pageEnabledSessions`—resides in the global `state` object exported from [`state.ts`](https://github.com/citrolabs/ego-lite/blob/main/state.ts). This centralized state management allows [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) functions to coordinate attachment status and cleanup across the entire runtime lifecycle.