Pr Ship
Autonomously iterate on a PR — local CI, code review, remote CI, review comments, merge conflicts — until ready to merge
---
description: Autonomously iterate on a PR — local CI, code review, remote CI, review comments, merge conflicts — until ready to merge
prompt: |
# PR Ship Loop — Make It Ready to Merge
Drive PR `${1:-$(gh pr list --head $(git branch --show-current) --json number --jq '.[0].number')}` to a mergeable state by iterating through five ordered gates until all are green.
## State File
All progress is tracked in `/tmp/pr-ship-${REPO_SLUG}-${BRANCH_SLUG}-${PR}.md`. Read it at the start of every iteration to understand what's already done. Update it after every action. This is your working memory across ScheduleWakeup wakeups.
**State file format** (initialize if missing):
```markdown
# PR Ship State — PR #N
Iteration: 0
Branch: <branch>
Base: <base-branch>
## Changed Files
(populated once from `gh pr diff "$PR" --name-only`)
- path/to/file.go
## Gate Status
- [ ] Gate 1a: Local compile
- [ ] Gate 1b: Local tests (changed packages only)
- [ ] Gate 2: Code review clean
- [ ] Gate 3: PR review comments addressed
- [ ] Gate 4: Remote CI green
- [ ] Gate 5: No merge conflicts
## Push History
(append after each push: `- COMMIT_SHA pushed at ITERATION N`)
## Code Review Issues
### Open
(populated after Gate 2 runs; format: `- [ ] FILE:LINE — DESCRIPTION [severity]`)
### Resolved
(moved here when fixed; format: `- [x] FILE:LINE — DESCRIPTION [fixed in COMMIT]`)
## Decision Log
(one line per iteration: what gate advanced, what was done, commits made)
Entry Check
PR="${1:-$(gh pr list --head $(git branch --show-current) --json number --jq '.[0].number')}"
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' | tr '/' '-')
BRANCH=$(gh pr view "$PR" --json headRefName --jq '.headRefName' | tr '/' '-' | tr '_' '-' | cut -c1-40)
STATE="/tmp/pr-ship-${REPO}-${BRANCH}-${PR}.md"
gh pr view "$PR" --json number,title,state,mergeable,mergeStateStatus,headRefName,baseRefName
If the PR is already merged or closed, report that and stop.
Read the state file. If it doesn't exist, initialize it. Populate Changed Files once using:
gh pr diff "$PR" --name-only
Never re-derive the changed files list from scratch — use what's in the state file.
Context Discipline — Orchestrator Only
This skill is an orchestrator, not a worker. Delegate all file editing, compiling, and committing to fresh subagents. Never accumulate file contents or diffs in this context — only gate status and state file updates. This is the lean-agent-loop skill pattern: the state file is the coordinator's memory, each fresh subagent is a Ralph Wiggum agent, and the five gates are the loop condition.
Orchestrator (this context)
└─ reads state file, checks gate, collects failure details
└─ spawns Agent(prompt="Fix these specific failures: ...") → waits for result
└─ fresh agent does all file reading, editing, testing, committing, pushing
After each agent returns: verify the fix locally (run the relevant check command), update the state file, append to Decision Log, then advance to the next gate.
The Loop (max 10 iterations; stop if no gate advances)
At the top of each iteration, increment Iteration: in the state file. Read Gate Status. Skip gates already marked [x]. Process gates in order — do not jump ahead.
Gate 1a — Local Compile
Only run if [ ]. Detect stack from repo contents, then compile:
| Stack | Compile check |
|---|---|
| Java/Maven | ./mvnw compile -q |
| Kotlin/KMP | ./gradlew compileTestKotlinJvm --no-daemon |
| Go | go build ./... |
| TypeScript | npx tsc --noEmit |
| JS | npm run build |
If it fails: delegate to a fresh agent with the exact error and the repo path. After agent returns, re-run the same compile command to verify — do not mark [x] until you confirm it passes. Update state file.
Gate 1b — Local Tests (changed packages only)
Only run if [ ] and Gate 1a is [x]. Scope tests to only the packages/modules containing changed files:
| Stack | Scoped test command |
|---|---|
| Go | `go test $(git diff --name-only origin/ |
| Java/Maven | ./mvnw test -pl $(changed modules) -q |
| TypeScript | npm test -- --testPathPattern="<changed files>" |
| Kotlin/KMP | ./gradlew jvmTest --no-daemon |
If a scoped command is too complex to derive, fall back to the full test suite. If it fails: delegate to a fresh agent with failing test output. After agent returns, re-run the failing tests to verify — not the full suite, just the specific failing ones. Mark [x] only after the re-run passes.
Gate 2 — Code Review (changed files only)
Only run if [ ] and Gates 1a+1b are [x].
Invoke the code review skill on the current diff (it naturally scopes to changed files):
/code:review --fix
Parse the findings. Write all BLOCKER and CRITICAL issues to ## Code Review Issues → Open in the state file. Write MAJOR issues too. Suggestions/NITs are optional — log them but don't block.
Delegate a fresh agent to fix all BLOCKER/CRITICAL/MAJOR issues. Include in the agent prompt:
- The state file path
- Each open issue with file, line, severity, description
- Instruction to commit (but NOT push — Gate 3 handles the push decision)
After the agent returns:
- Re-run
/code:reviewto verify no new BLOCKER/CRITICAL issues - Move fixed issues to
Resolvedin the state file with the commit SHA - Repeat until no BLOCKER/CRITICAL/MAJOR issues remain
- Mark
[x]in state file
Gate 3 — PR Review Comments
Only run if [ ] and Gates 1a+1b+2 are [x]. Address all reviewer feedback before pushing so CI runs on code reviewers have already seen and haven't flagged.
Maintain Pr Ship?
Let people know it's listed here — add the badge (live metrics, light/dark aware) or a plain link to your README or docs.
[Pr Ship on getagentictools](https://getagentictools.com/loops/tstapler-pr-ship?ref=badge)