# Task Space Facade in ego-lite: How Lifecycle and Ownership Are Managed

> Learn how the task space facade in ego-lite manages lifecycle and ownership with async helpers for discovery, creation, claiming, switching, completion, and hand-off.

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

---

**The task space facade in ego-lite provides a set of async helper functions that enforce strict ownership rules and orchestrate a predictable lifecycle: discovery, creation, claiming, switching, completion, and hand-off.**

The **ego-lite** browser package exposes a high-level abstraction over the low-level Ego runtime APIs. Located in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts), this facade shields agent code from raw runtime calls while enforcing a clear ownership model that distinguishes between **agent-owned** and **user-owned** task spaces.

## Understanding the Ownership Model

The facade operates on a binary ownership system inherited from the underlying Ego runtime:

- **Agent-owned spaces**: Created by or claimed by the agent; the agent has full control to execute tasks, switch contexts, and close spaces.
- **User-owned spaces**: Originated by the user; the agent can view them in listings but cannot manipulate them until ownership is transferred via `claimTaskSpace`.

This enforcement prevents accidental interference with user-controlled sessions while allowing cooperative hand-off patterns.

## Phase-by-Phase Lifecycle Management

### Discovery: Listing Available Task Spaces

The `listTaskSpaces()` helper retrieves all existing task spaces without ownership restrictions. It normalizes the raw runtime payload into a consistent format.

```typescript
// List all spaces regardless of ownership
const spaces = await listTaskSpaces();
console.log(spaces.map(s => ({ id: s.id, name: s.name, ownership: s.ownership })));

```

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 107–113. This is the only operation that returns **user-owned** spaces to agent code.

### Switching: Selecting Agent-Owned Spaces

The `switchTaskSpace(nameOrId)` helper selects an existing space for use but **strictly validates ownership**:

```typescript
// Throws if space 42 is user-owned
await switchTaskSpace(42);

```

Internally, it calls `findTaskSpace()` to resolve the identifier, then asserts `ownership === "agent"` before invoking `ego.useTaskSpace()`. This guard ensures agents never accidentally operate in user-controlled contexts.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 152–163.

### Creation: Establishing Agent Ownership

The `newTaskSpace(name)` helper creates a fresh space and immediately establishes agent ownership:

```typescript
const ts = await newTaskSpace("data-processing");
// ts.ownership === "agent"

```

The implementation: calls `ego.createTaskSpace(name)`, normalizes the result, validates it via `checkTaskSpace()`, then selects it via the internal `selectTaskSpace()` routine.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 171–183.

### "Use or Create" Pattern: Convenience with Enforcement

The `useOrCreateTaskSpace(nameOrId)` helper implements a common workflow: attempt to find an existing space, create if absent. Ownership rules apply:

- If found and **agent-owned**: select it.
- If found and **user-owned**: **reject**—caller must explicitly `claimTaskSpace` first.
- If not found: create new (automatically agent-owned).

```typescript
// Safe convenience that won't hijack user spaces
const ts = await useOrCreateTaskSpace("analysis-session");

```

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 193–213.

### Claiming: Transferring Ownership

The `claimTaskSpace(nameOrId)` helper is the **only sanctioned path** for converting user-owned spaces to agent-owned:

```typescript
// Transfer ownership from user to agent
await claimTaskSpace("existing-user-space");
// Now safe to switch or manipulate

```

Implementation calls `ego.claimTaskSpace()`, normalizes the result, then selects the claimed space. This is the critical bridge for collaborative workflows where users initiate sessions that agents later control.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 224–242.

### Completion and Cleanup: Controlled Termination

The `completeTaskSpace(nameOrId, { keep })` helper handles graceful shutdown with flexibility:

```typescript
// Complete and close (default)
await completeTaskSpace(ts.id, { keep: false });

// Complete but leave open for potential reuse
await completeTaskSpace(ts.id, { keep: true });

```

The implementation selects the target space, checks for native `ego.completeTaskSpace` support, falls back to claim-then-close if needed, and respects the `keep` flag to determine whether to call `ego.closeTaskSpace()`.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 274–314.

### Hand-Off: Returning Control to Users

The `handOffTaskSpace(nameOrId?)` helper enables cooperative multitasking:

```typescript
// Return control to user; returns { done: false, skipped: "user-owned" } if already theirs
const result = await handOffTaskSpace(ts.id);

```

The helper optionally selects a space, then invokes `ego.handOffTaskSpace()`. When operating on a **user-owned** space, the runtime call is skipped and the method resolves with a diagnostic object indicating no action was needed.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 326–338.

