| name | open-pr |
| description | Ship the current branch — open a PR, wait for CI, squash-merge into main, and move the Linear issue to Done. Invoked via `/open-pr` (no args; always operates on the current branch). Picks up where `/checkout` left off. Assumes local validation is already done; pairs with CLAUDE.md (Karpathy + hard rules apply). |
/open-pr — push, PR, CI, squash-merge, close Linear
You've been handed a fully-implemented and locally-validated branch. Your job: ship it.
Operates on the current branch only. No arguments. Derive the Linear ID from the branch slug (e.g. feat/pf-12-... → PF-12).
Step 1 — Sanity-check the branch
Before opening anything:
Step 2 — Push and open the PR
Push with upstream tracking, then gh pr create:
- PR title: short imperative, <70 chars.
- PR body: HEREDOC, includes
Closes PF-<n> (or Refs PF-<n> if the PR doesn't fully resolve the issue) so traceability holds even though Linear won't auto-transition.
- Summarize what changed and any reviewer-visible test plan. Don't restate the Linear description verbatim.
gh pr create --title "<title>" --body "$(cat <<'EOF'
## Summary
- ...
## Test plan
- [ ] ...
Closes PF-<n>
EOF
)"
Immediately after the PR is created, move the Linear issue to In Review via mcp__linear-server__save_issue with state: "In Review". (Exact name — case-sensitive.)
Step 3 — Wait for CI
Use Bash + run_in_background (not Monitor). Backgrounded poll loop, one completion notification with the final state. gh pr checks encodes the state in its exit code (0 pass / 1 fail / 8 pending), so we branch on $?, not on parsed output.
set -u
PR=<n>
INTERVAL=30
DEADLINE=$(( $(date +%s) + 25 * 60 ))
while :; do
raw=$(gh pr checks "$PR" 2>&1); rc=$?
case "$rc" in
0) echo "PR #$PR checks complete (all pass):"; awk -F'\t' '{ printf " %s %s\n", $2, $1 }' <<<"$raw"; exit 0 ;;
1) echo "PR #$PR checks complete (failures):"; awk -F'\t' '{ printf " %s %s\n", $2, $1 }' <<<"$raw"; exit 1 ;;
8) ;;
*) echo "gh failed (exit $rc): $raw"; exit 2 ;;
esac
if [ "$(date +%s)" -ge "$DEADLINE" ]; then
echo "timed out after 25m, last state:"
awk -F'\t' '{ printf " %s %s\n", $2, $1 }' <<<"$raw"
exit 3
fi
sleep "$INTERVAL"
done
Run via Bash with run_in_background: true and a generous timeout. Exit non-zero on failure/timeout so the completion notification reads as a problem. While CI runs, don't idle — review the diff one more time, address any obvious self-review nits in a follow-up commit, or update memory.
If CI fails: read the failing logs (gh run view --log-failed), fix in a new commit (never --amend, never --no-verify), push, and re-enter the wait loop.
Step 4 — Squash-merge
Once CI is green, stop and ask the user before merging. Never squash without explicit confirmation — the user may want to self-review, wait for a reviewer, or hold the merge for timing reasons. Surface the PR URL and the green check summary, then wait.
Once the user confirms:
gh pr merge <n> --squash --delete-branch
Then locally:
git checkout main
git pull --ff-only
Step 5 — Move Linear issue to Done
Linear does not auto-transition on merge in this workspace. Always follow up:
mcp__linear-server__save_issue with state: "Done" for the issue referenced by the branch slug.
- Resolve any open review threads via GraphQL if the user left comments that you addressed.
Then stop. Do not auto-chain into /checkout.
Anti-patterns
- Squash-merging without asking the user — CI green is necessary, not sufficient. Always confirm.
- Skipping the CI wait and merging on a yellow/red state.
- Forgetting to move the issue to "In Review" after opening the PR.
--amend-ing or force-pushing to fix a CI failure — push a new commit.
--no-verify to bypass hooks.
- Merging without moving the Linear issue to Done.
- Force-pushing to
main (never).
- Auto-chaining into the next
/checkout.