Task Space Ownership States in Ego-Browser: A Complete Guide

Ego-Browser defines three ownership states for task spaces—agent, agentDelegatedToUser, and user—that determine which party controls the browsing context at any given moment.

The ego-browser skill in the citrolabs/ego-lite repository provides isolated browsing contexts called task spaces where AI agents can execute automated actions. Every task space carries an ownership property that enforces strict access control, preventing conflicts when both agents and users need to interact with the same browser window. Understanding these states is essential for building reliable agent workflows that handle user hand-offs gracefully.

The Three Ownership States

According to the SKILL.md documentation, specifically lines 75-80, the ownership policy defines these mutually exclusive states:

agent

The task space is fully owned and controlled by the AI agent. The agent may execute any browser action—navigation, clicking, form filling, JavaScript injection—without restriction. This is the default state when you create a task space with useOrCreateTaskSpace().

agentDelegatedToUser

Control has been temporarily handed off to the user. This state typically occurs when:

  • A CAPTCHA requires human solving
  • Multi-factor authentication needs manual input
  • A login flow demands credentials the agent cannot access

While in this state, any agent-initiated action fails with a "user is controlling" error. The agent must explicitly reclaim the space before resuming automation.

user

The task space is owned by the user from the start. This rare configuration creates a browser window for direct user interaction without any agent involvement. Use this when the user wants a persistent, manually-controlled browsing session alongside agent-driven spaces.

How Ownership Transitions Work

Ownership changes are triggered by specific API calls defined in src/helpers.ts:

Function Ownership Transition Use Case
useOrCreateTaskSpace(name) agent (default) Start or resume agent-controlled automation
handOffTaskSpace(id) agentagentDelegatedToUser Pause for user input
claimTaskSpace(id) agentDelegatedToUseragent Resume agent control after user finishes

The runtime state is maintained in src/state.ts, which stores the ownership field alongside other task-space metadata.

Practical Code Examples

Creating an Agent-Owned Task Space

Start automation with default agent ownership:

// Create (or reuse) a task space that the agent fully controls
const task = await useOrCreateTaskSpace('search-github-issues')
await nav.goto('https://github.com')
await click('a[href="/search"]')
await completeTaskSpace(task.id, { keep: false })

Handing Off for User Interaction

Handle CAPTCHAs or manual logins with proper state management:

// Agent runs until a point where user input is required
await nav.goto('https://example.com/login')
await fill('input[name="email"]', 'user@example.com')
await click('button[type="submit"]')

// Hand off the task space so the user can solve the captcha
await handOffTaskSpace(task.id)
cliLog('Please solve the captcha, then come back.')

// After the user finishes, reclaim the space
await claimTaskSpace(task.id)
await click('#continue')
await completeTaskSpace(task.id, { keep: false })

Inspecting Current Ownership

Audit task spaces to debug permission issues:

// List all task spaces and inspect their ownership
const spaces = await listTaskSpaces()
for (const s of spaces) {
  cliLog(`Task ${s.id} (${s.name}) is owned by ${s.ownership}`)
}

Core Implementation Files

  • skills/ego-browser/SKILL.md – High-level documentation of task-space usage and ownership policy
  • src/helpers.ts – API implementations for useOrCreateTaskSpace, handOffTaskSpace, and claimTaskSpace
  • src/state.ts – Runtime state management including the ownership field
  • src/taskspace-e2e.test.mjs – End-to-end tests validating ownership transitions and hand-off behavior

Common Ownership Errors

The "user is controlling" error occurs when your agent attempts actions during agentDelegatedToUser state. Always verify state or wrap agent actions in error handling:

// Defensive pattern with ownership checking
const space = await getTaskSpace(task.id)
if (space.ownership !== 'agent') {
  await claimTaskSpace(task.id) // Or prompt user to finish
}
// Now safe to proceed with agent actions

Summary

  • Three ownership states govern task space control: agent, agentDelegatedToUser, and user
  • Default agent ownership enables full automation; hand-offs are explicit via handOffTaskSpace()
  • Reclaim with claimTaskSpace() after user interaction completes
  • State is enforced at runtime in src/state.ts, throwing errors for unauthorized access
  • End-to-end tests in taskspace-e2e.test.mjs validate all transition paths

Frequently Asked Questions

How do I check if a task space is currently controlled by the user?

Call listTaskSpaces() or getTaskSpace(id) and inspect the ownership property. If the value is agentDelegatedToUser or user, the agent cannot execute browser actions until ownership returns to agent.

What happens if my agent tries to act during a hand-off?

The action fails immediately with a "user is controlling" error. This is a safety mechanism to prevent the agent from interfering with manual user interaction. You must call claimTaskSpace(id) successfully before resuming automation.

Can I create a task space that starts with user ownership instead of agent?

Yes, though it's rarely needed. Pass ownership: 'user' when creating the space. Most workflows start with agent ownership and transition to agentDelegatedToUser only when user intervention is required.

Is the ownership state persisted across script restarts?

According to the source code in src/state.ts, task space metadata including ownership is maintained in the runtime state. Persistent behavior depends on how ego-browser is integrated into your deployment—review the state management implementation for your specific setup.

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 →