# How ego-lite Manages CDP Sessions with a 2-Second TTL

> Discover how ego-lite manages CDP sessions with a 2-second TTL, automatically refreshing stale connections with ensureSession() for seamless browser automation.

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

---

**Ego-lite caches Chrome DevTools Protocol sessions for exactly 2 seconds using a TTL-based expiration mechanism defined in [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts), automatically refreshing stale connections via the `ensureSession()` helper before executing page-level CDP commands.**

Ego-lite provides lightweight browser automation by communicating directly with the Chrome DevTools Protocol (CDP). To minimize connection overhead while preventing stale WebSocket attachments, the framework implements a strict **ego-lite CDP session management** strategy that caches session identifiers for precisely two seconds before requiring refresh.

## The 2-Second TTL Constant

The session lifetime threshold is hardcoded as a constant in the browser runtime module. In [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) at line 5, the codebase defines:

```typescript
// package/ego-browser/src/browser-runtime.ts
export const SESSION_TTL_MS = 2000; // 2 seconds

```

This value represents the maximum age in milliseconds that a cached CDP session remains valid. Once the elapsed time since the last successful attachment exceeds this threshold, the runtime treats the session as expired.

## Session State Architecture

Session metadata persists in a global `state` object defined in [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts). Lines 32-35 declare three critical properties that track the active CDP connection:

```typescript
// package/ego-browser/src/state.ts
export const state = {
  // ... other state properties
  sessionId: null as string | null,        // Active CDP session identifier
  sessionAt: 0 as number,                  // Timestamp of last attach (epoch ms)
  sessionTargetId: null as string | null,  // Target tab or page ID
};

```

These fields enable synchronous validation of session freshness before issuing asynchronous CDP commands.

## The `ensureSession()` Validation Lifecycle

Every helper function that requires a page-level CDP call invokes `await ensureSession()`. This function implements the TTL logic by comparing the current timestamp against `state.sessionAt`:

```typescript
// Conceptual implementation based on browser-runtime.ts patterns
async function ensureSession() {
  const now = Date.now();
  const sessionAge = now - state.sessionAt;
  
  // Check if existing session is still within 2-second TTL
  if (state.sessionId && sessionAge < SESSION_TTL_MS) {
    return state.sessionId; // Reuse valid cached session
  }
  
  // TTL expired or no session exists - refresh required
  return await refreshSession();
}

```

When the session age exceeds 2000ms, the function triggers `refreshSession()`, which detaches from the stale target, establishes a new CDP session via `Target.attachToTarget`, and updates `state.sessionId`, `state.sessionTargetId`, and `state.sessionAt` with current values.

## Automatic Refresh Behavior

The 2-second window creates an aggressive eviction policy that serves two purposes:

- **Prevents stale connections**: WebSocket links to browser targets can crash or timeout; the short TTL ensures ego-lite never attempts to reuse a dead session for more than 2 seconds.
- **Reduces session churn**: Rapid-fire operations completing within 2 seconds reuse the same `sessionId`, avoiding the overhead of repeated Target.attachToTarget calls.

When refreshing, the runtime updates all three state properties atomically to maintain consistency across concurrent operations.

## Summary

- **TTL Definition**: `SESSION_TTL_MS = 2000` in [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) enforces a strict 2-second session lifetime.
- **State Tracking**: The global `state` object maintains `sessionId`, `sessionAt`, and `sessionTargetId` in [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts).
- **Validation**: `ensureSession()` checks `Date.now() - state.sessionAt` against the TTL before every CDP operation.
- **Auto-Refresh**: Expired sessions trigger automatic re-attachment to the Chrome DevTools Protocol target without manual intervention.

## Frequently Asked Questions

### What triggers a CDP session refresh in ego-lite?

A refresh occurs when `ensureSession()` detects that the elapsed time since `state.sessionAt` exceeds `SESSION_TTL_MS` (2000ms). This function runs before every page-level CDP command, automatically detaching from stale targets and creating new sessions when the 2-second TTL expires.

### Why does ego-lite limit CDP sessions to 2 seconds?

The 2-second TTL prevents memory leaks and WebSocket timeouts in long-running automation scripts while allowing batch operations to reuse connections. According to the `citrolabs/ego-lite` source code, this aggressive expiration ensures that crashed or frozen browser targets do not leave zombie sessions in the cache.

### Where is the active CDP session ID stored in ego-lite?

The active session identifier resides in `state.sessionId`, defined in [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts) at line 32. This property updates whenever `ensureSession()` establishes a new connection, alongside `state.sessionAt` (timestamp) and `state.sessionTargetId` (browser tab reference).

### How can I force a new CDP session before the TTL expires?

While the framework handles this automatically, you can manually invalidate the cache by setting `state.sessionAt = 0` or `state.sessionId = null`. The next call to `ensureSession()` will detect the invalid state and trigger a fresh `Target.attachToTarget` request regardless of the 2-second window.