# Understanding Ego‑Lite's Task Space Ownership Model: Agent vs User Control

> Explore ego-lites task space ownership model. Understand agent versus user control for autonomous AI operations and human oversight. Learn how ego-lite governs AI permissions.

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

---

**The ego‑lite task space ownership model assigns every browser container an ownership flag—either "agent" for autonomous AI control or "user" for human oversight—strictly governing which operations the AI can perform without explicit permission.**

The ego‑lite framework isolates browsing work into **task spaces**, lightweight containers that each own a browser tab and its associated state. According to the citrolabs/ego‑lite source code in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), every task space carries an **ownership** property that enforces a clear separation of control between the autonomous agent and the human user. This design prevents the AI from unintentionally disrupting active user sessions while enabling full automation when the agent holds ownership.

## What Is a Task Space?

A task space is a logical container that encapsulates a browser tab and its execution context. As implemented in the `ego‑browser` package, these spaces allow agents to perform multi‑step browsing workflows without interfering with the user's own tabs. Each space maintains its own state, cookies, and session data, but the critical determinant of permissible actions is the **ownership** flag stored within the space metadata.

## Ownership States: Agent vs User

The ownership model recognizes two distinct states that determine control privileges:

- **Agent‑owned spaces** grant the autonomous AI complete operational freedom. When ownership is set to `"agent"`, the AI may create, select, claim, complete, close, or hand off the space without human intervention.
- **User‑owned spaces** reserve control for the human operator. When ownership is `"user"`, the agent may **select** the space to inspect its state, but any attempt to **claim** or modify it automatically raises the `EGO_TASK_SPACE_USER_IN_CONTROL` error. The user must explicitly transfer ownership before the agent can proceed with destructive actions.

## Core Ownership Helper Functions in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts)

The implementation in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) exposes seven primary functions that enforce these ownership rules through the global `ego` bindings provided by `helperContext()`:

**Creating agent spaces** – `newTaskSpace(name)` invokes `ego.createTaskSpace` and automatically registers the new container with `"agent"` ownership, returning a space object containing `{ id, name, ownership: 'agent', ... }`.

**Reusing or creating spaces** – `useOrCreateTaskSpace(nameOrId)` queries existing spaces via `listTaskSpaces`. If no space exists, it delegates to `newTaskSpace` to create an agent‑owned container. If the space exists and is agent‑owned, it selects that space for the current Node process. However, if the space is user‑owned, the function selects it without claiming, preserving user control and returning a guidance message that explicit claiming is required.

**Explicitly claiming user spaces** – `claimTaskSpace(nameOrId)` locates a user‑owned space and transfers ownership to the agent by calling `ego.claimTaskSpace`. After successful execution, the space behaves as agent‑owned, permitting full automation.

**Switching between spaces** – `switchTaskSpace(nameOrId)` validates ownership before switching; it throws an error if the target space is user‑owned, ensuring the agent cannot inadvertently hijack active user sessions.

**Handing off control** – `handOffTaskSpace([nameOrId])` returns the UI to the user. If the target space is already user‑owned, the operation returns `{ done: false, skipped: "user-owned" }` as a no‑op, acknowledging that the user already possesses control.

**Resuming agent control** – `takeOverTaskSpace([nameOrId])` restores the agent overlay on a previously handed‑off space, allowing the AI to resume work without creating a new container.

**Completing workflows** – `completeTaskSpace(nameOrId, { keep })` finalizes the task. With `keep: true`, the tab remains open for the user; with `keep: false`, it closes. For user‑owned spaces, `keep: true` skips all actions since the page inherently belongs to the user.

**Ownership validation** – The private helper `isAgentOwned(ownership)` (approximately line 143) performs strict equality checks against the string `"agent"`, serving as the gatekeeper for all privileged operations.

## Ownership Lifecycle and State Transitions

The typical workflow demonstrates how ownership transitions between states:

