How to Perform Control Handoff Between an ego-lite Agent and the User

Transfer browser control using handOffTaskSpace() to give the user access, waitForAgentControl() to pause until they finish, and takeOverTaskSpace() to resume automation.

ego-lite isolates browser work into task-spaces that enforce strict ownership—only one party (either the agent or the user) can issue commands at any time. Understanding how to perform a control handoff between an ego-lite agent and the user is essential for workflows that require interactive steps like CAPTCHA solving, manual login, or user confirmation.

Understanding Task-Space Ownership

Each task-space maintains exclusive ownership status. When the agent owns the space, it can execute browser commands freely. When the user owns the space, the agent is blocked from issuing commands until control is explicitly returned. This ownership model prevents race conditions and ensures that automated scripts do not interfere with manual user interactions.

The control handoff flow is implemented in package/ego-browser/src/helpers.ts and exposed through three public helper functions that manage this ownership transition.

Core Control Handoff Methods

handOffTaskSpace

The handOffTaskSpace([nameOrId]) helper transfers ownership from the agent to the user. According to the source code in package/ego-browser/src/helpers.ts at lines 326-340, this method first checks the current ownership status. If the space is already user-owned, it returns { done: false, skipped: "user-owned" }. Otherwise, it selects the specified space and invokes the internal ego.handOffTaskSpace() runtime call, returning { done: true } upon success.

Use this method when the task requires the user to perform an interactive step that the agent cannot automate, such as entering a password or solving a visual puzzle.

waitForAgentControl

The waitForAgentControl(nameOrId, {interval?, timeout?}) helper pauses execution until the agent regains control but does not change ownership itself. As implemented in package/ego-browser/src/helpers.ts at lines 84-108, this method polls a lightweight probe (ego.snapshot) through the private probeAgentControl() function.

If the probe returns a user-control error, the loop continues; if the snapshot succeeds, the agent has regained control. The method respects configurable parameters:

  • interval: Polling frequency in seconds (default: 20)
  • timeout: Maximum wait time in seconds (default: 600)

Call this inside a single heredoc after handOffTaskSpace() to suspend the script until the user signals completion.

takeOverTaskSpace

The takeOverTaskSpace([nameOrId]) helper returns control to the agent. Located at lines 47-53 in package/ego-browser/src/helpers.ts, this method selects the space and calls ego.takeOverTaskSpace(). The runtime does not enforce an ownership check, so your code must only call this after explicit user consent, as documented in skills/ego-browser/SKILL.md at lines 97-108.

Step-by-Step Implementation Workflow

A typical control handoff sequence follows these steps:

  1. Determine interaction necessity – The agent identifies that manual user input is required.
  2. Transfer control – Call await handOffTaskSpace(task.id) to switch ownership and hide the agent overlay.
  3. Instruct the user – Display clear instructions about what the user must complete.
  4. Pause execution – (Optional) Call await waitForAgentControl(task.id) to block until the user finishes.
  5. Resume or complete – After user confirmation, either call await takeOverTaskSpace(task.id) to continue automation, or await completeTaskSpace(task.id, {keep: false}) to finish the task.

Code Examples

Here is a complete implementation showing how to hand off control for a CAPTCHA challenge:

// Transfer control so the user can solve a CAPTCHA
const task = await useOrCreateTaskSpace('solve-captcha');
await handOffTaskSpace(task.id);

// Inform the user what to do next
await askUser('Please solve the CAPTCHA, then click Continue.');

// Wait inside the same heredoc until the user finishes
await waitForAgentControl(task.id, { interval: 10, timeout: 300 });

// Take back control and continue automation
await takeOverTaskSpace(task.id);
await click('#submit');

Handle cases where the user already owns the space to prevent redundant operations:

const result = await handOffTaskSpace(task.id);
if (!result.done) {
  // Space already user-owned, skip redundant handoff
  console.log('User already has control');
}

Error Handling and Edge Cases

When implementing control handoff between an ego-lite agent and the user, always check the return value of handOffTaskSpace(). The skipped state indicates that the user already owns the task-space, allowing your script to proceed gracefully without attempting redundant ownership transfers.

The waitForAgentControl() method will throw if the timeout expires before the agent regains control, so wrap polling calls in appropriate try-catch blocks for production use.

Summary

  • Task-spaces enforce single ownership – Only the owner (agent or user) can issue browser commands at any time.
  • Three helpers manage transitionshandOffTaskSpace() gives control to the user, waitForAgentControl() pauses until completion, and takeOverTaskSpace() resumes agent automation.
  • Check return values – Handle skipped states when the space is already user-owned to avoid redundant operations.
  • Confirm user readiness – The agent must explicitly ask the user before calling takeOverTaskSpace(), as the runtime does not enforce consent checks.

Frequently Asked Questions

What happens if I call handOffTaskSpace when the user already owns the task-space?

The method returns { done: false, skipped: "user-owned" } without attempting another handoff. This allows your script to continue execution gracefully, knowing the user already has control of the browser.

How long does waitForAgentControl wait by default?

By default, waitForAgentControl() polls every 20 seconds (interval) and times out after 600 seconds (10 minutes). You can customize these values by passing an options object: { interval: 10, timeout: 300 } for 10-second intervals and a 5-minute timeout.

Technically yes—the runtime does not enforce an ownership verification when takeOverTaskSpace() is called. However, the SKILL.md documentation and best practices require that agents explicitly ask the user to continue before reclaiming control. Always implement a user confirmation step before calling this method.

Where are the control handoff methods implemented?

The core logic resides in package/ego-browser/src/helpers.ts at lines 326-340 for handOffTaskSpace, lines 47-53 for takeOverTaskSpace, and lines 84-108 for waitForAgentControl. These are exposed through the task-space façade in src/index.ts according to the JSON-RPC signatures defined in src/format.ts.

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 →