| name | pr |
| description | Create/update PRs with Conventional Commits title, issue linking & guard rails. Triggers: "create PR" | "open PR" | "submit PR" | "update PR" | "/pr --draft" | "open a pull request" | "make a PR" | "open pull request" | "submit a pull request" | "create a draft PR" | "raise a PR". |
Pull Request
Success
I := PR created ∧ pushed ∧ rebased on base
V := gh pr view {N} ∧ git log origin/${BASE}..HEAD non-empty
Let:
β := staging (∃ origin/staging) ∨ main
Β := current branch
N := issue# (first number after / in Β)
Β → PR: Conventional Commits title, issue linking, guard rails.
Flow: single continuous pipeline. ¬stop between steps. Stop only on: REFUSE, explicit Cancel, or Step 6 completion.
Pipeline
| Step | ID | Required | Verifies via | Notes |
|---|
| 1 | gather-state | ✓ | state JSON emitted | — |
| 2 | guard-rails | ✓ | ¬REFUSE | — |
| 3 | generate | ✓ | title + body ready | — |
| 4 | create | ✓ | gh pr create success | — |
| 5 | rebase | ✓ | git push success | — |
| 6 | watch | — | — | inform only |
Pre-flight
Success: PR created ∧ pushed ∧ rebased on base
Evidence: gh pr view {N} returns valid PR
Steps: gather-state → guard-rails → generate → create → rebase
¬clear → STOP + ask: "Which branch are you PR-ing from?"
Step 1 — Gather State
bash ${CLAUDE_SKILL_DIR}/gather-state.sh
Emits: branch, base, commit log, diff stat, existing PR, issue number, lifecycle artifacts (analysis, spec), test file count.
Step 2 — Guard Rails
| Check | Condition | Action |
|---|
| Protected branch | Β ∈ {staging, main, master} | REFUSE. Create feature branch first. Stop. |
| No commits | git log origin/${β}..HEAD empty | REFUSE. Nothing to PR. Stop. |
| PR exists | gh pr list → result | → present choice Update (gh pr edit) | Cancel |
| Branch not pushed | git ls-remote --heads origin $BRANCH empty | git push -u origin $BRANCH |
| Quality gates | {commands.lint} && {commands.typecheck} | Warn on failure, ¬block. Note in PR body if proceeding. |
(Note: "behind base" is no longer a guard rail — Step 5 rebases post-create automatically.)
Step 3 — Generate Content
3a. Commits + diff:
git log origin/${BASE}..HEAD --format="%h %s%n%b"
git diff origin/${BASE}...HEAD --stat
3b. Lifecycle artifacts: already emitted by Step 1 (issue, analysis, spec, issue_data, test_files).
N detection: first number after / in Β (e.g. feat/42-slug → #42). ¬found → ask user "Which issue number does this PR close, if any?"
3c. Title: <type>(<scope>): <desc> (≤70 chars). Type from primary commit purpose. Scope from files: web | api | ui | config ∨ omit if cross-cutting.
3d. Body: template below.
Step 4 — Create + Update Issue
Show generated title + body → create immediately (¬ask how). --draft → draft.
Failure ∨ explicit edit request → present choice Edit title/body | Cancel
gh pr create --title "<title>" --body "<body>" --base ${BASE} [--draft]
Display PR URL.
Updating existing PR → gh pr edit <number> --title "<title>" --body "<body>".
Step 5 — Rebase on Base (post-create)
After PR creation, rebase Β on latest β → force-push with lease → PR updates with current base.
git fetch origin ${BASE}
BEHIND=$(git rev-list HEAD..origin/${BASE} --count)
BEHIND == 0 → skip rebase, skip push. Log: "Already up to date with origin/${BASE}."
BEHIND > 0:
git rebase origin/${BASE}
git push --force-with-lease origin ${BRANCH}
Safety: only --force-with-lease (not --force) — refuses push if remote moved unexpectedly. Only on the feature branch (Β ∉ {staging, main, master} is already enforced in Step 2).
Why post-create: ensures the PR reflects the latest base from the moment it lands, so reviewers see a minimal diff and CI runs against current base. Staging can move between branch creation and PR create — this step closes that gap.
Step 6 — Watch CI
Inform: "CI is running on the PR — use /ci-watch to monitor it live."
Merge path = gate-driven: reviewed label + auto-merge (gh pr merge --auto --merge). ¬manual gh pr merge while any check is IN_PROGRESS/QUEUED — the gate decides, not the operator.
PR Body Template
## Summary
- {what changed and why}
- {secondary change if applicable}
## Lifecycle
| Phase | Artifact | Status |
|-------|----------|--------|
| Intent | #{N}: {title} | {state} |
| Analysis | [{filename}](artifacts/analyses/{filename}) | Present/Absent |
| Spec | [{filename}](artifacts/specs/{filename}) | Present/Absent |
| Implementation | {N} commits on `{branch}` | Complete |
| Verification | Lint {✅/❌} Typecheck {✅/❌} Tests {✅/❌} ({N} new) | Passed/Failed |
## Test Plan
- [ ] {how to verify}
- [ ] {edge case}
## SC → Test Matrix
(Insert the fenced SC→Test Matrix block emitted by `/implement` Step 6a — a chained run carries it in conversation context; for a standalone `/pr`, retrieve it from the implement summary or reconstruct from the spec SCs + landed tests. Tier S: omit this section entirely — see the Lifecycle note below.)
| SC | Test(s) | Status |
|----|---------|--------|
| SC1: {text} | `{file} :: {test name}` | ⏳ not run |
Fixes #{N}
---
Generated with [Claude Code](https://claude.com/claude-code) via `/pr`
Lifecycle notes: S-tier → Intent + Implementation + Verification only. ¬issue → omit Lifecycle + Closes. S-tier → also omit SC → Test Matrix section.
Options
| Flag | Description |
|---|
| (none) | Target auto-detected base branch |
--draft | Create as draft |
--base <branch> | Override base branch |
Edge Cases
| Scenario | Behavior |
|---|
| Β ∈ {staging, main, master} | REFUSE: "Create a feature branch first" |
| ¬commits ahead | REFUSE: "Nothing to create a PR for" |
| PR already exists | Offer gh pr edit to update |
| ¬N in branch | → ask user link issue or skip |
| Multiple commit types | Use primary type only |
| Lint/typecheck fail | Warn + present choice: Proceed anyway | Fix first |
Safety Rules
- ¬PR from
staging, main, master
- ¬
git push --force — only --force-with-lease, and only during Step 5 rebase on feature branches
- Always show PR content before creation
- → present choice for all decisions (proceed despite warnings, edit)
- Always display PR URL after creation
- Rebase conflicts → abort + defer to user — ¬auto-resolve
- ¬manual
gh pr merge while any check is IN_PROGRESS/QUEUED — manual merge mid-CI cancels in-flight runs (concurrency.cancel-in-progress) and skips gates. Nominal path: reviewed label → auto-merge (--merge) on green.
Chain Position
- Phase: Build
- Predecessor:
/implement (worktree with commits)
- Successor:
/ci-watch
- Class: adv (continuous flow, no gate)
Task Integration
/dev owns the dev-pipeline task lifecycle externally
- This skill does NOT update its own dev-pipeline task
- Sub-tasks created: none
Exit
- Success via
/dev: PR created + rebased + pushed → return control silently. ¬write summary. ¬ask user. ¬announce /ci-watch. /dev re-scans and advances.
- Success standalone: print PR URL +
Next: /ci-watch --pr {PR#}. Stop.
- Failure (REFUSE, rebase conflict, gh error): return error.
/dev presents Retry | Skip | Abort.
$ARGUMENTS