Skip to content

Fix daemon terminating Claude for project-based tasks#495

Merged
bborn merged 1 commit intomainfrom
task/1965-fix-daemon-terminating-claude-for-projec
Mar 4, 2026
Merged

Fix daemon terminating Claude for project-based tasks#495
bborn merged 1 commit intomainfrom
task/1965-fix-daemon-terminating-claude-for-projec

Conversation

@bborn
Copy link
Owner

@bborn bborn commented Mar 4, 2026

Summary

  • Root cause: UpdateTask() in setupWorktree/setupSharedWorkDir writes all task fields back to DB, including the stale task.Status ("queued"). This overwrites the "processing" status set by updateStatus() earlier, because updateStatus() only updates the DB — not the in-memory task struct. When pollTmuxSession sees status="queued" on its first tick, it returns {Interrupted: true}, killing Claude and leaving the task queued → infinite retry loop.
  • Fix: Keep task.Status in sync with DB after updateStatus(processing) so subsequent UpdateTask() calls preserve the correct status
  • Also: result.Interrupted handler now explicitly sets status to backlog (doesn't assume Interrupt() already did it), and CleanupWorktree skips git worktree remove for non-worktree tasks (avoids "fatal: is a main working tree")

Test plan

  • TestUpdateTaskDoesNotResetStatus - verifies UpdateTask preserves processing status
  • TestCleanupWorktreeNonWorktreeTask - verifies cleanup handles non-worktree tasks
  • All existing executor tests pass
  • All internal package tests pass
  • Manual: create task in named project, verify Claude runs to completion without immediate termination
  • Manual: delete a non-worktree task, verify no "fatal: is a main working tree" error

🤖 Generated with Claude Code

Root cause: UpdateTask() in setupWorktree/setupSharedWorkDir writes ALL
task fields back to the DB, including the stale task.Status ("queued").
This overwrites the "processing" status set by updateStatus() moments
earlier, because updateStatus() only updates the DB but not the in-memory
task struct. When pollTmuxSession sees status="queued" on its first tick,
it returns {Interrupted: true}, which kills Claude and leaves the task
in "queued" status, creating an infinite retry loop.

Fix: Keep task.Status in sync after updateStatus(processing) so that
subsequent UpdateTask() calls preserve the correct status.

Also fixes:
- result.Interrupted handler now explicitly sets status to backlog
  instead of assuming Interrupt() already did it
- CleanupWorktree skips "git worktree remove" for non-worktree tasks
  where WorktreePath is the project root (avoids "fatal: is a main
  working tree" error)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bborn bborn merged commit 97d2caf into main Mar 4, 2026
4 checks passed
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