Ego-Lite Task Space Ownership Model and Agent-User Handoff Explained

Ego-lite implements a three-state task space ownership model—"agent", "agentDelegatedToUser", and "user"—that governs whether the AI agent or human user controls browser operations, with handoff managed through specific helpers in the citrolabs/ego-lite repository.

The citrolabs/ego-lite repository provides a browser harness that isolates work into independent task spaces, each governed by an ownership model determining control rights. This system enables seamless collaboration between automated agents and human users, allowing the agent to delegate control when human judgment is required and reclaim it when tasks resume.

The Three Task Space Ownership States

Ego-lite tracks ownership through the ownership field on task space objects, which can hold one of three string values that determine who may execute browser commands.

Agent Ownership States ("agent" and "agentDelegatedToUser")

When a task space has "agent" ownership, the AI agent maintains full control and can execute arbitrary browser commands. The "agentDelegatedToUser" state indicates the space was created by the agent but control has been temporarily handed to the user—real agent interactions are paused, though the agent retains ownership claims. In package/ego-browser/src/helpers.ts, the isAgentOwned helper treats both "agent" and "agentDelegatedToUser" as agent-owned (lines 43-45), allowing the agent to reclaim these spaces without claiming ownership first.

User Ownership ("user")

A "user" owned space originates from the human user rather than the agent, granting the user exclusive control. The native ego bindings enforce a hard boundary here: agent commands targeting user-owned spaces receive the EGO_TASK_SPACE_USER_IN_CONTROL error code defined in package/ego-browser/src/ego-errors.ts (lines 13-16), which the system treats as a non-retryable hard stop.

How Agent-User Handoff Works

The handoff mechanism enables safe transitions between automated and manual browsing, ensuring the agent releases control cleanly and can resume work when appropriate.

Delegating Control to the User

When the agent determines human intervention is necessary, it calls handOffTaskSpace([id|name]) from package/ego-browser/src/helpers.ts. If the target space is agent-owned, the helper invokes the native ego.handOffTaskSpace() binding (lines 27-38) and resolves { done: true }, transitioning the ownership to "agentDelegatedToUser". If the space is already user-owned, the helper returns early with { done: false, skipped: "user-owned" } (lines 31-35), avoiding redundant operations.

Reclaiming Control from the User

To resume automated operations, the agent executes takeOverTaskSpace([id|name]), which re-applies the agent overlay and restores execution capabilities without checking ownership boundaries (lines 44-54). For workflows that must pause until the user finishes, the agent can call waitForAgentControl(), which polls the native bridge until the agent regains control, effectively blocking execution during the handoff period.

Task Space Helper Behaviors by Ownership

The behavior of task space helpers varies based on the current ownership state, as documented in the source comments of package/ego-browser/src/helpers.ts (lines 24-33):

  • switchTaskSpace: Throws an error when targeting user-owned spaces, as it only operates on agent-owned contexts.
  • claimTaskSpace: Claims user-owned spaces (changing ownership to "agent") before selecting them.
  • handOffTaskSpace: Skips execution on user-owned spaces, returning { done: false, skipped: "user-owned" }.
  • completeTaskSpace({keep:true}): Skips user-owned spaces without action.
  • completeTaskSpace({keep:false}): Claims user-owned spaces first, then closes them.
  • takeOverTaskSpace: Bypasses ownership checks entirely, restoring the agent overlay immediately.
  • waitForAgentControl: Polls until agent control is restored, handling the transition from "agentDelegatedToUser" back to "agent".

Practical Implementation Examples

The following patterns demonstrate proper handoff implementation using the ego-browser API:

// Hand off the current task space to the user for manual intervention
import * as taskSpaces from "ego-browser";

await taskSpaces.handOffTaskSpace(); // returns { done: true }
// If already user-owned, returns { done: false, skipped: "user-owned" }
// Claim a user-owned space before closing it
import * as taskSpaces from "ego-browser";

await taskSpaces.completeTaskSpace("my-user-space", { keep: false });
// Claims ownership, then closes the space. Returns { done: true }.
// Wait for user to finish, then resume agent operations
import * as taskSpaces from "ego-browser";

await taskSpaces.waitForAgentControl("my-space"); // polls until control returns
// Safe to execute browser commands after this resolves

Error Handling During User Control

When the agent attempts unauthorized operations on a user-controlled space, the system returns EGO_TASK_SPACE_USER_IN_CONTROL. This error code, recognized in package/ego-browser/src/ego-errors.ts, signals that the agent must not retry the operation and should instead wait for the user to release control via waitForAgentControl() or explicitly reclaim the space using takeOverTaskSpace().

Summary

  • Ego-lite uses three ownership states: "agent" (full control), "agentDelegatedToUser" (paused agent, user active), and "user" (user control, agent blocked).
  • Handoff requires explicit delegation: The handOffTaskSpace() helper transitions agent-owned spaces to delegated states, while takeOverTaskSpace() restores agent control without ownership validation.
  • User-owned spaces are protected: Native bindings enforce boundaries that trigger EGO_TASK_SPACE_USER_IN_CONTROL errors when agents attempt unauthorized access.
  • Claiming converts ownership: The claimTaskSpace() and completeTaskSpace({keep:false}) helpers can convert user-owned spaces to agent ownership when necessary.
  • Polling enables synchronization: waitForAgentControl() provides a blocking mechanism for agents to pause execution until users finish manual operations.

Frequently Asked Questions

What happens when an agent tries to control a user-owned task space?

The native ego bindings return the error code EGO_TASK_SPACE_USER_IN_CONTROL, which the system treats as a hard stop that prevents retry. According to package/ego-browser/src/ego-errors.ts, this error indicates the agent must wait for the user to release control or explicitly claim the space first.

How does the agent know when the user has finished their session?

The agent calls waitForAgentControl() from package/ego-browser/src/helpers.ts, which continuously polls the native bridge until the task space returns to agent control. This function blocks execution until the user hands back control or the agent forcibly reclaims the space using takeOverTaskSpace().

Can a user-owned task space be converted to agent ownership?

Yes, through the claimTaskSpace() helper, which changes the ownership field from "user" to "agent". Additionally, calling completeTaskSpace({keep:false}) on a user-owned space first claims it (converting ownership) and then closes the task space entirely.

What is the difference between "agent" and "agentDelegatedToUser" ownership?

Both states indicate the agent created the space, but "agentDelegatedToUser" signifies the agent has temporarily handed operational control to the user while retaining ownership claims. The isAgentOwned helper in package/ego-browser/src/helpers.ts recognizes both as agent-owned, allowing the agent to reclaim either without claiming, whereas "user" owned spaces require explicit claiming before agent operations can resume.

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 →