Skill

create-pr

Install
1
Install the plugin
$
npx claudepluginhub sd0xdev/sd0x-dev-flow --plugin sd0x-dev-flow

Want just this skill?

Add to a custom plugin, then install with one command.

Description

Create or update GitHub PR with gh CLI. Auto-extracts ticket ID from branch name, generates title/summary from commits. Auto-detects existing PR and switches to update mode. Default: --dry-run (show command, don't execute). Use when: user asks to open/create/update a PR, says /create-pr, wants to refresh PR description after new commits, or says 'update pr', 'update PR title', 'refresh PR body'.

Tool Access

This skill is limited to using the following tools:

Bash(git:*)Bash(gh:*)ReadGrepGlob
Skill Content

Create PR

Input

/create-pr [--head <branch>] [--base <branch>] [--title <title>] [--update] [--execute] [--dry-run]

  • --head: Source branch (default: current branch)
  • --base: Target branch (default: {TARGET_BRANCH} or main)
  • --title: Override auto-generated title
  • --update: Force update mode (re-generate title/body for existing PR)
  • --dry-run: Show command without executing (default)
  • --execute: Actually create/update the PR (requires user confirmation)
  • No args: use current branch → default target, dry-run mode. Auto-detects existing PR → update mode

Workflow

1. Gather Info (parallel)

# Current branch
git rev-parse --abbrev-ref HEAD

# Remote repo (owner/repo)
gh repo view --json nameWithOwner --jq '.nameWithOwner'

# Check if head branch is pushed
git ls-remote --heads origin <head-branch>

# Check existing PR
gh pr list --head <head-branch> --base <base-branch> --json number,title,state

# Commits between base..head
git log --oneline <base>..<head>

# Full diff for summary
git diff <base>...<head> --stat

2. Extract Ticket ID

From branch name, extract ticket ID using {TICKET_PATTERN} (default: [A-Z]+-\d+):

Branch PatternTicket ID
fix/PROJ-520PROJ-520
fix/PROJ-520-2PROJ-520
feat/PROJ-123-some-descPROJ-123
refactor/PROJ-999PROJ-999

Regex: first match of {TICKET_PATTERN} — take first match. Strip trailing -N suffixes.

3. Generate Title

Format: <type>: [<TICKET>] <concise summary>

  • <type>: from branch prefix (fix/fix, feat/feat, docs/docs, refactor/refactor)
  • <TICKET>: extracted ticket ID (omit if none found)
  • <concise summary>: summarize commits in <60 chars, focus on main changes

4. Generate Body

## Summary

<3-5 bullet points summarizing changes from commits>

## Ticket

[<TICKET>]({ISSUE_TRACKER_URL}<TICKET>)

## Test plan

- [ ] <test items based on what changed>

Rules:

  • No AI-generated tags (no "Generated with Claude" etc.)
  • Keep summary factual, based on actual commits
  • Use imperative mood in bullet points
  • Omit Ticket section if no ticket ID or {ISSUE_TRACKER_URL} not configured

5. Pre-flight Checks + Mode Detection

CheckAction if fails
Head branch not pushedWarn: "branch not pushed to remote, push first" and STOP
PR already existsEnter Update Mode (see section below)
--update flag + no existing PRWarn: "no PR found for this branch" and STOP
No commits between base..head (create mode)Warn: "no diff between branches" and STOP
No commits between base..head (update mode)Continue — PR may need title/body refresh from --title override

Mode detection logic:

ConditionMode
--update flag passedForce update mode (error if no PR exists)
Existing PR detected (auto)Update mode (auto-switch)
No existing PR, no --updateCreate mode (original workflow)

5a. Update Mode

When an existing PR is detected (or --update is passed):

Step 1: Fetch current PR state (use PR number from pre-flight gh pr list result):

gh pr view <PR-number> --json number,title,body,url,baseRefName

Step 2: Re-generate title and body from latest commits (same logic as Steps 2-4 above, using full commit range base..head).

Step 3: Smart diff — compare current vs newly generated:

FieldCurrentNewAction
TitlesamesameSkip (no change needed)
TitlediffersdiffersShow before/after
BodysamesameSkip
BodydiffersdiffersShow before/after

Step 4: Decision — if both title and body are unchanged → report "PR is already up to date" and STOP.

If changes detected, show the diff and decide what to update:

  • Title changed significantly: update title automatically. Criteria: type prefix changed (fix:feat:) or ticket ID changed.
  • Title changed trivially: AskUserQuestion — "Title changed slightly. Update?" (show before/after). Criteria: only the summary text after <type>: [<TICKET>] differs.
  • Body changed: always update (body reflects commit history, should stay current)
  • When --title is passed: override title regardless of diff

Step 5: Output (respects --dry-run / --execute):

Dry-run (default) — show the gh pr edit command with only changed fields included:

# Title-only update (use printf for safe escaping):
gh pr edit <number> --title "$(printf '%s' '<new-title>')"

# Body-only update (use --body-file for safe escaping):
gh pr edit <number> --body-file /dev/stdin <<'EOF'
<new-body>
EOF

# Both title + body:
gh pr edit <number> --title "$(printf '%s' '<new-title>')" --body-file /dev/stdin <<'EOF'
<new-body>
EOF

Use --body-file instead of --body to avoid shell escaping issues with quotes and newlines in the body content.

Execute (--execute) — ask user for confirmation via AskUserQuestion, then run gh pr edit. Output:

PR updated: <URL>
Title: <old-title> → <new-title>
Changes: title updated, body updated

6. Output (dry-run, default) — Create Mode

Show the full gh pr create command:

gh pr create \
  --head <head-branch> \
  --base <base-branch> \
  --title "<title>" \
  --body "$(cat <<'EOF'
<generated body>
EOF
)"

User can copy-paste to execute, or re-run with --execute.

7. Execute (--execute flag)

Ask user for confirmation, then run the command. Output:

PR created: <URL>
Title: <title>
Base: <base> ← Head: <head>

Multi-PR Mode

When user specifies multiple branch pairs (e.g. "A → main, B → A"), create them sequentially and output all URLs at the end.

Edge Cases

CaseBehavior
No ticket ID in branch nameOmit [TICKET] from title, omit Ticket section from body
Branch suffix like -2, -3Strip suffix when extracting ticket ID
User provides --titleUse as-is, skip auto-generation
Stacked PRs (B → A → main)Note dependency in body: "Stacked on #<PR-number>"
--update but no existing PRError: "No PR found for branch <head><base>"
Auto-detect existing PRSwitch to update mode, show "Existing PR #N detected, switching to update mode"
PR body has manual editsRe-generate from commits; user reviews before/after diff
Title unchanged after new commitsSkip title update, only update body

Verification

Create mode

  • Branch exists and is pushed to remote
  • No existing PR for the same head/base
  • Title follows project convention
  • Body includes summary and test plan
  • Dry-run command is valid (copy-pasteable)

Update mode

  • Existing PR fetched successfully (gh pr view)
  • New title/body generated from latest commits
  • Before/after diff shown to user
  • Only changed fields included in gh pr edit command
  • Dry-run command is valid (copy-pasteable)
Stats
Stars90
Forks12
Last CommitMar 17, 2026
Actions

Similar Skills