Epic/Sprint Development Workflow Reference
Procedural reference for multi-phase feature development using git worktrees, GitHub issues with sub-issues, and phased PR delivery.
Phase Sizing and Epic-vs-Single Decision
One phase = one independently reviewable and testable PR: roughly one subsystem, one migration, or up to ~500 net lines of non-generated change.
- The description contains 2+ such units -> epic (this workflow).
- Exactly one unit -> single-phase shortcut (below), or simply the engineering-loop skill without epic machinery.
- Unsure how to break a description into phases: each phase must have its own testable Definition of Done; if two candidate phases can only be tested together, they are one phase.
Slug derivation for names: take the phase title, drop stopwords, keep 2-3 words with the object noun first, kebab-case ("backend-metrics", "sync-engine"; never "implement-the-new-backend-metrics").
Related skills, invoked by their fully qualified project:<skill> names through the host's skill-invocation mechanism: implementation-planning (writing each phase plan),
agent-fanout (parallel implementers, one worktree each), engineering-loop
(the inner loop within a phase), debugging (when a phase's tests fail for
unclear reasons).
Model handoff by phase
Follow agent-fanout driver mode. The session driver (Claude Sonnet at
xhigh, Codex Luna at max) orchestrates the workflow mechanically. Epic
decomposition, architecture, and high-risk or contested findings go to Opus
(or Fable) or Sol at xhigh. Named Sonnet or Luna workers implement the
approved brief in the isolated worktree; fresh Sonnet or Luna reviewers review
each phase per the review-convergence rules (two rounds at most). Close/remove
one-off agents after their reports are incorporated.
Branch Strategy Decision Tree
Determine the integration branch and branching model:
-
Integration branch detection:
- If
developbranch exists (local or remote): integration branch =develop - Otherwise: integration branch = default branch (
mainormaster)
- If
-
Epic branch:
- Named:
feature/issue-{N}-epic-{short-name} - Created from: integration branch
- Purpose: collects all phase PRs before final merge to integration
- Named:
-
Phase branches:
- Named:
feature/issue-{N}-phase{X}-{short-name} - Created from: epic branch
- Merged to: epic branch (squash merge)
- Named:
-
Single-phase shortcut:
- If only one phase, skip the epic branch layer
- Create feature branch directly from integration branch
- Merge directly to integration branch
State File Format
Persistent state stored in .claude/epic.local.md (gitignored via .claude/*.local.md):
yaml--- epic_issue: 132 epic_title: "Feature: Community Dashboard" integration_branch: develop epic_branch: feature/issue-132-epic-dashboard worktree_base: "../epic-dashboard" phases: - number: 1 title: "Backend metrics collection" issue: 133 branch: "feature/issue-133-phase1-metrics" status: complete # pending | in_progress | complete pr: 135 - number: 2 title: "Dashboard frontend" issue: 134 branch: "feature/issue-134-phase2-frontend" status: pending pr: null current_phase: 2 created_at: "2026-02-02T12:00:00Z" --- ## Notes Running notes about the epic, decisions made, blockers encountered.
Status transitions: pending -> in_progress -> complete
Git Worktree Operations
All worktree paths use absolute paths (Bash calls do not persist cd).
Create epic worktree:
bashREPO_ROOT=$(git rev-parse --show-toplevel) PARENT=$(dirname "$REPO_ROOT") git worktree add "$PARENT/epic-{short-name}" -b feature/issue-{N}-epic-{short-name} {integration_branch}
Create phase worktree from epic branch:
bashgit worktree add "$PARENT/{short-name}-phase{X}" -b feature/issue-{N}-phase{X}-{short-name} feature/issue-{EPIC}-epic-{epic-name}
Clean up worktree after merge:
bashgit worktree remove "$PARENT/{worktree-name}" git branch -d feature/issue-{N}-phase{X}-{short-name}
Handle existing worktree: Before creating, check:
bashgit worktree list | grep -q "{branch-name}" && echo "EXISTS" || echo "NEW"
GitHub Operations
Semantic line breaks remain the default for prose source. Text posted to GitHub (issue and pull-request bodies, comments, reviews, and discussions) is the exception: keep each paragraph and list item on one source line, separate paragraphs with blank lines, and do not insert sentence- or clause-level newlines inside a paragraph.
Create epic issue:
bashgh issue create --title "Epic: {description}" --label "feature" --body "{body with phase breakdown}"
Create phase sub-issue and link:
bashPHASE_ISSUE=$(gh issue create --title "Phase {X}: {title}" --label "feature" --body "Part of #{epic_issue}" | grep -o '[0-9]*$') gh sub-issue add {epic_issue} --sub-issue-number $PHASE_ISSUE
Create PR to epic branch:
bashgh pr create --base {epic_branch} --title "Phase {X}: {title}" --body "Closes #{phase_issue}\n\nPart of epic #{epic_issue}"
Squash merge (phase PRs into the epic branch only):
bashgh pr merge --squash --delete-branch
Merge-strategy rule: phase PRs squash-merge into the epic branch to keep it
readable; the FINAL epic-to-integration merge uses a regular merge
(gh pr merge --merge) to preserve history, unless the user directs
otherwise. When a local convention conflicts with the user's standing merge
preference, surface the conflict once, before the first merge runs, not
after several.
Create final PR (epic to integration):
bashgh pr create --base {integration_branch} --title "{epic_title}" --body "Closes #{epic_issue}\n\n## Phases completed\n{list}"
Confirmation Points
Confirm (pause and ask):
- Epic plan: before creating issues and branches, present the full plan
- Implementation plan: after plan mode (EnterPlanMode) produces the plan, wait for approval
- Unfixable Critical finding: an accepted Critical finding that cannot be fixed within the phase
- Final epic merge: before merging epic branch to integration
Auto-proceed (no confirmation):
- Repository detection
- Branch and worktree creation (after plan confirmed)
- Issue and sub-issue creation (after plan confirmed)
- State file updates
- Running tests
- Review fixes, the delta review, and phase merges (per
pr-review-toolkitreview-convergence.mdreference) - Recovery from CI failures, conflicts, and silent agents (per
engineering-loopunblock-rules.mdreference) - Worktree cleanup after merge
- PR creation
Variation Handling
No develop branch
Auto-detected. Use main (or master) as integration branch. All other workflow steps are identical.
Single-phase feature
When the user describes only one phase or says "just one phase":
- Skip epic worktree creation
- Create feature branch directly from integration branch:
feature/issue-{N}-{short-name} - Create single issue (no sub-issues needed)
- PR targets integration branch directly
Resume interrupted epic
When invoked with --resume:
- Read
.claude/epic.local.md - Find the first phase with status !=
complete - Check if its worktree exists; if so, switch to it
- If worktree does not exist, create it
- Continue from where the phase left off
Next phase
When invoked with --next-phase:
- Read state, find next
pendingphase - Mark it
in_progress, create worktree, begin execution
Finalize
When invoked with --finalize:
- Skip to Phase 3 (final PR from epic branch to integration)
Integration with Other Skills/Commands
- EnterPlanMode: Invoke at the start of each phase for implementation planning (Codex and Copilot: write the plan before editing)
project:pr-review-toolkit: Invoke before merging each phase PR and the final epic PR; itsreview-convergence.mdreference caps review at two roundsproject:engineering-loop: Optionally follow within a phase for the single-PR change workflow (user decides)- TodoWrite: Track all phases and steps throughout
Naming Conventions
Keep names short and lowercase with hyphens:
- Epic:
epic-{2-3 word slug}(e.g.,epic-dashboard-metrics) - Phase:
phase{N}-{2-3 word slug}(e.g.,phase1-backend-metrics) - Worktree dirs: same as branch slug without
feature/issue-N-prefix