1. **Initialization** – The agent calls `useOrCreateTaskSpace('workflow-name')`, creating an agent‑owned space or reconnecting to an existing one.
2. **User intervention** – At a decision point, the agent executes `handOffTaskSpace()`, transferring the browser UI to the user and implicitly marking the space as user‑controlled.
3. **Reclaiming work** – When the user requests the agent continue, `takeOverTaskSpace()` restores the agent overlay, though ownership remains technically with the user until `claimTaskSpace()` is explicitly invoked.
4. **Explicit claiming** – If the agent must modify a user‑owned space (e.g., close the tab), it must first call `claimTaskSpace()` to transfer the ownership flag to `"agent"`.
5. **Cleanup** – The agent finalizes with `completeTaskSpace(task.id, { keep: false })`, closing the tab only if it possesses agent ownership.

## Practical Code Examples

The following patterns from [`skills/ego-browser/SKILL.md`](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/SKILL.md) demonstrate safe ownership handling:

```javascript
// 1️⃣ Start (or reuse) a task space for the agent
const task = await useOrCreateTaskSpace('price‑lookup');
// `task` now contains { id, name, ownership: 'agent', ... }

// 2️⃣ Switch to an existing *agent‑owned* space
await switchTaskSpace(task.id);

// 3️⃣ If you need to work on a *user‑owned* space, first claim it
await claimTaskSpace('checkout‑flow'); // transfers ownership to the agent

// 4️⃣ Hand the space back to the user (e.g., after showing results)
await handOffTaskSpace(task.id);

// 5️⃣ Later the user asks the agent to continue – resume with overlay
await takeOverTaskSpace(task.id);

// 6️⃣ Finish the work and close the tab (or keep it open for the user)
await completeTaskSpace(task.id, { keep: false }); // closes the tab
// or
await completeTaskSpace(task.id, { keep: true });  // leaves page open for user

```

As noted in [`CONTRIBUTING.md`](https://github.com/citrolabs/ego-lite/blob/main/CONTRIBUTING.md), every heredoc in agent scripts must begin with `useOrCreateTaskSpace` to ensure re‑attachment to the correct container across execution rounds.

## Summary

- The **ego‑lite task space ownership model** bifurcates control between `"agent"` and `"user"` states, preventing unauthorized automation.
- **Agent‑owned spaces** permit full CRUD operations via `newTaskSpace`, `switchTaskSpace`, and `completeTaskSpace`.
- **User‑owned spaces** block automatic claiming; the agent must invoke `claimTaskSpace` to transfer ownership, or use `takeOverTaskSpace` to merely overlay the UI.
- All ownership checks are centralized in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts) through the `isAgentOwned` helper and enforced by the `helperContext` global bindings.
- The design ensures that user browsing contexts remain protected while enabling seamless, multi‑round AI workflows when ownership is properly managed.

## Frequently Asked Questions

### What happens if an agent tries to claim a user‑owned task space?

According to the implementation in [`src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/src/helpers.ts), any attempt to automatically claim a user‑owned space will raise the `EGO_TASK_SPACE_USER_IN_CONTROL` error. The agent must explicitly request ownership transfer through the `claimTaskSpace` function, ensuring the human user maintains control over active browsing sessions.

### Can the agent switch to a space that the user currently owns?

No. The `switchTaskSpace` function validates ownership before switching contexts. If the target space carries `"user"` ownership, the function throws an error rather than interrupting the human's browsing session. The agent may only `select` user‑owned spaces for inspection, not for active manipulation.

### How does the `keep` parameter in `completeTaskSpace` behave with user‑owned spaces?

When `completeTaskSpace(nameOrId, { keep: true })` is called on a user‑owned space, the operation skips all actions and returns immediately. Since the user already owns the tab, no state change is necessary. With `keep: false`, the agent must first possess ownership (via `claimTaskSpace`) to actually close the browser tab.

### Where is the ownership check performed in the source code?

The ownership validation logic resides in the `isAgentOwned(ownership)` helper function located at approximately line 143 in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts). This function strictly checks for the string `"agent"` and is invoked by `switchTaskSpace` and other privileged operations to enforce the ownership model. End‑to‑end tests validating these behaviors are available in `src/taskspace-e2e.test.mjs`.