feat: long-running worktrees for /fresh + autopilot sequence mode#26
Merged
Conversation
Rewrite /fresh from a "create a new worktree" command to a "re-key the current worktree to a new task" command, matching the long-running-worktree workflow where each terminal tab owns a persistent worktree directory. /fresh now discards working-tree state, fetches origin/<default>, creates a new branch, and delegates repo-specific process/container cleanup to a new .glorious/hooks/fresh-reset hook (scoped to this worktree only, never touches siblings). Adds --yes flag for non-interactive invocation by autopilot loops, with a deterministic decision matrix that aborts on tracked/intentional changes and only auto-discards gitignored debris. Writes .agent/fresh-handoff.md with tracker context + atomically resets autopilot-state.json iteration counters so the autopilot plugin can pick up the new task. Extends /autopilot with a sequence-of-issues mode: when given a Linear project, GitHub milestone, or "next N issues in <project>" phrase, autopilot loops through issues, pre-checks PR state (skips already-shipped refs), invokes /fresh <ref> --yes between each, and logs results to .agent/autopilot-sequence-log.md. Hard stops on dirty tracked trees, MAX_ITERATIONS hits, or repeated plan rejections; soft-skips already-shipped refs. Never auto-ships — the human /ship gate remains per-PR. Updates the autopilot plugin to detect /fresh re-key transitions via fresh-handoff.md mtime tracking + iteration-counter reset, injecting a new-task nudge that tells the agent to read the handoff brief and ignore prior plans in the same session. Preserves lastHandoffMtime across every state-write path (MAX_ITERATIONS reset, plan-completion reset, user-message reset) to prevent misfiring on stale briefs from prior sessions.
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.
Summary
Reshapes
/fresharound the long-running-worktree model and extends/autopilotwith a sequence-of-issues mode. Companion plugin changes let the autopilot plugin detect/freshre-key transitions and nudge the agent to pick up the new task from a handoff brief.Motivation
The previous
/freshcreated a new worktree directory every invocation. In practice, engineers keep 7-10 terminal tabs open — one per persistent worktree — and want/freshto transition the current tab to a new task without creating a new directory, killing the session, or touching sibling worktrees' Postgres/docker/dev-server state.Two concrete inefficiencies in the old flow drove this:
pnpm install+ Postgres slot reshuffle for what should be a branch rename.What changed
home/.claude/commands/fresh.md— full rewrite/freshre-keys the current worktree. Nogsag wt new. Nocdhint.git fetch origin <base>→git checkout -b <new-branch> origin/<base>→ invoke.glorious/hooks/fresh-reset→ write.agent/fresh-handoff.md→ reset autopilot state → summary.--yesflag for non-interactive invocation (autopilot/orchestrator callers). Deterministic decision matrix:.glorious/hooks/fresh-resetreceivesWORKTREE_DIR,WORKTREE_NAME,OLD_BRANCH,NEW_BRANCH,BASE_BRANCH+ pass-through args. Hook is responsible for scoping cleanup to this worktree only (never touches siblings)..agent/fresh-handoff.mdwith tracker context, branch info, hook output — the canonical artifact the agent reads to pick up the new task..agent/autopilot-state.jsoniteration counters so the plugin treats the next idle event as a fresh start.home/.claude/commands/autopilot.md— sequence mode addednext N issues in <project>phrases)..agent/autopilot-queue.jsonfor mid-sequence resumption./fresh <ref> --yes→ orchestrator arc → log result → repeat./shipgate stays human-driven per-PR./fresh --yesaborts, MAX_ITERATIONS hit, plan-reviewer rejects 3+ times, circular failure.home/.config/opencode/plugins/autopilot.ts— /fresh transition detectionlastHandoffMtimefield toSessionAutopilotstate.getHandoffMtime()helper./fresh), injects a "new task — read.agent/fresh-handoff.md" nudge instead of the normal "continue the plan" nudge.lastHandoffMtimeacross every state-write path (MAX_ITERATIONS reset, plan-completion reset, chat.message reset) to prevent misfires.Test plan
bun --print "import(...)"— passes.install.shdry-run was not re-exercised because no new files were added and noopencode.jsonentries changed./fresh GEN-1128 --yesinside a worktree, confirm branch switches, handoff brief is written, autopilot state is zeroed. Run/autopilot "Linear project X"(once the autopilot sequence-mode classifier lands in practice) and observe the loop.Out of scope
/deep-plan. No retroactive plan is written.install.shprune-on-rename. A future nice-to-have but not needed for this change — the new files replace existing files at the same paths./freshcan be simplified further. Not needed now — the long-running-worktree model sidesteps the need.Risk
Low. The old
/freshwas a user-invoked slash command with no downstream callers that would break. The autopilot plugin's additions are all guarded (null-check onhandoffMtime, first-encounter seeding, preserve-across-writes). The plugin backward-compatibly reads old state entries (missinglastHandoffMtime= undefined = 0 = never-seen), so existing state files work without migration.Commit
`7ba0f80 feat: long-running worktrees for /fresh + autopilot sequence mode`