# How to Handle Control Handoff Between Agent and User with `handOffTaskSpace` and `takeOverTaskSpace` in ego-lite

> Learn how to manage agent-user control handoff in ego-lite with handOffTaskSpace and takeOverTaskSpace. Seamlessly transfer and reclaim browser control.

- Repository: [CitroLabs/ego-lite](https://github.com/citrolabs/ego-lite)
- Tags: how-to-guide
- Published: 2026-07-28

---

**The `handOffTaskSpace` and `takeOverTaskSpace` functions in `citrolabs/ego-lite` allow an automated agent to transfer browser control to a human user and reclaim it later by toggling the ownership state of isolated task spaces.**

In the **ego-lite** browser-automation runtime, a **task space** represents an isolated browsing context that can be owned either by the **agent** or by the **user**. When the agent finishes automated work, it calls `handOffTaskSpace` to hide the agent overlay and return control. Later, `takeOverTaskSpace` restores the overlay so the agent can resume automation.

## Understanding Task Space Ownership

Task spaces in ego-lite follow a strict ownership model defined by the runtime. **Agent-owned** spaces are created by the automation system and display the agent overlay by default. **User-owned** spaces originate from manual user navigation (such as direct browser interaction) and launch without the overlay visible.

This distinction determines whether a handoff operation actually executes or gets skipped. The helpers defined in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) enforce these semantics through runtime checks before invoking the underlying ego methods.

## Handing Off Control with `handOffTaskSpace`

The `handOffTaskSpace` function enables the agent to surrender control of a specific task space or the current active space. According to the source code in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) (lines 326-340), the implementation follows this logic:

1. Optionally switches to the specified task space using internal selectors
2. Checks if the space is already **user-owned**
3. If user-owned, returns immediately with `{ done: false, skipped: "user-owned" }`
4. Otherwise, invokes the runtime's `handOffTaskSpace` method and returns `{ done: true }`

```typescript
// Hand off the current task space to the user
const result = await handOffTaskSpace();
// => { done: true } 
// or { done: false, skipped: "user-owned" } if already user-owned

// Hand off a specific named space
const result = await handOffTaskSpace('my-space');
if (result.done) {
  console.log('Control transferred to user');
}

```

The function accepts an optional string identifier (name) or numeric ID. When no argument is provided, it operates on the currently active task space.

## Taking Back Control with `takeOverTaskSpace`

When the human user completes their manual tasks, the agent calls `takeOverTaskSpace` to resume automation. Implemented in [`package/ego-browser/src/helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/helpers.ts) (lines 447-454), this function optionally selects the requested task space and then invokes the ego runtime's `takeOverTaskSpace` method to restore the agent overlay.

Unlike `handOffTaskSpace`, this function returns no value on success. It resolves silently once the overlay is visible and the space is marked as agent-owned, throwing only if the runtime encounters an error.

```typescript
// Resume control of the active space
await takeOverTaskSpace();

// Take over a specific space by ID
await takeOverTaskSpace(42);

```

## Internal Helper Chain

Both public functions rely on a chain of internal utilities also defined in [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts):

- **`findTaskSpace`** – Retrieves the full task-space descriptor (including ownership status) from the runtime's registry of known spaces
- **`selectTaskSpace`** – Calls `ego.useTaskSpace` to activate a specific space as the current browsing context
- **`selectTaskSpaceIfProvided`** – Convenience wrapper used by `takeOverTaskSpace` that performs selection only when a name or ID is supplied, preventing unnecessary context switches

These helpers ensure that ownership checks occur against the correct task space before any runtime mutations.

## Complete Workflow Example

The typical collaboration pattern between agent and user follows a four-step lifecycle:

```typescript
import { handOffTaskSpace, takeOverTaskSpace } from 'ego-browser';

// Step 1: Agent completes automated tasks
await performAutomation();

// Step 2: Agent hands off to user
const handoff = await handOffTaskSpace('checkout-flow');
if (handoff.done) {
  console.log('Waiting for user input...');
  
  // Step 3: Agent waits for external signal that user is done
  await waitForUserCompletion();
  
  // Step 4: Agent takes back control
  await takeOverTaskSpace('checkout-flow');
  await continueAutomation();
}

```

This pattern allows seamless human-in-the-loop workflows where the agent handles bulk operations and the user handles authentication, CAPTCHA, or complex decision points.

## Summary

- **Task spaces** are isolated browsing contexts owned by either the agent or the user
- **`handOffTaskSpace`** (lines 326-340 in [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts)) hides the agent overlay and returns control, skipping if already user-owned
- **`takeOverTaskSpace`** (lines 447-454 in [`helpers.ts`](https://github.com/citrolabs/ego-lite/blob/main/helpers.ts)) restores the overlay for agent automation
- Both functions accept optional task space identifiers; omitting the argument targets the currently active space
- Internal helpers `findTaskSpace`, `selectTaskSpace`, and `selectTaskSpaceIfProvided` manage context switching and ownership validation

## Frequently Asked Questions

### What happens if I call `handOffTaskSpace` on a user-owned space?

The function returns `{ done: false, skipped: "user-owned" }` without invoking the runtime handoff, as the space already belongs to the user. This idempotent behavior prevents unnecessary UI flickering.

### Can `takeOverTaskSpace` fail silently?

No. While the function returns `void` on success, it will throw an error if the ego runtime fails to restore the overlay or if the specified task space does not exist. Always wrap calls in try-catch blocks for production reliability.

### How do I know which task space is currently active?

The `findTaskSpace` helper (used internally by both functions) queries the runtime state from [`package/ego-browser/src/state.ts`](https://github.com/citrolabs/ego-lite/blob/main/package/ego-browser/src/state.ts). You can import and use this directly to inspect ownership status before deciding whether to hand off or take over.

### Do these functions work across browser tabs?

Yes. Task spaces in ego-lite represent isolated browsing contexts that persist across tab switches. The `selectTaskSpace` helper calls `ego.useTaskSpace` to ensure the correct context is active before ownership transfer occurs.