# How ego-lite Manages CDP Sessions and Automatic Re-attachment

> Discover how ego-lite manages CDP sessions with a 2-second TTL and automatic re-attachment. Learn about its centralized state management and transparent retry logic.

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

---

**ego-lite maintains a 2-second TTL-based CDP session that automatically re-attaches to the browser when connections are lost, using centralized state management and transparent retry logic.**

The `citrolabs/ego-lite` browser automation framework communicates with Chromium through the Chrome DevTools Protocol (CDP) using a resilient session management architecture. This article examines how ego-lite handles CDP session lifecycle, implements automatic re-attachment, and maintains connection state to ensure uninterrupted browser automation.

## Session TTL and Validation

ego-lite considers a CDP session valid for **2 seconds** after creation, defined by the `SESSION_TTL_MS = 2000` constant in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) (line 5). After this period, the runtime treats the session as expired and requests a new one.

Every helper function that requires a page-level CDP call first invokes **`ensureSession()`** (lines 7-44). This function checks `state.sessionId` and validates whether the session has exceeded the TTL using the `sessionAt` timestamp. If the session is missing or stale, `ensureSession()` automatically creates a fresh session.

## Session Creation and Target Attachment

When `ensureSession()` determines a new session is needed, it executes the following sequence (lines 16-36 in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts)):

1. Lists all available tabs using `browserEgo().listTabs()`
2. Selects the target tab based on priority: `state.preferredTargetId` if set, otherwise the active tab, or the last tab
3. Calls `Target.attachToTarget` with flattened mode to obtain a new session ID
4. Stores the session ID in `state.sessionId` and updates `state.sessionAt` with the current timestamp
5. Invokes `enablePageEvents(state.sessionId)` to buffer page events like `Page.loadEventFired`

Developers can force attachment to a specific tab by setting **`state.preferredTargetId`** via the `setPreferredTarget()` function (lines 56-58).

## Automatic Re-attachment Mechanism

Session loss is handled transparently through the **`browserCdp`** function's error handling logic (lines 95-103). When a CDP request fails with a "session not found" or "Target closed" error (matched against the `SESSION_LOST` regex), the runtime:

1. Checks if the call was explicitly bound to a session
2. If not bound, calls **`invalidateSession()`** (lines 46-54) to clear `state.sessionId` and associated caches (`pageEnabledSessions`, `pendingDialogs`)
3. Retries the original request with a newly created session via `ensureSession()`

This automatic retry mechanism ensures that transient connection failures do not interrupt automation scripts.

## Central State Management

All session-related state lives in the exported **`state`** object defined in [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) (lines 24-38):

- **`sessionId`**: Current CDP session identifier
- **`sessionTargetId`**: The target (tab) to which the session is attached
- **`sessionAt`**: Timestamp of last successful session acquisition (used for TTL validation)
- **`sessionInflight`**: Promise tracking ongoing session creation to prevent duplicate work
- **`preferredTargetId`**: Optional override specifying which tab to attach to
- **`defaultTimeout`**: Default CDP request timeout (10 seconds)

## Practical Implementation Examples

The following examples demonstrate how to interact with ego-lite's session management:

```typescript
// Force the runtime to use a specific tab
import { browserCdp, setPreferredTarget } from "ego-browser";

setPreferredTarget("target-id-123");

// Page-level CDP commands automatically ensure a valid session
const result = await browserCdp("Page.navigate", { url: "https://example.com" });
console.log(result);

```

```typescript
// Manual session invalidation for advanced error handling
import { browserCdp, invalidateSession } from "ego-browser";

try {
  await browserCdp("Runtime.evaluate", { expression: "document.title" });
} catch (err) {
  if (/Session.*not found/.test(err.message)) {
    invalidateSession(); // Force fresh attachment
    const title = await browserCdp("Runtime.evaluate", { expression: "document.title" });
    console.log("Recovered title:", title);
  } else {
    throw err;
  }
}

```

## Summary

- **Session TTL**: CDP sessions remain valid for 2 seconds (`SESSION_TTL_MS = 2000`) before requiring renewal
- **Automatic Creation**: The `ensureSession()` function in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) handles lazy session initialization and tab selection
- **Transparent Recovery**: The `browserCdp` function automatically retries failed requests after calling `invalidateSession()` when session loss is detected
- **Centralized State**: Session metadata is stored in the mutable `state` object from [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts), including IDs, timestamps, and configuration
- **Tab Targeting**: Use `setPreferredTarget()` to force attachment to specific tabs via `state.preferredTargetId`

## Frequently Asked Questions

### How long does ego-lite keep a CDP session active?

ego-lite maintains a CDP session for **2 seconds** after creation. The `SESSION_TTL_MS` constant in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) defines this duration, after which `ensureSession()` automatically creates a new session on the next page-level CDP call.

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

When a request fails with a session error, `browserCdp` catches the exception using the `SESSION_LOST` regex, calls `invalidateSession()` to clear the cached ID, and transparently retries the request with a fresh session. This occurs in lines 95-103 of [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts).

### Can I force ego-lite to use a specific browser tab?

Yes. Call `setPreferredTarget(targetId)` to set `state.preferredTargetId`. During the next session creation, `ensureSession()` will prioritize this target ID when calling `Target.attachToTarget`, ensuring attachment to your specified tab.

### Where is session state stored in ego-lite?

Session state resides in the exported `state` object defined in [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) (lines 24-38). This includes `sessionId`, `sessionTargetId`, `sessionAt` timestamps, and the `sessionInflight` promise used to prevent duplicate session creation requests.