# How Task Spaces Work With the Agent vs User Ownership Model in ego-lite

> Understand ego-lite task spaces and the agent vs user ownership model. Learn how three states control AI agent browser context manipulation for seamless operation.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: internals
- Published: 2026-08-01

---

**Task spaces in ego-lite use a three-state ownership system (`agent`, `agentDelegatedToUser`, `user`) that determines whether an AI agent can directly manipulate a browser context or must first claim it from the user.**

The **citrolabs/ego-lite** browser automation framework isolates each workflow in a dedicated task space with strict access controls. Understanding how the **agent vs user ownership model** governs these spaces is essential for building reliable agents that handle collaborative hand-offs without permission errors.

---

## The Three Ownership States

Every task space carries an **ownership flag** that the runtime checks before allowing operations. The possible values are:

- **`agent`** — The agent created the space and has full control.
- **`agentDelegatedToUser`** — The agent created the space but voluntarily handed control to the user; the agent may still act without re-claiming.
- **`user`** — The user created the space. The agent **must claim it first** before switching to or manipulating it.

The core ownership check is implemented in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) at lines 143–144:

```typescript
function isAgentOwned(ownership) {
  return ownership === "agent" || ownership === "agentDelegatedToUser";
}

```

This predicate guards all agent-side operations, ensuring the runtime throws a clear error when an agent attempts to access a `user`-owned space.

---

## Creating and Retrieving Task Spaces

The `taskSpaces` API provides two paths for obtaining a space, with different ownership guarantees.

### `taskSpaces.useOrCreate(nameOrId)`

**Behavior:** Returns an existing agent-owned space or creates a new one. **Fails if a matching space exists but is user-owned.**

```typescript
// Returns existing agent-owned space or creates new one
const task = await taskSpaces.useOrCreate('research-topic');

```

If the named space has `ownership: 'user'`, the call throws:

```

useOrCreateTaskSpace cannot use task space … with ownership …

```

([source line 213](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts#L213))

### `taskSpaces.new(name)`

**Behavior:** Always creates a brand-new space with `ownership: 'agent'`. Use this when you explicitly need a fresh isolated context.

---

## Claiming User-Owned Spaces

When a space carries `user` ownership, the agent must invoke **`taskSpaces.claim(nameOrId)`**. This operation:

1. Transfers ownership to the agent
2. Automatically selects the space as active

```typescript
// Claim a user-owned task space (ownership transfers to the agent) and select it
await taskSpaces.claim(task.id);

```

([source line 218](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts#L218))

After claiming, the space behaves like any `agent`-owned space for the remainder of its lifecycle (or until the agent hands it off).

---

## Switching Between Spaces

**`taskSpaces.switch(nameOrId)`** requires the target space to be agent-owned:

```typescript
await taskSpaces.switch(task.id);

```

Attempting to switch to a `user`-owned space produces:

```

switchTaskSpace requires an agent-owned task space, got ownership …

```

([source line 160](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts#L160))

Always verify or claim ownership before switching, especially in multi-step workflows where user intervention may have changed the state.

---

## Hand-off and Take-over Operations

The ownership model supports collaborative workflows through two special methods that bypass normal ownership checks:

### `taskSpaces.handOff(nameOrId?)`

The agent voluntarily returns control to the user, setting `ownership: 'user'`. The space remains open for user interaction.

### `taskSpaces.takeOver(nameOrId?)`

The agent reclaims a user-owned space without an explicit claim step—useful when the agent knows it previously handed off the space and wants to resume work.

These are **"no-ownership-check" shortcuts** designed for predictable hand-off patterns where the agent and user alternate control.

---

## Completing Tasks and Cleanup

When finished, call **`taskSpaces.complete(nameOrId, { keep })`**:

- `keep: false` (default) — Closes the space entirely
- `keep: true` — Preserves the space for live-page scenarios documented in the skill reference

([source line 207](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/SKILL.md#L207))

Always complete spaces to release browser resources, especially in long-running agent sessions.

---

## Waiting for Agent Control

After a hand-off, agents can pause until control is regained:

```typescript
await taskSpaces.waitForAgentControl(task.id);

```

([source lines 764–766](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/format.ts#L764))

This is particularly useful when coordinating with user actions that must complete before the agent resumes automation.

---

## Complete Workflow Example

```javascript
// 1️⃣ Create or reuse an agent-owned space
const task = await taskSpaces.useOrCreate('research-topic');

// 2️⃣ Defensive: claim if user somehow owns the space
if (task.ownership === 'user') {
  await taskSpaces.claim(task.id);
}

// 3️⃣ Activate the space
await taskSpaces.switch(task.id);

// ... perform browser automation ...

// 4️⃣ Hand off to user for review
await taskSpaces.handOff(task.id);

// 5️⃣ Later: resume without re-claiming
await taskSpaces.takeOver(task.id);
await taskSpaces.waitForAgentControl(task.id);

// 6️⃣ Clean up
await taskSpaces.complete(task.id, { keep: false });

```

---

## Summary

- **Three ownership states** (`agent`, `agentDelegatedToUser`, `user`) govern all task space operations in ego-lite.
- **Agent-owned spaces** allow immediate switching and manipulation; **user-owned spaces require claiming first**.
- **Use `useOrCreate`** for automatic reuse or creation, but handle the potential failure when a user-owned space exists.
- **Hand-off patterns** use `handOff`/`takeOver` for clean collaboration without repeated claim cycles.
- **Always call `complete`** to release resources, choosing `keep: true` only when the live-page pattern requires persistence.

---

## Frequently Asked Questions

### What happens if I try to switch to a user-owned task space without claiming it?

The runtime throws an explicit error: `switchTaskSpace requires an agent-owned task space, got ownership …`. You must call `taskSpaces.claim()` first to transfer ownership from the user to the agent.

### Can an agent act on a space after calling `handOff`?

Yes, if the agent uses `takeOver` or `claim`. The `handOff` operation sets ownership to `user`, but the agent can regain control through these methods without needing user permission checks—since the agent previously owned the space.

### What's the difference between `agentDelegatedToUser` and `user` ownership?

`agentDelegatedToUser` means the agent created the space and handed it to the user, but retains implicit rights to act without reclaiming. `user` ownership means the user originated the space, and the agent has no automatic access rights—it must explicitly claim the space.

### When should I use `keep: true` in `taskSpaces.complete`?

Use `keep: true` when implementing the live-page pattern where the browser context must persist after task completion—for example, when the final result should remain visible to the user indefinitely. Otherwise, use the default `keep: false` to close the space and free resources.