### Take-Over: Reclaiming Control

The `takeOverTaskSpace(nameOrId?)` helper allows agents to resume control after a hand-off:

```typescript
// Re-acquire control of current or specified space
await takeOverTaskSpace(); // uses current space

```

Unlike `claimTaskSpace`, no ownership check is performed—this works on the current space as-is, useful for re-entry workflows.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 347–353.

## Shared Internal Infrastructure

### Normalization and Validation

The `normalizeTaskSpace()` function (invoked by all public helpers) ensures consistent object shapes regardless of runtime version or API surface variations. The `checkTaskSpace()` utility validates space integrity before selection.

### Unified Selection Routine

The `selectTaskSpace(ego, space, op)` internal helper is the **single point of contact** with `ego.useTaskSpace()`. All public helpers route through it, ensuring consistent logging, error handling, and state synchronization.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 245–253.

### Space Resolution

The `findTaskSpace(nameOrId)` utility resolves string names or numeric IDs to concrete space objects, throwing descriptive errors for unmatched identifiers.

**Source**: [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) lines 440–460.

## Complete Workflow Example

```typescript
import {
  listTaskSpaces,
  newTaskSpace,
  claimTaskSpace,
  switchTaskSpace,
  completeTaskSpace,
  handOffTaskSpace,
  takeOverTaskSpace
} from "@citrolabs/ego-browser";

async function collaborativeWorkflow() {
  // 1. Discover existing user context
  const spaces = await listTaskSpaces();
  const userSpace = spaces.find(s => s.name === "shared-analysis");
  
  // 2. Claim user-initiated space
  if (userSpace && userSpace.ownership === "user") {
    await claimTaskSpace(userSpace.id);
  }
  
  // 3. Or create fresh agent space if none exists
  const workspace = userSpace 
    ? await switchTaskSpace(userSpace.id)
    : await newTaskSpace("fresh-analysis");
  
  // 4. Do work...
  
  // 5. Hand back to user for review
  const handoff = await handOffTaskSpace();
  console.log(handoff.skipped ? "Already user-owned" : "Handed off");
  
  // 6. Later, resume control
  await takeOverTaskSpace();
  
  // 7. Complete and cleanup
  await completeTaskSpace(workspace.id, { keep: false });
}

```

## Key Source Files

| File | Responsibility |
|------|---------------|
| [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) | Core facade implementation with all lifecycle helpers |
| [`package/ego-browser/src/index.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/index.ts) | Public exports exposing the facade API |
| [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts) | Runtime state management used by helpers |
| `package/ego-browser/src/taskspace-e2e.test.mjs` | End-to-end validation of ownership transitions |

## Summary

- The task space facade enforces a **strict ownership boundary** between agent and user contexts.
- **Seven public helpers** cover the complete lifecycle: `listTaskSpaces`, `newTaskSpace`, `claimTaskSpace`, `switchTaskSpace`, `useOrCreateTaskSpace`, `completeTaskSpace`, `handOffTaskSpace`, and `takeOverTaskSpace`.
- **Claiming is explicit**: agents cannot accidentally manipulate user-owned spaces; `claimTaskSpace` is the required bridge.
- **Internal utilities** (`selectTaskSpace`, `findTaskSpace`, `normalizeTaskSpace`) provide consistent, maintainable abstractions over raw runtime calls.
- All operations are implemented in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) according to the citrolabs/ego-lite source code.

## Frequently Asked Questions

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

The `switchTaskSpace` helper throws an error. It validates that `ownership === "agent"` before calling `ego.useTaskSpace()`. You must first call `claimTaskSpace` to transfer ownership from user to agent.

### How is `useOrCreateTaskSpace` different from manually checking then creating?

The helper encodes the ownership-check logic so you don't accidentally claim user spaces. If an existing space is found and user-owned, it **rejects** rather than proceeding, forcing explicit intent via `claimTaskSpace`. If no space exists, it creates a fresh agent-owned one.

### Can I reuse a task space after calling `completeTaskSpace`?

Only if you pass `{ keep: true }`. The default `{ keep: false }` calls `ego.closeTaskSpace()`, terminating the space. The `keep` flag exists specifically to support reuse patterns in long-running agent workflows.

### What's the difference between `handOffTaskSpace` and `claimTaskSpace`?

They are complementary opposites. `handOffTaskSpace` transfers control **from agent to user** (or no-ops if already user-owned). `claimTaskSpace` transfers control **from user to agent**. Together they enable cooperative hand-off patterns where agents and users alternate control of shared sessions.