Skip to content

feat: coordinate isolated subagent dispatch#670

Merged
yogthos merged 7 commits into
mainfrom
feat/subagent-dispatch-strategy
Jul 16, 2026
Merged

feat: coordinate isolated subagent dispatch#670
yogthos merged 7 commits into
mainfrom
feat/subagent-dispatch-strategy

Conversation

@nikolap

@nikolap nikolap commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR adds coordinated subagent dispatch with optional worktree isolation for read-write subagents, plus the lifecycle hardening identified during review. Resolves #660

  • Coordinates background subagents in batches and delivers one reconciliation update after the batch reaches terminal states.
  • Routes work through configured readonly and readwrite agent profiles.
  • Runs isolated writers in rooted Git worktrees when available; otherwise auto mode warns and serializes writers in the parent checkout.
  • Preserves writer branch, path, commit, dirty-state, and salvage metadata in reconciliation output.
  • Documents configuration, dispatch modes, worktree behavior, limits, and troubleshooting in docs/subagent-dispatch-strategy.md.

Validation

cargo fmt --check
cargo check --bin dirge
cargo clippy --all-targets -- -D warnings
cargo test --bin dirge -- --skip h7_glm

@nikolap
nikolap force-pushed the feat/subagent-dispatch-strategy branch from 56401ce to 2255982 Compare July 16, 2026 06:39
Yogthos added 2 commits July 16, 2026 07:08
- attach_handle no longer re-inserts a handle for a task that already
  finished (notify races ahead of attach on a multi-thread runtime),
  which was leaking phantom running slots and wedging the 4/4 cap.
- A panic or early return in a coordinated subagent closure now marks
  the task Failed via a drop guard (notify_if_running) instead of
  leaving it stuck Running forever and stalling the batch barrier.
- cancel_all reports retained (dirty/committed) writer worktree paths
  and branches before dropping coordinator state, so salvaged work
  isn't orphaned without a pointer.
…rent writers

Worktree write-isolation only confines the writer's shell when a real
OS sandbox (bwrap) is active; without it (macOS / sandbox off) the
writer's bash could escape the worktree via ../ or absolute paths. Gate
worktree isolation on Sandbox::confines_writes() — an explicit Worktree
mode errors, Auto falls through to a serialized parent-checkout run.

A serialized writer running in the parent checkout is now refused when
that checkout is dirty (it would clobber the user's uncommitted work via
edits / git add -A). Covers both the gated-off path and the auto-fallback
after a failed worktree creation. Docs updated to match.
@yogthos

yogthos commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Reviewed and merging. Thanks @nikolap — the core design is solid: file-tool isolation via ToolRoot (absolute/..//symlink escapes all caught), the readonly tier allowlist, permission cwd-scoping, the timeout clamp, and writer-vs-writer serialization all check out.

I pushed two fix commits addressing issues the review found:

Coordination robustness

  • attach_handle no longer re-inserts a handle for a task that already notify()d (a race on multi-thread runtimes that leaked phantom running slots and could wedge the concurrency cap).
  • A panic / early-return in a coordinated subagent closure now marks the task Failed via a drop guard (notify_if_running) instead of leaving it stuck Running and stalling the batch barrier forever (dropping the completed siblings' results).
  • cancel_all reports retained (dirty/committed) writer-worktree paths + branches before dropping coordinator state, so salvaged work isn't orphaned without a pointer.

Isolation + data-loss

  • Worktree write-isolation is gated on a confining sandbox (Sandbox::confines_writes()): without one (macOS / sandbox off), the writer's bash could escape the worktree via ..//absolute paths, so explicit Worktree now errors and Auto falls back to a serialized parent run.
  • A serialized writer is refused when the parent checkout is dirty (it was editing / git add -A-ing over the user's uncommitted work). Docs updated.

Deferred as follow-ups (filed internally): worktree writers not honoring profile allow/deny; the parent .git bind-mounted read-write into the writer sandbox (ref/hook tampering); plus minor hardening (unbounded retry chain, batch can exceed 4, dispatches map growth, orphan-worktree GC).

@yogthos
yogthos merged commit 067452d into main Jul 16, 2026
13 checks passed
@yogthos
yogthos deleted the feat/subagent-dispatch-strategy branch July 16, 2026 11:14
yogthos pushed a commit that referenced this pull request Jul 17, 2026
Defer the critic on a parent turn waiting for coordinated subagents, and
normalize blank task retry ids (#679). Also backfill CHANGELOG: coordinated
subagent dispatch (#670) under 0.19.10 and the OpenCode reasoning fix (#671)
under 0.19.9, which shipped but weren't recorded.
allen-munsch pushed a commit to allen-munsch/dirge that referenced this pull request Jul 18, 2026
Defer the critic on a parent turn waiting for coordinated subagents, and
normalize blank task retry ids (dirge-code#679). Also backfill CHANGELOG: coordinated
subagent dispatch (dirge-code#670) under 0.19.10 and the OpenCode reasoning fix (dirge-code#671)
under 0.19.9, which shipped but weren't recorded.
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.

Optional subagent dispatch strategy

2 participants