# What Is the ego-browser Node.js Harness? A Complete Technical Guide

> Discover the ego-browser Node.js harness, a lightweight automation bridge that provides a unified Playwright-style API for AI agents to control the ego-lite browser runtime via CDP bindings. Learn more now.

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

---

**The ego-browser Node.js harness is a lightweight automation bridge that exposes a unified, Playwright-style API for AI agents to control the closed-source ego-lite browser runtime through Chrome DevTools Protocol (CDP) bindings.**

The `ego-browser` package sits between your automation scripts and the underlying browser engine in the citrolabs/ego-lite repository. It transforms low-level CDP commands into high-level, agent-friendly helpers while managing session lifecycle, task-space ownership, and site-specific skill discovery automatically.

## Unified Helper Surface Architecture

At the heart of the harness lies the `helperContext()` function in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts). This factory method constructs a set of **facade objects** that agents interact with instead of importing modules directly.

The helper surface includes:

- **`page`** – Navigation and element interaction methods
- **`browser`** – High-level browser control and CDP session management
- **`taskSpaces`** – Task-space lifecycle API for isolated execution contexts
- **`site`** – Site-specific skill discovery and execution
- **`fetch`** – Network request utilities

These facades abstract the raw ego runtime bindings located in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts), providing a consistent interface regardless of whether code runs as a CLI script or an imported module.

## Global Environment Injection

The `installEgoSdk()` function in [`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts) (lines 44-66) installs the helper facades onto a target object—by default `globalThis`. This ensures that automation scripts can access `page`, `browser`, and other globals without explicit imports.

The installation process performs two critical tasks:

1. **Binds underlying ego runtime methods** to the global scope, connecting the JavaScript facade to the native CDP bridge
2. **Wraps asynchronous helpers** to automatically await a "ready" signal before executing, preventing race conditions during harness initialization

This global injection pattern allows the harness to function as both a standalone CLI tool and a programmatic SDK.

## Session and Task Space Management

The harness tracks CDP sessions and invalidates them automatically on navigation or tab changes. It exposes a high-level **task-space API** through `taskSpaces` (defined in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), lines 52-78) that abstracts the native ego bindings:

- `newTaskSpace()` – Creates isolated execution contexts
- `useOrCreateTaskSpace()` – Reuses existing spaces or provisions new ones
- `claimTaskSpace()` – Acquires ownership for user-controlled sessions

These methods handle the complex lifecycle of browser contexts, ensuring that agents maintain clean state between operations without manually managing CDP session attachments.

## Site-Specific Skill Discovery

Through the **learning subsystem** in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts), the harness can discover, load, and execute site-specific automation tools bundled under `skills/ego-browser/learnings`.

The `site` helper exposes:

- `site.skills` – Lists available learned capabilities for the current domain
- `site.runTool()` – Executes specific learned workflows (e.g., `site.runTool("github", "fetchRepo", {owner: "octocat", repo: "hello-world"})`)
- `site.learnContext()` – Captures new site-specific interaction patterns

This allows the harness to extend its capabilities dynamically based on the target domain, moving beyond generic automation into specialized, learned behaviors.

## Buffered Output and Error Handling

The harness implements a **buffered output sink** via [`src/output-sink.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/output-sink.ts) that captures `console.log` and error output during execution. Rather than streaming logs immediately, it buffers all output and flushes only at process teardown.

This design allows the harness to discard logs entirely if an agent aborts early or encounters a fatal error, preventing noise in partial execution scenarios and ensuring clean output for successful runs.

## Key Source Files and Architecture

Understanding the codebase structure reveals how the harness components interact:

- **[`src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/index.ts)** – CLI entry point and SDK installer containing `installEgoSdk()` and global binding logic
- **[`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)** – Builds the public API facades (`page`, `browser`, `taskSpaces`, `site`, `fetch`) and exports `helperContext()`
- **[`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts)** – Manages CDP transport, session attachment, and event buffering between Node.js and the ego-lite runtime
- **[`src/cdp-eval.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/cdp-eval.ts)** – Low-level CDP evaluation utilities (`cdp`, `evaluate`) used internally by the facades
- **[`src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/state.ts)** – Central mutable state including default timeouts and workspace locations
- **[`src/element-resolver.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/element-resolver.ts)** – Locator resolution and selector parsing for the `page.locator()` API
- **[`src/help-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/help-runtime.ts)** – Generates documentation strings for the `help()` introspection system

## Practical Usage Examples

Install and initialize the harness in your automation script:

```javascript
// Install the harness (normally done automatically by the runtime)
import { installEgoSdk } from "./src/index.js";
installEgoSdk();

// Navigate and interact with pages using the Playwright-style API
await page.goto("https://example.com");
await page.waitForLoadState("networkidle");

// Locate elements using text or CSS selectors
const loginBtn = page.locator("text=Log in");
await loginBtn.click();

// Manage task spaces for isolated sessions
const ts = await taskSpaces.useOrCreate("my-session");
await ts.claim();               // Optional: acquire user ownership
await ts.waitForAgentControl(); // Blocks until agent regains control

// Execute site-specific learned skills
const result = await site.runTool("github", "fetchRepo", { 
  owner: "octocat", 
  repo: "hello-world" 
});
console.log(result);

```

The harness automatically handles CDP session management behind these calls, invalidating cached sessions when navigation occurs and rebinding to new browser contexts as needed.

## Summary

- The **ego-browser Node.js harness** acts as a bridge between AI agents and the ego-lite browser runtime, exposing a unified facade API.
- **`installEgoSdk()`** injects helpers into the global scope and wraps async operations to prevent race conditions.
- **`helperContext()`** constructs the primary facades (`page`, `browser`, `taskSpaces`, `site`) that abstract raw CDP bindings.
- The harness manages **CDP session lifecycle** automatically, invalidating and rebinding sessions on navigation events.
- **Task spaces** provide isolated execution contexts with ownership semantics via `useOrCreateTaskSpace()` and `claim()`.
- The **learning subsystem** enables dynamic loading of site-specific skills from the `skills/ego-browser/learnings` directory.
- **Buffered output** in [`src/output-sink.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/output-sink.ts) captures logs and only flushes at process teardown, allowing clean abort handling.

## Frequently Asked Questions

### What is the difference between ego-browser and Playwright?

While both provide high-level browser automation APIs, **ego-browser** specifically wraps the closed-source ego-lite runtime and manages CDP session bindings automatically. Unlike Playwright, which communicates directly with browser binaries, ego-browser acts as a harness that injects helpers into the global scope and handles task-space ownership patterns unique to the ego-lite architecture.

### How does the harness handle navigation and session invalidation?

The harness monitors CDP events in [`src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/browser-runtime.ts) and automatically invalidates cached session references when navigation or tab changes occur. This prevents "detached frame" errors by ensuring that the `page` and `browser` facades always reference valid execution contexts, rebinding to new sessions transparently behind the API.

### Can I use ego-browser without global installation?

Yes. While `installEgoSdk()` defaults to binding helpers on `globalThis`, you can pass a custom target object to install the SDK into a specific namespace. This allows multiple harness instances or scoped automation contexts within the same Node.js process without polluting the global scope.

### Where are site-specific skills stored and how are they loaded?

Site-specific skills reside in the `skills/ego-browser/learnings` directory as bundled modules. The learning subsystem in [`src/learning/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/learning/index.ts) discovers these modules based on the current domain and loads them dynamically when `site.runTool()` is invoked, extending the harness capabilities without modifying core source code.