How Ego-Lite Achieves Parallel Multitasking Using Multiple Task Spaces
Ego-Lite enables parallel multitasking by isolating browser sessions into independent task spaces, each with its own CDP session and state, allowing agents to run concurrent workflows without interference.
The citrolabs/ego-lite repository implements a sophisticated concurrency model that treats browser automation as a multi-tenant environment. By leveraging isolated task spaces with dedicated Chrome DevTools Protocol (CDP) sessions, the framework allows AI agents to execute multiple independent browsing tasks simultaneously. Understanding how these spaces are created, managed, and switched is essential for building high-throughput automation workflows.
Understanding Task Spaces in Ego-Lite
A task space represents an isolated browser-runtime session that maintains its own CDP connection, tab list, and snapshot state. Unlike traditional single-session automation where one agent blocks the browser until completion, Ego-Lite's architecture treats each space as a independent virtual browser instance.
This isolation occurs at the runtime level. When you create a new task space, the system allocates a unique numeric identifier and establishes a separate CDP session channel. According to the source code in src/helpers.ts [L66-L84], the newTaskSpace(name) function invokes the native ego runtime via ego.createTaskSpace, then immediately activates the space using useTaskSpace to establish the session context.
The Task Space Architecture
Core Implementation Files
The parallel multitasking capability spans three critical components:
src/helpers.ts– Contains the public façadecreateTaskSpacesFacade()that exposes helper methods includinglist,new,useOrCreate,switch,claim,complete,handOff,takeOver, andwaitForAgentControl[L85-L97]src/state.ts– Maintains runtime state including current CDP session IDs (state.sessionId,state.sessionTargetId) that bind specific spaces to their underlying browser connections [L30-L36]src/browser-runtime.ts– Manages the low-level CDP transport layer that multiplexes commands across different task space sessions [L1-L12]
The Public API Façade
Developers interact with task spaces through a unified helper interface exposed via helperContext() → taskSpaces. This façade abstracts the complexity of session management while providing granular control over parallel execution contexts.
The façade implementation in src/helpers.ts enforces an ownership model where spaces are either agent-owned or user-owned. This distinction matters because operations like switchTaskSpace only work on agent-owned spaces, while claim, handOff, and takeOver manage transitions between these states [L18-L33].
Creating and Managing Isolated Sessions
Space Creation and Selection
To initiate parallel work, agents invoke taskSpaces.new(name), which triggers the native runtime to instantiate a fresh browser context. The helper immediately calls useTaskSpace to select the newly created space, ensuring subsequent API calls target the correct session.
The selection mechanism works by updating the active CDP session identifiers stored in the global state. When ego.useTaskSpace(id) executes, the runtime swaps the active session context, causing all subsequent page, browser, or locator operations to target that specific space exclusively.
Reusing Existing Spaces
For workflows that resume previous work, useOrCreateTaskSpace(nameOrId) implements intelligent space discovery. This helper first enumerates available spaces via ego.listTaskSpaces, then either switches to an existing owned space or creates a new one if no match exists [L90-L104].
This pattern enables efficient resource utilization when branching work across multiple existing sessions without spawning redundant browser instances.
Session Isolation and CDP Management
True parallelism requires strict isolation at the protocol level. Each task space maintains independent sessionId and sessionTargetId values that map to distinct CDP targets within the browser.
The isolation mechanism ensures that:
- Page navigations in space A do not affect space B's DOM state
- Screenshots and snapshots capture only the active space's viewport
- JavaScript execution contexts remain separate between spaces
When switching contexts via taskSpaces.switch(id), the system updates the global state object in src/state.ts to reference the new session identifiers. This state change propagates to the CDP transport layer in src/browser-runtime.ts, which injects the correct session_id into every subsequent DevTools command.
Implementing Parallel Execution
Concurrent Workflow Patterns
Because task spaces are fully independent, developers can leverage standard JavaScript concurrency patterns to run multiple automation tasks simultaneously. The façade guarantees thread-safe operation by ensuring each async call uses the correct session_id supplied by the active task space.
Here is a practical example demonstrating parallel data extraction across two isolated sessions:
// Example: run two independent tasks in parallel
(async () => {
// Create two separate agent‑owned task spaces
const spaceA = await taskSpaces.new('Data extraction A');
const spaceB = await taskSpaces.new('Data extraction B');
// Helper to perform work inside a given space
const workInSpace = async (space, url) => {
// Switch to the target space
await taskSpaces.switch(space.id);
// Navigate and scrape
await page.goto(url);
const title = await page.title();
console.log(`Space ${space.name} → ${title}`);
};
// Launch both jobs concurrently
await Promise.all([
workInSpace(spaceA, 'https://example.com/a'),
workInSpace(spaceB, 'https://example.com/b'),
]);
// Clean up
await taskSpaces.complete(spaceA.id, { keep: false });
await taskSpaces.complete(spaceB.id, { keep: false });
})();
Ownership and Control Handoff
Parallel multitasking extends beyond autonomous agent execution to include human-in-the-loop workflows. The handOff and takeOver methods allow agents to transfer space ownership to users while continuing other independent tasks in different spaces.
When handing off control, waitForAgentControl polls a harmless snapshot on the target space to detect when the user has returned control, enabling safe coordination between concurrent automated and manual tasks [L64-L78].
// Example: hand off a space to the user while the agent continues elsewhere
(async () => {
const research = await taskSpaces.useOrCreate('Research task');
await taskSpaces.switch(research.id);
await page.goto('https://news.ycombinator.com/');
// Let the user inspect the page
await taskSpaces.handOff(research.id);
// Meanwhile, the agent starts another independent task
const summary = await taskSpaces.new('Summary task');
await taskSpaces.switch(summary.id);
await page.goto('https://example.com/');
// When the user returns control, resume work
await taskSpaces.waitForAgentControl(research.id);
await taskSpaces.takeOver(research.id);
// ...continue processing
})();
Summary
- Task spaces provide isolated CDP sessions that enable true parallelism in browser automation, with each space maintaining independent state and browser context.
- The
createTaskSpacesFacade()insrc/helpers.tsexposes a comprehensive API for creating, switching, and managing spaces through methods likenew,switch,useOrCreate, andcomplete. - Session isolation occurs at the CDP level via unique
sessionIdandsessionTargetIdvalues stored insrc/state.tsand managed bysrc/browser-runtime.ts. - Concurrent execution leverages standard
Promise.allpatterns, with the façade ensuring each async operation targets the correct space through active session tracking. - Ownership management supports complex workflows where agents hand control to users via
handOffand resume later withtakeOver, all while maintaining parallel operations in other spaces.
Frequently Asked Questions
What is a task space in Ego-Lite?
A task space is an isolated browser-runtime session that encapsulates its own CDP connection, tab list, and execution context. Unlike browser contexts in standard Playwright or Puppeteer, Ego-Lite task spaces are first-class entities with unique numeric IDs that can be created, persisted, switched between, and shared between agents and users.
How does Ego-Lite maintain isolation between concurrent tasks?
Isolation is enforced through separate CDP sessions managed in src/state.ts. When you switch task spaces using taskSpaces.switch(id), the system updates the active sessionId and sessionTargetId in the global state. The CDP transport layer in src/browser-runtime.ts then routes all subsequent commands through the specific session channel associated with that space, ensuring page states, cookies, and JavaScript contexts remain compartmentalized.
Can multiple agents work in the same task space simultaneously?
No. Task spaces follow an ownership model where a single entity (either an agent or a user) holds control at any given moment. The claim, handOff, and takeOver methods manage transitions between owners. While multiple spaces can operate in parallel, a single space cannot be actively controlled by multiple agents simultaneously to prevent state corruption and race conditions.
How do I hand control between a user and agent without stopping parallel tasks?
Use the taskSpaces.handOff(id) method to transfer ownership to the user while the agent continues working in other spaces. To resume automated control, first call taskSpaces.waitForAgentControl(id) to poll for user readiness, then invoke taskSpaces.takeOver(id) to reclaim the space. This pattern allows human review or intervention in one workflow while the agent processes unrelated tasks in parallel spaces.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →