# How ego-lite Enables Parallel Execution for AI Agents and Human Users in a Browser

> Discover how ego-lite enables parallel execution for AI agents and human users in a browser. Its task space isolation prevents state collisions for seamless concurrent operation.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-08-22

---

**TLDR:** ego-lite achieves parallel execution for AI agents and human users in a browser by isolating each actor inside its own task space, a lightweight container that owns a dedicated CDP session, snapshot map, and DOM references, so concurrent agents never share state or collide.

The [citrolabs/ego-lite](https://github.com/citrolabs/ego-lite) repository provides an open-source runtime for browser automation that supports multiple AI agents — and human operators — working simultaneously inside the same browser process. Its design centers on the task space abstraction found in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts), which gives every actor an isolated execution context. This article explains how task-space isolation, session swapping, and resource-safe concurrency combine to deliver genuine parallel execution for AI agents and human users in a browser.

## The Task Space Architecture: Foundation of Parallel Execution

A **task space** is a lightweight container that owns a dedicated Chrome DevTools Protocol (CDP) session, a snapshot map, and a set of DOM references. Because each space tracks its own state independently, multiple agents can run side-by-side without overwriting each other's page data, DOM snapshots, or navigation history.

### Task-Space Ownership Flags

Every task space carries an ownership flag that determines what actions are allowed inside it:

- **`agent`** — The space is controlled exclusively by an AI agent.
- **`agentDelegatedToUser`** — The agent has temporarily handed control to a human.
- **`user`** — A human operator owns the space; the agent must claim it before acting.

The helpers in **[helpers.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts)** enforce these flags at runtime. Only agent-owned spaces allow direct browser actions. If an agent attempts to execute a command inside a `user`-owned space, the runtime throws an `EGO_TASK_SPACE_USER_IN_CONTROL` error — preventing the agent from unintentionally interfering with a human user mid-session.

### Session Isolation Through `useTaskSpace`

When an agent selects a task space, the runtime swaps the underlying CDP session to the one owned by that space. The **browser-runtime.ts** layer binds the active task space to its corresponding CDP transport, so every subsequent command — `click`, `navigate`, `evaluate` — operates against that isolated session.

This design means parallel agents never share the same page, DOM snapshot, or navigation stack. Two agents working simultaneously on different task spaces can even interact with two different tabs, pages, or websites without any data leak between them.

## Concurrent Resource Safety for Parallel Execution

Parallel execution in a single browser process introduces resource-collision risks, primarily around shared files and global state. ego-lite addresses both.

### Sequenced Screenshot Files

Temporary screenshot resources are made unique per process and per task-space operation. In **[observe.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/driver/observe.ts)**, the screenshot implementation constructs a filename from the process ID and a monotonically increasing sequence number:

```text
ego-browser-shot-${process.pid}-${++screenshotSeq}.png

```

Because the PID and sequence number are both guaranteed unique at runtime, two parallel agents can never overwrite each other's screenshot output — a common source of corruption in naive concurrency implementations.

### Scoped Shared-State Singleton

The runtime's global `state` object in **[state.ts](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts)** stores the current task-space ID, environment configuration, and a small set of helper caches. Critically, each agent's code runs in its own Node invocation, which scopes the singleton to that invocation. Parallel runs therefore keep their state fully isolated — there is no shared mutable global across agents.

## The Parallel Execution API

The public helper functions in [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts) provide a deterministic lifecycle for creating, claiming, and disposing task spaces:

- **`newTaskSpace`** — Create a new agent-owned space.
- **`useOrCreateTaskSpace`** — Select an existing space or create one.
- **`claimTaskSpace`** — Take ownership of a space currently owned by a user.
- **`switchTaskSpace`** — Switch the active CDP session to a different space.
- **`completeTaskSpace`** — Clean up and release a space.
- **`handOffTaskSpace`** — Temporarily hand control to a human user.
- **`takeOverTaskSpace`** — Regain control from a human user.

### Example: Running an Agent in Its Own Space

```js
// Create an agent-owned task space and start working in it
const space = await ego.newTaskSpace('agent-checkout-1');
await ego.navigate('https://example.com/shop');
await ego.click('button=Add to cart');
await ego.screenshot();   // Writes ego-browser-shot-<pid>-<seq>.png

// Switch to a previously created space (agent-owned)
await ego.switchTaskSpace('agent-checkout-1');

// Hand the space to a human user for review, then take it back
await ego.handOffTaskSpace('agent-checkout-1');   // UI shows user overlay
await ego.takeOverTaskSpace('agent-checkout-1'); // Agent regains control

```

### Example: Collaborating with a Human-Controlled Space

```js
// Human-owned space: the agent can read but must claim before acting
await ego.useOrCreateTaskSpace('user-session-42'); // selects user space
// Attempting a click now throws EGO_TASK_SPACE_USER_IN_CONTROL
// Claim it first:
await ego.claimTaskSpace('user-session-42');
await ego.click('button=Proceed');

```

This human-agent handoff is what enables **hybrid workflows** — an agent performs the bulk of a task, then hands the space to a human for approval or fine-tuning, then takes it back. No context is lost and no state collisions occur during the transfer.

## Key Files That Power Parallel Execution

| File | Role |
|------|------|
| [**helpers.ts**](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) | Core task-space helpers (`newTaskSpace`, `switchTaskSpace`, `claimTaskSpace`, handoff functions) |
| [**observe.ts**](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/driver/observe.ts) | Screenshot logic with per-process sequencing to avoid file overwrites |
| [**state.ts**](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts) | Global mutable runtime state that tracks active task space and environment config |
| [**browser-runtime.ts**](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) | CDP transport layer that binds a task space to its isolated session |
| [**env.ts**](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/env.ts) | Resolves the agent workspace and loads environment variables for each space |

Together, these components give ego-lite the ability to run many AI agents — or a mix of agents and humans — concurrently inside a single browser process, while preserving safety, isolation, and a clean developer-facing API.

## Summary

- **Task spaces are the isolation boundary** — each task space owns its CDP session, snapshot map, and DOM references, so agents never share page state.
- **Ownership flags enforce safety** — `agent`, `agentDelegatedToUser`, and `user` flags dictate who can execute browser actions; violations raise `EGO_TASK_SPACE_USER_IN_CONTROL`.
- **Session swapping is deterministic** — `useTaskSpace` and `switchTaskSpace` redirect all subsequent commands to the correct CDP session.
- **Resource collisions are prevented** — screenshots use pid-based sequential filenames and the global state singleton is scoped per Node invocation.
- **Human-agent handoffs are built-in** — `handOffTaskSpace` / `takeOverTaskSpace` allow seamless collaboration without losing state.

## Frequently Asked Questions

### How does ego-lite prevent race conditions between parallel AI agents?

Each agent runs inside an isolated task space with its own CDP session and state snapshot. Because commands act only on the active task space's session, there is no shared mutable state between agents. Screenshots are also uniquely named per process and operation, so concurrent agents cannot overwrite each other's files.

### Can a human user and an AI agent work on the same task space simultaneously?

Not simultaneously — but sequentially handoff-friendly. A space can be delegated from agent to user (`handOffTaskSpace`) and back (`takeOverTaskSpace`). The agent must `claimTaskSpace` before running browser actions inside a user-owned space, otherwise the runtime raises the `EGO_TASK_SPACE_USER_IN_CONTROL` error.

### What happens if an AI agent tries to run a command in a human-owned task space?

In [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts), the ownership check raises the `EGO_TASK_SPACE_USER_IN_CONTROL` error, preventing the action entirely. The agent must first call `claimTaskSpace` to take ownership before executing `click`, `navigate`, `evaluate`, or any other browser action.

### Which files in ego-lite are responsible for task-space parallel execution?

The main implementations live in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) (task-space lifecycle functions), [`package/ego-browser/src/browser-runtime.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/browser-runtime.ts) (CDP session binding), [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts) (per-invocation global state), and [`package/ego-browser/src/driver/observe.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/driver/observe.ts) (collision-safe screenshot logic).