How `handOffTaskSpace()` Works in ego-lite: Agent-to-User Control Transfer

The handOffTaskSpace() helper transfers browser control from the ego-lite agent back to the user by hiding the agent overlay and marking the task space as user-owned, returning status objects that indicate whether the hand-off succeeded or was skipped.

The handOffTaskSpace() function is a core utility in the citrolabs/ego-lite repository that enables seamless transitions between automated agent actions and manual user intervention. This helper is essential for workflows requiring human input—such as authentication flows or CAPTCHA verification—where the agent must temporarily relinquish control of the browser session according to the control transfer protocol defined in the source code.

Core Runtime Validation

The implementation in package/ego-browser/src/helpers.ts begins by validating that the runtime environment exposes the required ego binding through globalThis.ego【source:helpers.ts†L326-L340】. If the runtime is unavailable or lacks the handOffTaskSpace method, the function throws a descriptive error before attempting any state changes. This defensive check ensures that skills fail fast with clear messaging rather than generating opaque runtime exceptions.

Task Space Resolution Logic

When invoked with an optional nameOrId parameter, the helper resolves the target task space using the internal findTaskSpace() utility. This lookup accepts either a string name or numeric ID to locate the specific browser context. If the specified space is already under user control, the function returns early with { done: false, skipped: "user-owned" } to prevent redundant transitions. For valid agent-controlled spaces, selectTaskSpace() activates the target before invoking the underlying runtime hand-off mechanism.

Return Values and Error Handling

The function returns a standardized result object indicating the operation status. A successful hand-off returns { done: true }, confirming that the agent overlay is hidden and the user regains full browser control. Any failure from the runtime call is wrapped by assertNoEgoError to surface consistent error types, ensuring that calling code receives normalized exceptions rather than raw runtime errors.

Practical Implementation Examples

Here are practical patterns for integrating handOffTaskSpace() into your ego-lite skills:

// Hand off the current active task space (no argument required)
await handOffTaskSpace();
// Returns: { done: true } — agent overlay hidden, user controls the page
// Hand off a specific named space with conditional handling
const result = await handOffTaskSpace('checkout-flow');
if (!result.done && result.skipped === 'user-owned') {
  console.log('Space already under user control — nothing to do');
} else {
  console.log('Control handed off — awaiting user interaction');
}
// Complete workflow: hand off, wait for user, and reclaim control
await handOffTaskSpace('login');
// ... user completes manual login in browser ...
await waitForAgentControl('login');  // optional polling
await takeOverTaskSpace('login');    // restore agent overlay

Integration with Task Space Lifecycle

According to the skill documentation in skills/ego-browser/SKILL.md, handOffTaskSpace() operates as the inverse of takeOverTaskSpace() within the control transfer protocol【source:SKILL.md†L81-L109】. The function works in concert with waitForAgentControl() to facilitate bidirectional hand-offs between automated and manual modes, as documented in the repository's contribution guidelines【source:CONTRIBUTING.md†L186-L188】. The helper is exported from package/ego-browser/src/index.ts and listed in AGENTS.md among the core task-space commands available to skill authors.

Summary

  • handOffTaskSpace() transfers browser control from agent to user by hiding the overlay and updating task space ownership in the ego-lite runtime.
  • The function validates the globalThis.ego binding before executing and throws descriptive errors for missing or incomplete runtimes.
  • It accepts an optional nameOrId parameter to target specific task spaces, returning { done: false, skipped: "user-owned" } for spaces already under manual control.
  • Successful operations return { done: true }, with all runtime errors normalized via assertNoEgoError for consistent exception handling.
  • Defined in package/ego-browser/src/helpers.ts, the helper integrates with takeOverTaskSpace() and waitForAgentControl() to form the complete agent-user control transfer protocol.

Frequently Asked Questions

What happens if I call handOffTaskSpace() without arguments?

Without a nameOrId parameter, the function operates on the currently active task space. It immediately attempts to transfer control of the active space to the user, returning { done: true } upon success or { done: false, skipped: "user-owned" } if the space is already user-controlled.

How does handOffTaskSpace() differ from takeOverTaskSpace()?

While handOffTaskSpace() transfers control from agent to user (hiding the agent overlay), takeOverTaskSpace() performs the inverse operation, restoring agent control over a user-owned task space. These functions form the bidirectional control transfer protocol documented in the ego-lite architecture and contribution guidelines.

What error occurs if the ego runtime is not available?

If globalThis.ego is undefined or lacks the handOffTaskSpace method, the helper throws a clear runtime error before attempting any task space operations. This validation occurs at the start of the function in package/ego-browser/src/helpers.ts to ensure actionable error messages.

Can I hand off a task space that is already user-owned?

Yes, but the operation will be skipped. The function checks ownership status via internal resolution logic and returns { done: false, skipped: "user-owned" } without modifying the state, preventing unnecessary transitions and allowing idempotent calling patterns.

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 →