How ego-lite Implements Task Space Isolation for Concurrent Agent Tasks

ego-lite isolates concurrent agent tasks using sandboxed "task spaces"—lightweight browsing contexts that encapsulate separate CDP sessions, DOM snapshots, and event queues—enforced through numeric IDs, strict ownership models, and per-space reference maps that prevent state leakage between parallel automation workflows.

The citrolabs/ego-lite repository provides a browser automation framework designed for concurrent AI agent operations. Task space isolation ensures that multiple agents can execute simultaneously without sharing browser state, cookies, or DOM node references, with each agent receiving its own dedicated CDP session and isolated browsing context maintained in src/state.ts.

Core Isolation Architecture

The Task Space Registry

In src/state.ts, ego-lite maintains a singleton registry at state.taskSpaces that tracks all active spaces. This registry stores ownership metadata, creation timestamps, and the underlying CDP session for each space, guaranteeing that concurrent agents never share the same BrowserRuntime instance.

Numeric ID System

Every task space receives a stable numeric id (e.g., 42) that persists across execution rounds. This ID-based addressing prevents collisions when multiple agents create spaces simultaneously, while optional human-readable names provide convenience without sacrificing uniqueness or isolation boundaries.

Ownership and Access Control

Agent-Owned vs User-Owned Spaces

Task spaces implement a strict ownership model distinguishing between agent and user control. By default, spaces created through automation are agent-owned, but users can claim browser tabs through claimTaskSpace(). Only the current owner may switch to or manipulate a space, preventing accidental hijacking of user-controlled tabs by parallel automation scripts.

Creating and Reusing Spaces

The useOrCreateTaskSpace(nameOrId) function in src/helpers.ts implements a safe reuse pattern: it first attempts to locate an existing agent-owned space matching the identifier, and only creates a fresh context if none exists. This function explicitly avoids auto-claiming user-owned spaces, ensuring that manual browser tabs remain protected from automated takeover.

Lifecycle and Session Management

Switching Contexts Safely

The switchTaskSpace(space) helper validates ownership before changing the active CDP session. This check ensures agents cannot inject commands into spaces they do not own, maintaining isolation even when agents execute interleaved operations.

Explicit Teardown with completeTaskSpace

When tasks finish, completeTaskSpace(nameOrId, { keep }) handles cleanup. The mandatory keep parameter forces explicit decisions about tab persistence—setting keep: true preserves the tab for debugging, while the default destroys the isolated context and releases associated resources from the registry.

Reference Isolation and Safety

Per-Space Reference Maps

In src/ref-map.ts, ego-lite maintains separate reference maps for each task space. DOM elements are tracked as backend node IDs (e.g., @21, @22) that are unique within their space but isolated from other contexts. If an agent attempts to use a reference from a different space, the system triggers an automatic re-snapshot that safely fails rather than leaking state across boundaries.

Coordination Workflows

Hand-Off Patterns for Human-in-the-Loop

For interactive scenarios, handOffTaskSpace() transfers ownership to the user, while waitForAgentControl() pauses the agent until takeOverTaskSpace() returns control. In src/browser-runtime.ts, each space maintains its own CDP transport layer, ensuring that temporary human interactions do not expose other agent spaces to the user session.

Implementation Examples

Creating or reusing an agent-owned space:

// Grab an existing space named "order-flow" or create a new one.
const space = await useOrCreateTaskSpace('order-flow');
// The helper automatically ensures the space is owned by the agent.

Source: src/helpers.tsuseOrCreateTaskSpace implementation.

Claiming a user-owned space:

// The user previously opened a tab "shopping-cart". The agent now claims it.
const space = await claimTaskSpace('shopping-cart');
// After claiming, the agent can switch to it.
await switchTaskSpace(space);

Source: src/helpers.tsclaimTaskSpace.

Handing off to a human user:

await handOffTaskSpace(space);    // User now controls the tab.
await waitForAgentControl(space); // Agent pauses until it gets the tab back.

Source: src/helpers.tshandOffTaskSpace, waitForAgentControl.

Completing a task with optional persistence:

// Tear down the space after the task, but keep the tab for debugging.
await completeTaskSpace(space.id, { keep: true });

Source: src/helpers.tscompleteTaskSpace.

Safe cross-space reference handling:

// In space A we capture a ref.
const buttonRef = await $(`button=Submit`);   // → @23

// Trying to use @23 in space B triggers an automatic re-snapshot.
await switchTaskSpace(spaceB);
await click(@23);   // Re-snapshot occurs; error if element not present.

Source: src/ref-map.ts – ref-map lifecycle.

Summary

  • Sandboxed contexts: Each task space encapsulates its own CDP session, DOM snapshot, and event queue in src/browser-runtime.ts.
  • Collision prevention: Numeric IDs and the ownership model in state.taskSpaces ensure parallel agents never share browser tabs.
  • Explicit lifecycle: The completeTaskSpace function requires intentional decisions about tab persistence via the mandatory keep flag.
  • Reference safety: Per-space ref maps in src/ref-map.ts isolate backend node IDs, with automatic re-snapshotting preventing cross-space DOM access.
  • Coordinated hand-offs: The hand-off API enables temporary user control without breaking isolation boundaries between concurrent agent tasks.

Frequently Asked Questions

How does ego-lite prevent two agents from controlling the same browser tab?

ego-lite enforces an ownership model where only the current owner (agent or user) can manipulate a task space. The switchTaskSpace() function validates ownership before changing contexts, and useOrCreateTaskSpace() refuses to auto-claim user-owned spaces, ensuring that parallel agents cannot accidentally share tabs or interfere with manual browsing sessions.

What happens if an agent uses a DOM reference from another task space?

The reference map system in src/ref-map.ts tracks backend node IDs per space. If an agent attempts to use a reference like @23 in a space where it was not captured, the system triggers an automatic re-snapshot. This operation fails safely rather than accessing the wrong DOM node, preventing state leakage between isolated contexts.

Can multiple agents reuse the same task space?

Yes, but only sequentially and only when owned by the agent. The useOrCreateTaskSpace() function allows agents to reconnect to their existing spaces using stable numeric IDs or names. However, concurrent access is prohibited by the ownership model—two agents cannot simultaneously switch to the same space, ensuring true isolation during parallel execution.

How does task space isolation handle user-interactive workflows?

The hand-off API (handOffTaskSpace, takeOverTaskSpace, waitForAgentControl) enables temporary transfers of ownership to users. During hand-off, the agent releases control and pauses execution, ensuring that human interactions occur within the same isolated context without exposing other agent spaces to the user session or allowing interference with automated workflows.

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 →