Summary
Task mode (the default execution mode for /zerg:rush) currently has no git worktree isolation. All subagent workers edit files in the same working directory. Conflict prevention relies entirely on:
- Design-time validation —
validate_file_ownership() ensures no file appears in two tasks' files.create or files.modify lists
- Prompt-based discipline — each worker prompt includes
"IMPORTANT: Only touch files listed above. Other files are owned by other tasks."
- Level sequencing — all Level N tasks complete before Level N+1 starts
Container and subprocess modes already use full git worktree isolation via WorktreeManager. This issue tracks adding optional worktree isolation to task mode for stronger conflict guarantees.
Current Architecture
Task Mode (no isolation)
/zerg:rush (default, --mode task)
→ Orchestrator uses Task tool for parallelization
→ All subagents share the same working directory
→ File ownership enforced by prompt instructions only
→ No merge phase needed — direct commits to shared checkout
Relevant prompt template (rush.core.md:159-199):
## Files
- **Create**: {files.create}
- **Modify**: {files.modify}
- **Read (context only)**: {files.read}
IMPORTANT: Only touch files listed above. Other files are owned by other tasks.
## On Completion
1. Stage ONLY your owned files: git add {files.create + files.modify}
2. Commit with message: "feat({FEATURE}): {TASK_ID} - {title}"
Container/Subprocess Mode (full isolation)
/zerg:rush --mode container|subprocess
→ WorkerManager.spawn_worker(worker_id)
→ WorktreeManager.create(feature, worker_id)
→ git worktree add .zerg-worktrees/{feature}/worker-{id} zerg/{feature}/worker-{id}
→ Each worker operates in isolated worktree on dedicated branch
→ Merge phase reconciles branches after each level
Relevant code (rush.core.md:238-262):
for i in $(seq 0 $((WORKERS - 1))); do
BRANCH="zerg/$FEATURE/worker-$i"
WORKTREE="../.zerg-worktrees/$FEATURE/worker-$i"
git worktree add "$WORKTREE" "$BRANCH"
done
Problem Statement
While prompt-based file ownership works in practice (LLM workers rarely edit files they aren't told to), there is no runtime enforcement. Failure modes include:
- Accidental file touches — A worker modifies a shared config file, utility, or
__init__.py that it reads but doesn't own. Common with auto-formatters or IDE-style cleanup behaviors.
- Implicit side effects — Running
ruff format or similar tools in the shared directory reformats files beyond the worker's ownership scope.
- Race conditions on git operations — Two workers running
git add + git commit concurrently in the same checkout can produce corrupted commits or include unintended files.
- No rollback granularity — If one worker in a level fails, its partial changes are already committed to the shared branch. There's no clean way to revert just that worker's changes without reverting the entire level.
Proposed Enhancement
Add optional worktree isolation to task mode, controllable via a flag:
/zerg:rush --isolate # Enable worktree isolation in task mode
/zerg:rush --isolate=worktree # Explicit (same as above)
/zerg:rush # Default: no isolation (current behavior)
Implementation Approach Options
Option A: Claude Code Native Worktree Isolation
Claude Code's Agent tool supports isolation: "worktree" natively. Each Task tool call could use this:
# In rush.core.md subagent prompt generation
# Add isolation parameter to each Task tool call
Agent(
prompt="You are ZERG Worker executing task {TASK_ID}...",
subagent_type="general-purpose",
isolation="worktree" # <-- Claude Code creates/manages worktree automatically
)
Pros:
- Zero custom worktree management needed — Claude Code handles creation and cleanup
- Each subagent gets an auto-managed worktree with its own branch
- Minimal changes to ZERG codebase
Cons:
- Merge strategy is opaque — Claude Code manages the worktree lifecycle, not ZERG
- Changes made in the worktree may need manual merging back
- Less control over branch naming, cleanup timing, and merge order
- Need to verify Claude Code worktree behavior with concurrent agents
Option B: Reuse Existing WorktreeManager
Extend the existing WorktreeManager (zerg/worktree.py) to task mode:
# Before launching task-mode subagents at each level:
worktree_mgr = WorktreeManager(repo_path)
for task in level_tasks:
wt_path = worktree_mgr.create(feature, task.id, base_branch="main")
# Pass worktree path to subagent prompt
# Subagent uses: cd {wt_path} && <do work>
# After level completes:
for task in level_tasks:
merge_worker_branch(task)
worktree_mgr.delete(wt_path)
Pros:
- Full control over worktree lifecycle, branch naming, merge order
- Consistent with container/subprocess modes
- Reuses existing, tested
WorktreeManager API
- Enables ZERG's existing merge coordinator for conflict resolution
Cons:
- Requires adding a merge phase to task mode (currently has none)
- Significant complexity increase — task mode's simplicity is a feature
- Disk space overhead (full checkout per worker per level)
- Slower execution (worktree creation + merge per level)
Option C: Hybrid — Lightweight File Locking
Instead of full worktree isolation, add runtime file-level enforcement:
# Before task execution, create lock files for owned files
for file in task.files.create + task.files.modify:
lock_path = f".zerg/locks/{hashlib.sha256(file.encode()).hexdigest()}"
# Attempt exclusive lock creation
# Fail if lock already held by another task
# After task completion, release locks
Pros:
- Minimal overhead (no worktree creation, no merge phase)
- Catches accidental cross-ownership edits at runtime
- Preserves task mode's simplicity
Cons:
- Doesn't prevent git staging race conditions
- Lock management adds complexity
- Subagents may not honor lock checks (prompt-based again)
Recommended Approach
Option A (Claude Code native isolation: "worktree") for initial implementation:
- Lowest implementation cost
- Leverages platform-native isolation
- Can upgrade to Option B later if more control is needed
Option B as a follow-up if Option A proves insufficient for merge control or branch naming requirements.
Key Files
| File |
Role |
Lines |
zerg/data/commands/rush.core.md |
Task mode execution flow (Step 2) |
95-228 |
zerg/data/commands/rush.core.md |
Container/subprocess worktree setup (Step 3) |
232-262 |
zerg/worktree.py |
WorktreeManager — create, delete, list, sync |
30-340 |
zerg/worker_manager.py |
WorkerManager — calls worktree create/delete on spawn/terminate |
— |
zerg/launcher_configurator.py |
Mode detection and launcher creation |
117-126 |
zerg/validation.py |
validate_file_ownership() — design-time conflict detection |
— |
zerg/data/commands/merge.core.md |
Merge coordinator (container/subprocess only) |
— |
Acceptance Criteria
Risks & Mitigations
| Risk |
Impact |
Mitigation |
| Merge conflicts between worker branches |
Tasks fail at merge phase |
File ownership validation prevents overlapping modifications by design |
| Disk space (N worktrees × full repo) |
CI/local runs hit disk limits |
Shallow worktrees, cleanup after each level, document disk requirements |
| Performance regression (worktree creation overhead) |
Slower task-mode execution |
Measure overhead, make isolation opt-in (not default) |
Claude Code isolation: "worktree" behavior changes |
Breaking changes upstream |
Pin to known-good behavior, add integration tests |
| Subagents can't find spec files in worktree |
Task execution fails |
Copy or symlink .zerg/specs/ into worktree, or use absolute paths |
Non-Goals
- Making isolation the default — task mode's simplicity is valuable; this is opt-in
- Replacing container/subprocess modes — those modes serve different deployment needs
- Runtime file locking — may be a separate enhancement (Option C above)
- Cross-level worktree persistence — worktrees are per-level, not per-feature
Related Issues
Summary
Task mode (the default execution mode for
/zerg:rush) currently has no git worktree isolation. All subagent workers edit files in the same working directory. Conflict prevention relies entirely on:validate_file_ownership()ensures no file appears in two tasks'files.createorfiles.modifylists"IMPORTANT: Only touch files listed above. Other files are owned by other tasks."Container and subprocess modes already use full git worktree isolation via
WorktreeManager. This issue tracks adding optional worktree isolation to task mode for stronger conflict guarantees.Current Architecture
Task Mode (no isolation)
Relevant prompt template (
rush.core.md:159-199):Container/Subprocess Mode (full isolation)
Relevant code (
rush.core.md:238-262):Problem Statement
While prompt-based file ownership works in practice (LLM workers rarely edit files they aren't told to), there is no runtime enforcement. Failure modes include:
__init__.pythat it reads but doesn't own. Common with auto-formatters or IDE-style cleanup behaviors.ruff formator similar tools in the shared directory reformats files beyond the worker's ownership scope.git add+git commitconcurrently in the same checkout can produce corrupted commits or include unintended files.Proposed Enhancement
Add optional worktree isolation to task mode, controllable via a flag:
Implementation Approach Options
Option A: Claude Code Native Worktree Isolation
Claude Code's
Agenttool supportsisolation: "worktree"natively. Each Task tool call could use this:Pros:
Cons:
Option B: Reuse Existing WorktreeManager
Extend the existing
WorktreeManager(zerg/worktree.py) to task mode:Pros:
WorktreeManagerAPICons:
Option C: Hybrid — Lightweight File Locking
Instead of full worktree isolation, add runtime file-level enforcement:
Pros:
Cons:
Recommended Approach
Option A (Claude Code native
isolation: "worktree") for initial implementation:Option B as a follow-up if Option A proves insufficient for merge control or branch naming requirements.
Key Files
zerg/data/commands/rush.core.mdzerg/data/commands/rush.core.mdzerg/worktree.pyWorktreeManager— create, delete, list, synczerg/worker_manager.pyWorkerManager— calls worktree create/delete on spawn/terminatezerg/launcher_configurator.pyzerg/validation.pyvalidate_file_ownership()— design-time conflict detectionzerg/data/commands/merge.core.mdAcceptance Criteria
--isolateflag parsed by/zerg:rushzerg/{feature}/task-{id}--isolateis activevalidate_file_ownership()still runs at design time (defense in depth)/zerg:statusreports worktree state when isolation is active/zerg:cleanuphandles task-mode worktrees--isolate, verify no cross-contaminationRisks & Mitigations
isolation: "worktree"behavior changes.zerg/specs/into worktree, or use absolute pathsNon-Goals
Related Issues