# Epic Ship

> Execute a multi-phase epic end to end - one worktree and PR per phase, verified before merge, merged and cleaned up immediately, moving straight to the next phase without stalling for a prompt. Use when asked to run, ship, drive, or execute an epic (a phased plan doc), or "ship the epic", "run phase M", "continue the epic". For a single change use ship-pr; for independent parallel PRs use parallel-ship.

- Skill: `davidtheproduct/epic-ship` (Agent Skill)
- Install (CLI): `npx skillmds@latest add davidtheproduct/epic-ship`
- Raw SKILL.md: https://api.skillmd.com/api/skills/davidtheproduct/epic-ship/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: davidtheproduct (https://skillmd.com/u/davidtheproduct)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/davidtheproduct/epic-ship

---


# Epic Ship

Runs a multi-phase epic (a markdown plan doc with a phase list, e.g. `docs/epics/epic-<n>.md`) phase by phase, calling the `ship-pr` skill once per phase for the actual worktree/implement/verify/PR/merge/cleanup mechanics, until every phase is shipped or you hit an explicit review checkpoint. This is the sequential composition operator of the ship stack: `parallel-ship` fans out when changes are independent; this skill loops when phase N+1 builds on phase N's code.

The default failure mode this skill exists to fix is **stalling after a routine merge waiting to be told to continue**. `ship-pr` ships one PR and stops - epic-ship is what decides to call it again immediately.

## Step 0: Reconcile against reality first

Before touching anything:

1. `git status` and `git branch --show-current` at the repo root - confirm it's on the default branch and clean. If not clean and the changes aren't yours, stop and tell the user.
2. `git worktree list` - confirm no stray worktree already covers this epic's phases.
3. Read the epic doc fully: phase list, current status column, and any explicit checkpoint markers (see Step 3).
4. `gh pr list --search "<epic keyword>" --state all` and `git log --oneline -20` - confirm what's _actually_ already merged before trusting the epic doc's status table. Epic docs drift; git and GitHub are the source of truth. This step exists because past sessions have reported phases as unshipped when they'd already landed, or vice versa - always reconcile before planning work.

## Step 1: Plan the run

List the unshipped phases in order. For each, note what it touches (which packages/apps - and which specialized subagent fits, if the project defines any) and whether it's DB/migration work (regenerate types afterward if the project has a typegen step).

### Then re-order for risk, not just dependency

Epic docs number phases in dependency order (DB -> backend -> frontend). That is not always a safe **merge** order. Before shipping anything, ask of each phase:

> Does this phase widen what the server permits or creates, while the code that handles the new case safely is still unmerged?

If yes, **ship the guard phase first** (it is inert until the permission exists), or merge both back to back. Never merge and deploy the permission first.

Example: an epic adds restricted sub-accounts. Phase 2 lets the backend create them; phase 3 teaches the frontend to recognize them and hide the surfaces they shouldn't see. Merge and deploy phase 2 first, and every production build until phase 3 lands shows those accounts everything the epic existed to hide. The logic of both phases is right; only the merge order is wrong - and the epic doc's dependency numbering told you to do it.

Concretely, when a phase is permission-widening and its guard is a later phase:

- Reorder so the guard merges first, **or**
- Hold the permission phase on its branch until the guard is merged, **or**
- If dependency genuinely forces the original order, merge the permission but do **not** deploy it until the guard lands.

Say which of these you picked in the Step 4 status board, so the choice is visible.

## Step 2: Per-phase loop

For each phase, in order, until you hit a checkpoint (Step 3) or run out of phases, invoke the `ship-pr` skill for that phase's change, with two epic-specific overrides on top of its normal behavior:

- **Branch/worktree name**: `<prefix>/epic-<n>-phase-<m>-<slug>` (`ship-pr`'s own branch-type table still decides the prefix) instead of a plain slug, so phases from the same epic are identifiable in `git worktree list` and `gh pr list`.
- **PR body**: reference the epic doc and phase number, not just the change on its own.

`ship-pr` owns the mechanics: worktree, implement (delegate to a matching specialized subagent if the project defines them, rather than doing everything inline), verify (including any phase-specific verification query named in the epic doc - **run it live**, against real data, don't just document it), ship, and the CI-check-before-merge decision.

Once `ship-pr` merges and cleans up the worktree:

1. Update the epic doc's phase status table, in the same PR or a fast-follow docs commit.
2. If this phase is **not** a checkpoint (Step 3): **invoke `ship-pr` for the next phase immediately, without waiting for a prompt.**
3. If it **is** a checkpoint: stop here, don't start the next phase.

## Step 3: What counts as a checkpoint

Treat a phase as a hard stop - report status and wait for the user - when the epic doc marks it explicitly (e.g. "STOP", "review", "awaiting go-ahead", "manual deploy") OR when it involves any of:

- A manual production step with no CLI path (e.g. a dashboard-only config change, a production deploy the user runs by hand)
- A schema change with no rollback path already tested
- Anything touching billing/payment webhooks, auth/SSO, or row-level-security policies on tables with existing user data
- The epic doc doesn't say and you're genuinely unsure whether it's reversible
- The phase PR's CI came back red for a reason `ship-pr`'s own verification didn't already predict (a genuine unknown, not a known quirk `ship-pr` already stops on)

Everything else: merge and keep going.

## Step 4: Status board

After finishing all remaining phases, or on hitting a checkpoint, report a table: `Phase | PR # | Status (merged / awaiting review / blocked) | Note`. Keep it to one screen - this is a status report, not a retrospective.

## Hard rules

- Never push directly to the default branch. Every phase is its own PR.
- Every phase's worktree forks fresh from the remote default branch via `ship-pr`'s `worktree-new.sh` - never stack one phase's branch on another unmerged phase's branch, even though they're part of the same epic. When phase N+1's worktree is created, phase N must already be merged, or phase N+1 will conflict when phase N lands.
- Close each worktree immediately after its PR merges (`worktree-close.sh`) - don't batch cleanup to the end of the epic.
- One epic = many PRs (one per phase), not one giant PR. Epic-scale work is the exception to any general "bundle into one PR" preference.

## See also

- `ship-pr` - the atomic single-PR mechanics this skill calls once per phase; invoke it directly for anything that isn't a multi-phase epic
- `parallel-ship` - the parallel counterpart: fan out independent PRs from one analysis pass

