# How ego-browser Embeds a Node.js Helper Runtime Inside Chromium

> Discover how ego-browser embeds a Node.js helper runtime in Chromium using a global ego object and CDP transport for a powerful API.

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

---

**ego-browser embeds a Node.js-compatible helper runtime inside Chromium by exposing a global `globalThis.ego` object that provides a thin CDP transport layer, then building a full-featured helper API on top of it.**

ego-browser is the JavaScript runtime component of the ego-lite project (citrolabs/ego-lite). It transforms a standard Chromium build into a programmable browser by embedding Node-style helper functions directly into the browser's JavaScript context. This architecture lets automation scripts run with familiar `await page.goto()` semantics while executing entirely within the Chromium process.

## How the Host Runtime Detection Works

The embedding starts with runtime detection. When [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) loads, it determines whether it's running in CLI mode or inside the ego-lite Chromium host.

```ts
// src/index.ts (excerpt)
if (isDirectCli()) {
  // CLI usage – run user script from stdin
  process.exitCode = await runMain();
} else {
  // Embedded use – expose helpers on the global object
  installEgoSdk();               // <─ attaches helpers to globalThis
}

```

The `isBrowserRuntime()` function in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) performs the actual check:

```ts
// Detects ego-lite host availability
globalThis.ego && typeof globalThis.ego.sendCDPMessage === 'function';

```

This verification ensures the Chromium binary has exposed the expected CDP bridge before proceeding with helper installation.

## The CDP Bridge: globalThis.ego

The ego-lite Chromium build exposes a minimal but complete CDP transport through `globalThis.ego`. This object provides three core methods:

- `sendCDPMessage` — sends raw CDP commands to the browser
- `onCDPMessage` — registers callbacks for CDP events
- `onSendCDPMessageError` — handles transport failures

In [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts), the `browserCdp()` function wraps this interface into a Promise-based API:

```ts
import { browserCdp } from 'ego-browser';

// Enable Network domain via raw CDP
const result = await browserCdp('Network.enable');

```

The [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) module also handles session lifecycle concerns: automatic session attachment, re-attachment on connection loss, buffered event handling during reconnection, and dialog tracking. These mechanisms ensure that transient CDP failures don't break automation scripts.

## Building the Helper Context

Once the host is detected, `installEgoSdk()` in [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) invokes `helpers.helperContext()` from [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) to construct the public API surface. This includes browser automation primitives:

- `click(selector)` — element interaction
- `goto(url)` — navigation
- `snapshot()` — page state capture
- `runSiteTool(name, params)` — site-specific automation extensions

Each helper is wrapped by `wrapReady()` before installation. This wrapper delays actual execution until an optional `ready` promise resolves, preserving "fire-and-forget" semantics required by the browser environment while preventing race conditions during initialization.

## Global Installation and Host Binding

The wrapped helpers are installed onto the global object via `Object.defineProperty`:

```ts
// Manual SDK installation for custom targets
import { installEgoSdk } from 'ego-browser';

const myWindow = {/* a custom global object */};
installEgoSdk(myWindow, { ready: someInitPromise });

```

By default, `target` is `globalThis`, making helpers immediately available to agent scripts injected into the page. The host's `ego` object receives back-references to the installed helpers through `ego.helpers` and exposes site-specific capabilities via `ego.learnings`.

Mutating host methods like `createTab` and `useTaskSpace` are also wrapped to maintain session state consistency. When these methods execute, they trigger `invalidateSession()` or `clearPreferredTarget()` as needed, ensuring that [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) (the singleton runtime state manager) stays synchronized.

## Running Agent Scripts

Automation scripts execute with standard Node-style syntax despite running inside Chromium:

```ts
// Agent script executed via ego-browser
await page.goto('https://example.com');
await click('button#submit');
const screenshot = await screenshot();  // returns a Buffer

```

The [`src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/run.ts) module handles heredoc script execution, injecting all helpers into the runtime context before user code begins.

## Key Files and Their Roles

| File | Responsibility |
|------|---------------|
| [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) | Entry point, runtime detection, SDK installation orchestration |
| [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) | Public helper API implementation (`click`, `goto`, `snapshot`, etc.) |
| [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) | CDP transport, session management, event buffering, reconnection logic |
| [`src/run.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/run.ts) | Script execution harness with helper injection |
| [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) | Singleton state for session IDs, preferred targets, and buffers |

## Summary

- ego-browser detects the ego-lite host through `globalThis.ego.sendCDPMessage` availability
- The host provides a minimal CDP bridge; ego-browser builds a full Node-style API on top
- Helpers are wrapped for readiness signaling, then installed globally via `Object.defineProperty`
- Session state stays consistent through wrapped mutating methods in [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts)
- Agent scripts use familiar `await` syntax while executing entirely within Chromium

## Frequently Asked Questions

### What is ego-lite?

ego-lite is an open-source project (citrolabs/ego-lite) that provides a modified Chromium build with embedded automation capabilities. The "ego" name refers to the global bridge object that enables external JavaScript runtimes to control the browser via CDP.

### Why use CDP instead of DevTools Protocol over WebSocket?

Embedding CDP directly through `globalThis.ego` eliminates network overhead and connection management. The [`browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/browser-runtime.ts) implementation handles session attachment and re-attachment automatically, providing more reliable automation than external WebSocket connections that can drop during page navigations.

### Can ego-browser run outside ego-lite?

Yes, but with reduced functionality. The `isDirectCli()` path in [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) supports standalone execution, though without the `globalThis.ego` bridge, CDP-based helpers will fail. For non-ego-lite environments, manual SDK installation with a custom target object is possible but requires implementing the `sendCDPMessage` interface yourself.

### How does session state persistence work?

The [`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts) module maintains a singleton runtime state including current session IDs, preferred targets, and event buffers. When wrapped methods like `createTab` execute, they call `invalidateSession()` to clear stale state. This design ensures that automation scripts always interact with the correct browser context even as pages navigate or tabs change.