How ego-lite's Code-Based Function Call Interface Improves Agent Interaction

TLDR: ego-lite replaces raw Chrome DevTools Protocol (CDP) messages with a high-level JavaScript API that injects helpers like page, locator, and taskSpaces directly into the agent's execution context, enabling deterministic, retry-aware browser automation without protocol complexity.

ego-lite is an open-source browser automation framework from citrolabs that abstracts low-level browser protocols into developer-friendly JavaScript helpers. Instead of forcing agents to construct and manage raw CDP JSON messages, the ego-lite code-based function call interface exposes a structured API that handles session management, element resolution, and error recovery automatically. This approach transforms imperative protocol commands into declarative function calls that run inside a heredoc execution context.

Central Helper Façade (helperContext)

The foundation of the interface is helperContext(), defined in src/helpers.ts (lines 22-36), which aggregates all public helpers into a single object. This façade groups functionality into six primary domains:

  • page – A Playwright-style API for navigation, evaluation, screenshots, and input simulation
  • locator – Chainable, auto-waiting element selectors that handle stability checks internally
  • browser – Tab management operations including listing, switching, opening, and closing contexts
  • taskSpaces – Isolated browsing contexts with ownership semantics for concurrent workflows
  • site – Learned site-skill discovery and execution for domain-specific automation
  • fetch – Unified HTTP client for both server-side and browser-side requests

Each helper is implemented as a pure function that internally coordinates CDP calls, session caching, and error handling. Agents never interact directly with protocol internals; they invoke high-level methods like await page.goto(url) while the runtime manages the underlying complexity.

Automatic Injection into Global Scope

When the ego-lite runtime initializes, installEgoSdk() in src/index.ts (lines 51-73) automatically injects these helpers into the agent's global scope (typically globalThis). The installation process follows a specific readiness pattern:

  1. Synchronous helpers (enumerated in SYNC_HELPERS and SYNC_FACTORY_HELPERS) such as help and page.locator are available immediately
  2. Asynchronous helpers are wrapped via wrapReady() (lines 164-168) to defer execution until the runtime signals readiness

The injection mechanism ensures that within any heredoc script, agents can reference page, locator, taskSpaces, and other utilities without import statements or boilerplate setup. This design choice eliminates configuration overhead and guarantees that the full API surface is available consistently across execution contexts.

Synchronous vs Asynchronous Helper Design

The interface carefully distinguishes between synchronous and asynchronous operations to prevent event-loop blocking while maintaining ergonomics. As implemented in src/index.ts (lines 24-30), the wrapReady function checks helper categories:

  • Synchronous: Returns the original value immediately for utilities like help text or factory methods
  • Asynchronous: Returns a Promise-based wrapper that first awaits the runtime's "ready" state before executing the underlying CDP command

This separation allows agents to write natural async/await patterns (await locator.click()) while the runtime handles the complexity of session initialization and protocol handshake in the background.

High-Level Abstractions Hiding CDP Intricacies

The code-based interface translates low-level browser operations into composable, typed functions that reduce protocol errors and script verbosity.

Locator Abstraction

The createLocator() function in src/helpers.ts (lines 520-610) transforms selector strings into intelligent query engines. It supports "nth" indexing, filtering, and role-based queries while automatically implementing retry logic and element stability checks. Agents write await page.getByRole('button', { name: /submit/i }).click() instead of managing DOM node IDs or CDP node resolution chains.

Task-Space Management

The taskSpaces façade encapsulates complex CDP session lifecycle management. Methods like useOrCreate() and complete() (defined in src/helpers.ts lines 86-118) handle context creation, ownership claiming, and hand-off protocols. Agents can isolate multi-step workflows without manually manipulating browser targets or debugging session leaks.

Site-Skill Integration

Learned site-specific capabilities are exposed through the site helper, which loads skill definitions from src/learning/index.ts. Functions like site.runTool() and site.runBrowserTool() provide first-class access to domain-specific automation patterns while the underlying module loader and sandbox execution remain hidden from the agent.

Consistent Output Handling

installEgoSdk() configures a buffered logging system via createBufferedLog() in src/index.ts (lines 67-73) that intercepts console.log output. Rather than streaming logs immediately, the system accumulates entries and flushes them once the agent script completes. This ensures that agent-generated output is captured reliably and can be combined with runtime status messages without interleaving or corruption.

Practical Code Example

The following script can be run as an ego-lite heredoc (no imports needed):

// Navigate and wait for full load
await page.goto('https://example.com', { waitUntil: 'load' });

// Chain locators with automatic waiting
await page.getByRole('button', { name: /login/i }).click();

// Build complex interactions through method chaining
const loginForm = page.locator('form#login');
await loginForm.getByLabel('Email').fill('agent@example.com');
await loginForm.getByLabel('Password').fill('s3cr3t');
await loginForm.locator('button[type=submit]').click();

// Execute learned site-specific tools
await site.runTool('example.com', 'extractProfile');

// Isolate workflow in dedicated task space
await taskSpaces.useOrCreate('profile-scrape');
await page.goto('https://example.com/profile');
const name = await page.locator('h1').innerText();
await taskSpaces.complete('profile-scrape', { keep: true });

console.log('Finished, name =', name);

Summary

  • helperContext() in src/helpers.ts aggregates six helper categories into a unified façade
  • installEgoSdk() automatically injects helpers into globalThis, eliminating setup boilerplate
  • wrapReady() manages the distinction between synchronous utilities and asynchronous CDP operations
  • Locator abstraction via createLocator() handles element resolution, retries, and stability checks internally
  • Task spaces provide isolated browsing contexts through simple function calls rather than manual session management
  • Buffered logging ensures reliable output capture without streaming complexity

Frequently Asked Questions

What files implement the core function call interface?

The primary implementation resides in src/helpers.ts, which exports the helperContext() façade and all public helpers. src/index.ts handles the injection mechanism through installEgoSdk(). Low-level driver implementations in src/driver/*.ts (including pointer.ts, keyboard.ts, and nav.ts) provide the underlying CDP coordination that the high-level API consumes.

How does ego-lite handle element selection compared to raw CDP?

Instead of requiring agents to construct CDP node resolution chains or manage element IDs, ego-lite exposes the locator helper with methods like getByRole(), getByLabel(), and locator(). These methods, implemented in createLocator() within src/helpers.ts, automatically handle selector parsing, element stability waiting, and retry logic, reducing the likelihood of flaky scripts due to timing issues.

Can agents use these helpers synchronously or only with await?

The interface supports both patterns. Synchronous helpers such as help and locator factories are enumerated in SYNC_HELPERS and available immediately. All other helpers return Promises and must be awaited. The wrapReady() function in src/index.ts enforces this distinction, ensuring that async helpers wait for runtime initialization before executing underlying CDP commands.

What happens to console output from agent scripts?

installEgoSdk() redirects console.log to a buffered sink created by createBufferedLog() in src/index.ts. Output accumulates during script execution and flushes only upon completion, preventing interleaving with runtime status messages and ensuring that structured logging remains intact for downstream processing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →