# Task Space Ownership Model in ego-lite: How Agent vs User Control Works

> Understand the ego-lite task space ownership model. Learn how agent vs user control works with explicit claims for agent access to user spaces.

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

---

**The ego-lite framework implements a three-tier ownership system for task spaces where the `agent`, `agentDelegatedToUser`, and `user` ownership values determine control permissions, with agents requiring explicit claims to access user-owned spaces.**

Each task space in the ego-lite runtime functions as an isolated browser context with a strict ownership flag governing who can create, switch, or manipulate it. According to the citrolabs/ego-lite source code, this model prevents unauthorized agent interference while enabling collaborative hand-off patterns between autonomous agents and human users.

---

## The Three Ownership States

Task spaces exist in one of three distinct ownership states defined in [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts):

| Ownership value | Control semantics |
|-----------------|-----------------|
| **`agent`** | Full agent ownership; the agent created the space and controls it completely. |
| **`agentDelegatedToUser`** | Delegated control; the agent created the space but handed it to the user, yet retains the right to act without re-claiming. |
| **`user`** | User-created space; the agent **must claim** it before any manipulation or switching. |

The ownership predicate is implemented as a simple helper:

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

```

([source lines 143-144 in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts)](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts#L143))

This predicate gates all agent-controlled operations on task spaces.

---

## Creating and Retrieving Task Spaces

### useOrCreate: Agent-Owned Spaces Only

The **`taskSpaces.useOrCreate(nameOrId)`** method returns an existing agent-owned space or creates a new one with `agent` ownership. Critically, it **fails on user-owned spaces**:

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

// Throws if matching space exists with 'user' ownership:
// "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))

### new: Force Fresh Agent Creation

The **`taskSpaces.new(name)`** method always creates a brand-new space with `agent` ownership, regardless of existing spaces.

---

## Claiming User-Owned Spaces

When a space carries `user` ownership, the agent must explicitly **claim** it before any interaction. The **`taskSpaces.claim(nameOrId)`** operation:

- Transfers ownership from `user` to `agent`
- Automatically selects the space for immediate use

```typescript
// Claim transfers ownership and selects the space
await taskSpaces.claim(task.id);

```

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

This is the mandatory pathway for agents to access user-created contexts.

---

## Switching Between Spaces

The **`taskSpaces.switch(nameOrId)`** method enforces strict ownership verification. It only operates on spaces where `isAgentOwned()` returns true:

```typescript
await taskSpaces.switch(task.id); // Works only on agent-owned spaces

```

Attempting to switch to a non-agent-owned space produces a clear error:

```

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))

---

## Hand-Off and Take-Over Patterns

ego-lite provides **bypass methods** for collaborative workflows that skip ownership checks:

| Method | Ownership transition | Use case |
|--------|----------------------|----------|
| **`taskSpaces.handOff(nameOrId?)`** | `agent` → `user` | Agent voluntarily returns control to user |
| **`taskSpaces.takeOver(nameOrId?)`** | `user` → `agent` | Agent regains control without claim overhead |

Both methods are "no-ownership-check" shortcuts optimized for scripted collaboration patterns where explicit claim/verify cycles would add friction.

### Waiting for Confirmed Control

After asynchronous hand-off scenarios, agents can ensure control before proceeding:

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

```

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

---

## Completing Task Spaces

Task cleanup uses **`taskSpaces.complete(nameOrId, { keep })`** which must be called when work finishes:

- `keep: false` (default): Closes and destroys the space
- `keep: true`: Preserves the space for live-page scenarios documented in [`SKILL.md`](https://github.com/citrolabs/ego-lite/blob/main/SKILL.md)

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

---

## Complete Workflow Example

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

// 2. Handle user-owned spaces with explicit claim
if (task.ownership === 'user') {
  await taskSpaces.claim(task.id);
}

// 3. Switch to the target space (verified agent-owned)
await taskSpaces.switch(task.id);

// ... execute agent operations ...

// 4. Collaborative hand-off to user
await taskSpaces.handOff(task.id);

// 5. Later retrieval without claim overhead
await taskSpaces.takeOver(task.id);
await taskSpaces.waitForAgentControl(task.id);

// 6. Cleanup with space closure
await taskSpaces.complete(task.id, { keep: false });

```

---

## Implementation Files

| File | Purpose |
|------|---------|
| [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) | Core ownership predicates, claim/switch logic, error handling |
| [`package/ego-browser/src/format.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/format.ts) | Public API signatures and `waitForAgentControl` implementation |
| [`skills/ego-browser/SKILL.md`](https://github.com/citrolabs/ego-lite/blob/main/skills/ego-browser/SKILL.md) | Human-readable API documentation with ownership semantics |
| [`AGENTS.md`](https://github.com/citrolabs/ego-lite/blob/main/AGENTS.md) | High-level task space concepts for agent developers |

---

## Summary

- **Three ownership states** govern all task space operations: `agent`, `agentDelegatedToUser`, and `user`
- **Agent-owned predicate** (`isAgentOwned`) gates `switch()` and most manipulation methods
- **Mandatory claim requirement** for user-owned spaces prevents unauthorized agent access
- **Hand-off/take-over shortcuts** enable collaborative workflows without claim overhead
- **Explicit completion** via `complete()` ensures proper resource cleanup

---

## Frequently Asked Questions

### What happens if an agent tries to useOrCreate a user-owned task space?

The call fails with a descriptive error: `useOrCreateTaskSpace cannot use task space … with ownership …`. The agent must instead call `claim()` to transfer ownership, or use `new()` to force creation of a fresh agent-owned space.

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

No direct manipulation. After `handOff()`, ownership becomes `user` and standard methods like `switch()` are blocked. The agent must use `takeOver()` or `claim()` to regain control, or rely on `agentDelegatedToUser` status if the space was created in that mode.

### What is the difference between claim and takeOver?

`claim()` performs full ownership verification and transfer from `user` to `agent`, suitable for unknown spaces. `takeOver()` is a no-check shortcut assuming the caller already knows the space should transfer—optimized for scripted recovery after `handOff()`.

### When should an agent use keep: true in complete()?

Set `keep: true` when the task space must persist as a live page for user inspection after agent completion, documented in [`SKILL.md`](https://github.com/citrolabs/ego-lite/blob/main/SKILL.md) for scenarios like delivered reports or interactive results. Default `keep: false` closes the browser context immediately.