fix(bg): v0.11.1 background dispatch isolation split (non-git cwd fix) - #19
Merged
Conversation
Proper-fix spec for the background dispatch 100%-failure in non-git cwds. Splits runBackground into a git-agnostic core (runBackgroundInPlace) + a worktree wrapper (runBackgroundIsolated) + an auto router. Adds isolation: worktree|none|auto (default auto) to the subagent tool + scheduler. Synchronous fail-fast on worktree failures. Closes the conflation of background-execution with worktree-isolation; produces the seam SPEC-6-3's agent() isolation opt-in inherits.
6-task TDD implementation plan for the v0.11.1 patch. Task 1: foundation (isGitRepo + optional journal/lifecycle fields). Task 2: the split (core + wrapper + router + index adapter). Task 3: subagent tool isolation param + sync-fail isError. Task 4: scheduler isolation plumbing. Task 5: scanResumeCandidates in-place handling. Task 6: release v0.11.1.
Foundation for the background isolation split. WorktreeService gains a cheap isGitRepo() pre-flight. RunStartedEvent.worktree and RunCompletedEvent.branch become optional (in-place runs have neither). RunLifecycleOpts.worktreePath/branch become optional. Additive — old events still parse; no behavior change.
…r + auto router
runBackgroundInPlace (core) is git-agnostic: pool + journal + runLifecycle
in ctx.cwd, no worktree. runBackgroundIsolated (wrapper) does a SYNCHRONOUS
isGitRepo pre-flight + worktree.create before returning, so worktree failures
surface as { status: 'failed', error } (no runId) — the tool maps to isError,
not an async toast + 90s poll. runBackgroundAuto routes: isolated when cwd is
git (current behavior preserved), in-place + one per-session notify when not.
The index.ts adapter becomes isolation-aware (conditional artifactDiscovery +
parentCwd). Closes the 100% bg failure in non-git cwds.
The subagent tool accepts isolation: worktree|none|auto (default auto). On a synchronous worktree failure (e.g. 'worktree' in a non-git cwd) the tool now returns isError with the actionable message, instead of 'background run: undefined' + an async toast the model never sees.
Scheduled runs are background runs; they inherit the isolation opt-in. ScheduleSpec gains optional isolation (default auto). The onFire callback + subagent tool's schedule branch thread it through to runBackground.
An interrupted in-place run (run:started with no worktree field) has no worktree to clean; abort it + mark canResume=false with an honest reason (partial edits may remain in cwd). ResumeCandidate.worktreePath/branch become optional. Isolated-run handling unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Proper-fix for the background dispatch 100%-failure in non-git cwds (repro:
~/local-dev/bug-bounty, session019fa956…— 7 parallel bg dispatches all died withworktree create failed: not a git repository, then the model polledfleet_results90s for runs that already failed).Root cause
Worktree isolation was conflated with background execution.
runBackgroundunconditionally calledgit worktree add(needs a git repo), and the failure surfaced as an asyncctx.ui.notifytoast the model never saw as a tool result — so it returnedbackground run: fl-…(looks successful) then waited on a dead inbox.The fix (proper architectural split, not a flag)
runBackgroundInPlace— git-agnostic core (pool + journal + runLifecycle inctx.cwd, no worktree).runBackgroundIsolated— worktree wrapper with a synchronousisGitRepo()pre-flight → returns{status:"failed", error}(no runId, no pool slot, no async toast) on failure. The tool maps this toisError.runBackgroundAuto— router: isolated when cwd is git (current behavior preserved), in-place + one per-session notify when not.subagenttool + scheduler gainisolation: "worktree" | "none" | "auto"(defaultauto).RunStartedEvent.worktree?/RunCompletedEvent.branch?/RunLifecycleOpts.worktreePath?/branch?optional (additive; old events still parse).scanResumeCandidateshandles in-place interrupted runs (abort +canResume:false, honest reason).artifactDiscovery+parentCwd).Tests
450/450 pass (+12 new: in-place in non-git, sync-fail worktree-in-non-git, auto-fallback dedup, git-auto regression, explicit-none-in-git, journal optional round-trips, old-event parse, in-place interrupted abort, isGitRepo, subagent sync-fail isError, scheduler persist+load). Typecheck clean. Bug repro covered.
Design
docs/superpowers/specs/2026-07-28-bg-non-git-isolation-split-design.mddocs/superpowers/plans/2026-07-28-bg-non-git-isolation-split.mdThis produces the seam SPEC-6-3's
agent()isolationopt-in will inherit.