Skip to content

🤖 feat: add isolation:none for non-local sub-agent tasks#3475

Open
ammar-agent wants to merge 11 commits into
mainfrom
agent-isolation-cs0v
Open

🤖 feat: add isolation:none for non-local sub-agent tasks#3475
ammar-agent wants to merge 11 commits into
mainfrom
agent-isolation-cs0v

Conversation

@ammar-agent

@ammar-agent ammar-agent commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds an isolation: none | fork configuration to the task tool so sub-agents on non-local runtimes (worktree/SSH) can run directly in the parent workspace's checkout instead of paying for a fork. fork remains the default to preserve current semantics. The parameter is runtime-conditional: on local runtimes it is omitted from the tool schema entirely, so it never enters LLM context.

Background

On worktree/SSH runtimes, every spawned sub-agent forks a new checkout (git worktree / remote clone) plus runs init hooks. For read-only analysis (e.g. explore) — or when the caller has already arranged isolation via the prompt — that overhead is pure waste. Local runtimes already share the project directory, so forking is a no-op there and the option is meaningless (hence hidden).

Implementation

  • Runtime-conditional tool schema (the novel part). createTaskTool now builds its inputSchema per runtime: buildTaskToolAgentArgsSchema({ includeIsolation }). isolation is only included for runtimes that support sharing the parent checkout (runtimeModeSupportsSharedTaskWorkspace → worktree/SSH). The local schema is .strict() without the field, so the model is never shown it. The canonical schema (with isolation) is still used for the execute() re-parse and token counting.
  • No-fork path in TaskService.create. When isolation: "none" is honored, the task skips orchestrateFork, points its workspace path at the parent's checkout, reuses the parent runtime config, and skips runBackgroundInit (the parent dir is already initialized). The runtime is built with the child's identity but the parent's persisted path; WorktreeRuntime now honors that path override (mirroring SSHRuntime) so cwd resolution and ensureReady land in the shared checkout.
  • Queued/dequeue path (reservation launch flow). Queued shared tasks persist taskIsolation: "none" with path pointing at the parent's checkout. On dequeue, getExistingMaterializedTaskLaunch reuses that existing path (no fork), and startReservedAgentTask skips runBackgroundInit for it. If the parent checkout disappeared before dequeue, materialization falls back to a real fork and the shared flag is cleared so the new worktree is cleaned up normally.
  • Batched creation. TaskService.createMany() applies the same gating: honored plans persist the parent's checkout path + taskIsolation: "none", and the reservation launch reuses it without fork/init.
  • Deletion safety. WorkspaceService.remove skips physical runtime deletion for taskIsolation: "none" tasks so removing a shared task never deletes the parent's working tree. Internal failure-cleanup helpers (cleanupMaterializedTaskWorkspace, rollbackFailedTaskCreate) take a preservePhysicalWorkspace flag for the same reason — notably SSHRuntime.deleteWorkspace resolves through the persisted-path override, which would otherwise target the parent checkout.
  • Scope. Honored for worktree and ssh (the runtimes named in the request). docker/devcontainer tie runtime identity to the workspace name in the runtime factory, so they are intentionally excluded for now; multi-project parents also fall back to forking.

Validation

  • make static-check green (incl. regenerated docs/hooks/tools.mdx + built-in skill snapshot from the new tool param).
  • New tests: schema is runtime-conditional (task.test.ts asserts the advertised schema rejects/accepts isolation per runtime; toolDefinitions.test.ts covers the builder + description gating; runtime.test.ts covers the gating helper), isolation is forwarded to TaskService.create, integration tests that isolation: "none" shares the parent worktree without calling orchestrateFork/runBackgroundInit (both the immediate path and the queued→dequeue reservation path), and a guard test that remove never deletes the shared parent checkout.

Risks

  • Touches the hot TaskService.create path (immediate + queued + reservation dequeue) and WorkspaceService.remove. The shared path is gated behind an opt-in flag and supported runtimes; default fork behavior is unchanged. Main regression surface is task lifecycle (create/remove) on worktree/SSH — covered by the full taskService/workspaceService suites.

Generated with mux • Model: anthropic:claude-fable-5 • Thinking: high • Cost: $40.36

@mintlify

mintlify Bot commented Jun 5, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Mux 🟢 Ready View Preview Jun 5, 2026, 9:34 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f4c7f284b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/common/types/runtime.ts
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed the P1 (worktree shared-checkout resolution):

WorktreeRuntime now honors an explicit workspacePath override (mirroring SSHRuntime.getWorkspacePath). For an isolation: "none" task, the runtime is built with the child's unique name but the parent's persisted checkout path, so getWorkspacePath / ensureReady / cwd resolution all land in the parent checkout instead of the name-derived directory that was never created. Added WorktreeRuntime.test.ts covering the override + ensureReady. (SSH already honored the override via its identity-keyed getWorkspacePath.)

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Allow worktree/SSH sub-agents to skip fork overhead by sharing the parent
workspace checkout (isolation: none|fork, default fork). The isolation tool
parameter is conditionally added to the task tool schema based on runtime, so
it never enters LLM context on local runtimes.
Codex P1: worktree isolation:none tasks resolved cwd/ensureReady from the
name-derived child path (never created) instead of the parent checkout. Make
WorktreeRuntime honor an explicit workspacePath override (mirroring SSHRuntime)
so shared tasks land in the parent's checkout. Adds WorktreeRuntime tests.
@ammar-agent ammar-agent force-pushed the agent-isolation-cs0v branch from 1a75460 to d441167 Compare June 12, 2026 14:46
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Rebased onto latest main. The dequeue path was re-implemented for the new reservation/launch-plan architecture (startReservedAgentTask now skips init for shared tasks and clears taskIsolation on fork fallback), and failure-cleanup helpers gained a preservePhysicalWorkspace guard so SSH cleanup can never delete the shared parent checkout. Added a dequeue-path integration test.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d4411679e4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/taskService.ts
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed the P2: TaskService.createMany() now applies the same isolation: "none" gating as create() — honored plans persist the parent's checkout path plus taskIsolation: "none", and the reservation launch path (startReservedAgentTaskgetExistingMaterializedTaskLaunch) reuses that checkout without fork/init. Added an integration test covering the batched path.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 527ae6a78b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/taskService.ts Outdated
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed: create() and createMany() now resolve parentWorkspacePath from the parent's persisted checkout path (falling back to the name-derived path), so nested delegation from an isolation: "none" parent discovers agents in the real shared checkout instead of a non-existent synthetic-name path. The shared-path computation now reuses that same value.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 20d46e4bf5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/taskService.ts
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed the P1 (fork source from a shared parent):

  • create(), createMany(), and startReservedAgentTask() now build the parent/source runtime with namedWorkspacePath from the parent's persisted entry, so override-aware runtimes resolve the parent's real checkout.
  • WorktreeRuntime.forkWorkspace now resolves the source path through its override-aware getWorkspacePath and passes it to WorktreeManager.forkWorkspace (new optional sourceWorkspacePath); SSHRuntime.forkWorkspace already resolves the source via this.getWorkspacePath, so the runtime-level override covers it.
  • Added a WorktreeRuntime test proving a fork whose source is a synthetic-named shared task succeeds from the parent checkout.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

const trunkBranch = coerceNonEmptyString(parentMeta.name);

P2 Badge Persist the real branch for shared queued tasks

When a queued isolation: "none" task is spawned from a parent that is itself a shared task, parentMeta.name is the synthetic agent workspace name rather than the branch checked out in the shared parent checkout. If that shared checkout is gone by dequeue time, startReservedAgentTask explicitly falls back to forking and passes this persisted taskTrunkBranch as preferredTrunkBranch, so the fallback tries to create the worktree from a nonexistent synthetic branch (or the wrong base) instead of the parent's real branch. Persist the checked-out branch or the parent's existing taskTrunkBranch for shared tasks.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed the trunk-branch P2: create() and createMany() now persist taskTrunkBranch as the branch actually checked out in the parent's checkout — when the parent is itself an isolation: "none" task (synthetic name), the parent's own persisted taskTrunkBranch is used instead of parentMeta.name. Dequeue fork-fallbacks (preferredTrunkBranch) therefore always reference a real branch. Added a nested shared-parent integration test asserting the persisted branch and checkout path.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdb3baec99

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/taskService.ts
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed: when the parent is a shared (isolation: "none") task, create() now passes the computed real branch as preferredTrunkBranch to orchestrateFork, and createMany() sets it on the launch plan (flowing into materializeReservedTaskWorkspace's fork + getExistingMaterializedTaskLaunch's fallback chain). Gated to shared parents so the existing branch-discovery fallback is unchanged for normal parents.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0255317fb5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceService.ts
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed: WorkspaceService.remove now also guards the inverse direction — before physically deleting a workspace's checkout, it scans config for other entries with taskIsolation: "none" whose persisted path points at this checkout and whose task status is active (queued/starting/running/awaiting_report). If found, runtime deletion is skipped (config/session cleanup still runs) so live shared sub-agents keep their cwd. Reported/interrupted shared children don't block deletion. Added tests for both the active-child skip and the reported-child delete.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cdf30e02ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/node/services/workspaceService.ts Outdated
@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

Addressed: queued shared children no longer block parent checkout deletion. Rationale: dequeue (maybeStartQueuedTasksFromReservations) requires the parent config entry for ANY isolation mode, so a queued child of a removed parent already fails fast with "Queued task parent not found" — identical to queued forked tasks. Preserving the checkout for a child that cannot launch would only leak the directory. The guard now covers starting/running/awaiting_report (live streams whose cwd must survive), with tests for the queued-deletes and active-preserves cases.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep them coming!

Reviewed commit: 10917f41e8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant