How Ego-Browser Helpers Handle User-Owned Task Spaces: Skip Logic and Claim Workflows

Ego-browser helpers automatically skip mutating actions on user-owned task spaces, returning { done: false, skipped: "user-owned" } unless you explicitly claim the space first.

When building autonomous browsing workflows with ego-browser, understanding how task space ownership affects helper behavior is critical for reliable agent-user collaboration. The citrolabs/ego-lite repository implements a strict protection model: user-owned contexts are immutable by default, preventing accidental interference while preserving explicit control.


Understanding Task Space Ownership Levels

Every task space in ego-browser carries an ownership field with three possible values:

  • 'agent' — Fully controlled by the agent; all helpers operate normally
  • 'agentDelegatedToUser' — Agent-initiated but user-visible; partial restrictions apply
  • 'user' — User-created and user-controlled; mutating helpers are blocked

This ownership model is documented in skills/ego-browser/SKILL.md:

"Every task space has ownership: 'agent' | 'agentDelegatedToUser' | 'user'; the helpers treat user‑owned spaces differently."【/SKILL.md#L75-L82】


Helper Behavior When Targeting User-Owned Spaces

The skip logic is centralized in package/ego-browser/src/helpers.ts. Here's how each helper responds:

Helper User-Owned Behavior
handOffTaskSpace Skipped — resolves to { done: false, skipped: "user-owned" }【/helpers.ts#L123-L128】
completeTaskSpace(..., { keep: true }) Skipped — same skip result as above【/helpers.ts#L123-L128】
claimTaskSpace Allowed — transfers ownership to agent, enabling subsequent operations【/helpers.ts#L206-L218】
useOrCreateTaskSpace Selects without claiming — does NOT auto-transfer ownership; space remains user-owned【/helpers.ts#L123-L128】
handOffTaskSpace (post-claim) Works normally — only if ownership was successfully changed; otherwise still skipped【/helpers.ts#L298-L324】

The implementation uses a consistent check pattern. In helpers.ts, the core skip condition evaluates whether space.ownership === 'user' before executing mutating operations.


The Claim-First Workflow

To modify a user-owned task space, you must explicitly claim it first. According to SKILL.md:

"To work with a user‑owned space you must first claim it (e.g., await claimTaskSpace(id)) before performing any modifying actions. After claiming, the space's ownership changes to the agent, and other helpers operate normally."【/SKILL.md#L73-L77】

This design ensures intentional handoffs rather than silent takeovers.


Practical Code Examples

Detecting and Handling User-Owned Spaces

// List all task spaces and identify a user-owned one
const spaces = await taskSpaces.list();
const userSpace = spaces.find(s => s.ownership === 'user');

// Attempt handoff — will be skipped with diagnostic result
const handoff = await taskSpaces.handOff(userSpace.id);
console.log(handoff); // { done: false, skipped: 'user-owned' }

// Claim transfers ownership to agent
await taskSpaces.claim(userSpace.id);

// Now mutating operations succeed
await taskSpaces.handOff(userSpace.id);                    // works
await taskSpaces.complete(userSpace.id, { keep: true });   // works

useOrCreateTaskSpace Limitations

// useOrCreateTaskSpace does NOT auto-claim user-owned spaces
const ts = await taskSpaces.useOrCreate('my-research');

// If 'my-research' exists and is user-owned:
// - ts is selected and returned
// - ownership remains 'user'
// - handOff/complete will still skip until you claim()

// Required explicit claim for full control
if (ts.ownership === 'user') {
  await taskSpaces.claim(ts.id);
}

Why This Protection Model Matters

The skip-not-fail approach provides several advantages:

  1. Non-destructive defaults — Agents cannot accidentally disrupt user work
  2. Observable behavior — The skipped: "user-owned" return value enables programmatic detection
  3. Explicit consent — The claimTaskSpace requirement acts as an intentional handoff signal
  4. Audit trail — Ownership changes are traceable in space history

This aligns with the broader ego-browser philosophy described in AGENTS.md, which emphasizes clear boundaries between autonomous agent actions and user-controlled contexts【/AGENTS.md#L27-L28】.


Summary

  • User-owned spaces block mutating helpershandOffTaskSpace and completeTaskSpace return { done: false, skipped: "user-owned" } per helpers.ts lines 123-128 and 298-324
  • claimTaskSpace is the gateway — Explicitly transfers ownership from 'user' to 'agent', enabling normal helper operation
  • useOrCreateTaskSpace is conservative — Selects existing spaces without claiming, preserving user ownership
  • Check ownership before acting — Query taskSpaces.list() or inspect the ownership field on any space object to predict helper behavior

Frequently Asked Questions

Why does handOffTaskSpace skip instead of throwing an error?

The ego-browser design favors graceful degradation over exceptions. Returning { done: false, skipped: "user-owned" } allows agents to detect the condition programmatically and decide whether to claim, notify the user, or proceed with read-only operations. This pattern appears consistently across helpers.ts lines 123-128 and 298-324.

Can I override the skip behavior without claiming?

No. The source code in package/ego-browser/src/helpers.ts implements ownership checks without configuration overrides. This is intentional — the only supported path to modify a user-owned space is through claimTaskSpace, which updates the ownership field server-side before subsequent operations proceed.

What happens if I call claimTaskSpace on an already-claimed space?

According to the implementation at helpers.ts lines 206-218, claimTaskSpace is idempotent when called by the owning agent — it succeeds and selects the space. If another agent owns the space, the claim will fail with an ownership conflict error.

How do I detect if a space will trigger skip behavior before calling helpers?

Inspect the ownership property directly on any task space object:

const space = await taskSpaces.get(id);
if (space.ownership === 'user') {
  // Mutating helpers will skip; claim first if modification is needed
  await taskSpaces.claim(id);
}

This check matches the internal logic used by the helpers themselves.

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 →