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

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 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 (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 }
// 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 (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.

// 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:

  • 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:

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) hides the agent overlay and returns control, skipping if already user-owned
  • takeOverTaskSpace (lines 447-454 in 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →