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:
- Non-destructive defaults — Agents cannot accidentally disrupt user work
- Observable behavior — The
skipped: "user-owned"return value enables programmatic detection - Explicit consent — The
claimTaskSpacerequirement acts as an intentional handoff signal - 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 helpers —
handOffTaskSpaceandcompleteTaskSpacereturn{ done: false, skipped: "user-owned" }perhelpers.tslines 123-128 and 298-324 claimTaskSpaceis the gateway — Explicitly transfers ownership from'user'to'agent', enabling normal helper operationuseOrCreateTaskSpaceis conservative — Selects existing spaces without claiming, preserving user ownership- Check
ownershipbefore acting — QuerytaskSpaces.list()or inspect theownershipfield 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →