# Pr Create

> Use this skill whenever the user wants to create, open, or raise a new GitHub pull request from the current branch — including phrasings like "open a PR", "raise a PR", "make a PR", "ship this". Drafts a Conventional Commits title and a Summary body that explains *why* and *what*, respects `.github/pull_request_template.md` when present, auto-links referenced issues, waits for approval, then pushes and opens the PR. Assumes commits already exist. Requires `gh` CLI.

- Skill: `robdefeo/pr-create` (Agent Skill)
- Install (CLI): `npx skillmds add robdefeo/pr-create`
- Raw SKILL.md: https://api.skillmd.com/api/skills/robdefeo/pr-create/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: robdefeo (https://skillmd.com/u/robdefeo)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/robdefeo/pr-create

---


# PR Create

## Hard rules

These override anything else. No exceptions without an explicit user instruction.

- **Never append Claude attribution trailers.** No `🤖 Generated with Claude Code`, no `Co-Authored-By: Claude …`, no "Generated by" footers. The PR title and body contain nothing that identifies the author as an AI.
- **Never force-push unless the user explicitly asks this turn** — and only `--force-with-lease`, never plain `--force`. Confirm the head branch is not `main` / `master` before the push.
- **Never open a PR from `main` / `master`.** Stop and surface to the user.
- **Never auto-rebase or auto-merge the base branch.** If the branch is behind, surface it and ask.
- **Never fill a checklist item you haven't verified.** Leave `[ ]` unchecked; don't tick boxes on the user's behalf.
- **Never open a PR that contains secrets.** If the diff touches `.env*`, `*credentials*`, `*.pem`, `*.key`, or `id_rsa*`, stop and surface to the user — even if the user asked you to proceed. Public PRs cache forever.

---

## Workflow

1. **Preflight** — validate branch state, remote state, and `gh` auth.
2. **Gather context** — commits, diff, branch name, referenced issues, existing PR template.
3. **Draft title and body** — Conventional Commits title + Summary covering *why* and *what*.
4. **Propose for approval** — show the draft; wait for edits or OK.
5. **Push and create** — push the branch, open the PR, return the URL.

---

## Step 1 — Preflight

Run these in parallel and stop if any check fails:

```bash
gh auth status
git rev-parse --abbrev-ref HEAD
git status --porcelain
BRANCH=$(git rev-parse --abbrev-ref HEAD)
gh pr list --head "$BRANCH" --state open --json url,number
```

Fail-stop conditions:

| Check | Condition | Action |
|---|---|---|
| Current branch | `main` or `master` | Stop. Tell the user to switch to a feature branch. |
| `gh auth status` | not authenticated | Stop. Tell the user to run `gh auth login`. |
| Existing PR | a PR already exists for this branch | Stop. Return the existing URL — don't open a duplicate. |
| Uncommitted changes | `git status --porcelain` is non-empty | Surface to the user. This skill is PR-only; don't auto-commit. |

Determine the base branch (usually `main`, sometimes `master` or `develop`):

```bash
gh repo view --json defaultBranchRef --jq .defaultBranchRef.name
```

Check the branch is up to date with the base. Fetch first so the comparison is accurate:

```bash
git fetch origin
BASE=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name)
BEHIND=$(git rev-list --count HEAD..origin/$BASE)
```

If `BEHIND > 0`, surface it: *"Your branch is N commits behind `origin/$BASE`. Rebase or merge before opening the PR?"* — **do not auto-rebase**.

---

## Step 2 — Gather context

Collect the material needed to write the title and body:

```bash
BASE=$(gh repo view --json defaultBranchRef --jq .defaultBranchRef.name)
git log --reverse --pretty=format:'%h %s%n%b%n---' origin/$BASE..HEAD
git diff --stat origin/$BASE...HEAD
git rev-parse --abbrev-ref HEAD
```

**Sensitive-file scan.** Check the file list from `git diff --stat` for paths matching `.env*`, `*credentials*`, `*.pem`, `*.key`, or `id_rsa*`. Any match → stop and surface to the user per the hard rule. Do not proceed even if the user tells you to; require a direct re-confirmation that the file is intentional.

**Issue references.** Scan commit subjects, commit bodies, and the branch name for `#NNN` patterns. Only promote to `Closes #NNN` when the signal is unambiguous:

- A commit *subject* matches `^(fix|close|resolve)(\(.+\))?:` **and** contains `#NNN` on the same line.
- The branch name starts with `fix/NNN-…` or `issue-NNN-…`.

Every other reference (`#NNN` in a body, a `refactor` commit mentioning an issue, a `feat` that relates to but doesn't close an issue) is `Refs #NNN`. Default to `Refs` when in doubt and flag for the user in Step 4 — a wrong `Closes` silently closes an issue on merge, a wrong `Refs` is harmless.

**PR template.** Check for a template and use it as the body scaffold if it exists. GitHub looks in several locations — check all of them:

```bash
ls .github/pull_request_template.md \
   .github/PULL_REQUEST_TEMPLATE.md \
   pull_request_template.md \
   PULL_REQUEST_TEMPLATE.md \
   docs/pull_request_template.md \
   docs/PULL_REQUEST_TEMPLATE.md \
   2>/dev/null
ls -d .github/PULL_REQUEST_TEMPLATE/ 2>/dev/null
```

If `.github/PULL_REQUEST_TEMPLATE/` is a directory (multi-template repo), list its contents and ask the user which template applies before filling.

If a template is found, fill its sections from the gathered context. If it has a checklist, leave items unchecked unless you've verified them.

---

## Step 3 — Draft title and body

### Title

Conventional Commits: `type(scope): subject`

- **type** — `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `build`, `ci`.
- **scope** — optional; the primary package/module/area touched. Derive from paths in `git diff --stat`.
- **subject** — imperative mood, lowercase, no trailing period, under ~70 chars total.

If the branch has a single commit, reuse its subject when it already follows Conventional Commits. Otherwise, synthesize a new subject that covers the dominant change.

### Body — default structure (when no repo template exists)

```markdown
## Summary

<2–4 sentences. Lead with *why* — the problem, the user need, the constraint that forced this. Then *what* — the concrete change. Avoid restating the diff.>

Closes #NNN
```

**Summary rules:**

- Start with the motivation (*why*), not the implementation (*what*).
- One paragraph, not a wall of text. If you need headings inside Summary, the change is probably two PRs.
- Never write "This PR …" — write the change directly.
- No hedging ("attempts to", "should hopefully"). State what it does.

### Body — when a repo template exists

Fill the template's sections verbatim (don't rename or reorder). Map:

- Template "Summary" / "Description" / "What" → the Summary content above.
- Template "Why" / "Motivation" → the *why* from the Summary (split it if the template separates them).
- Template "Testing" / "Test Plan" → describe what was tested **if verified**, otherwise leave blank with a note for the user to fill in. **Do not fabricate test steps.**
- Template "Checklist" → unchecked `[ ]` unless verified.
- Template "Issue" / "Related" → `Closes #NNN` / `Refs #NNN`.

---

## Step 4 — Propose for approval

Print the full draft — exactly as it will be submitted — and wait. Format:

```
Title:  feat(tracer): stream spans to disk without blocking the agent loop
Base:   main ← <current-branch>
Draft:  no

---
## Summary
…

Closes #42
---
```

If there's any ambiguity (close vs refs, unclear scope, behind base), list it under the draft as numbered clarifications. The user edits by number or gives a free-form correction. Re-render the draft after edits and re-confirm before proceeding.

**Do not proceed without explicit approval.** A silent response is not approval.

---

## Step 5 — Push and create

Push the branch (set upstream if missing). **No `--force` variants.**

```bash
git push -u origin HEAD
```

Create the PR with a HEREDOC so the body formats correctly:

```bash
gh pr create \
  --base "$BASE" \
  --title "feat(tracer): stream spans to disk without blocking the agent loop" \
  --body "$(cat <<'EOF'
## Summary

Span export was blocking the agent loop under load because the exporter flushed synchronously on every span. This moves writes to a background task with a bounded channel so the hot path stays non-blocking.

Closes #42
EOF
)"
```

Return the PR URL to the user. Done.

---

## Edge cases

Fail-stop conditions are already covered in Step 1 (main/master, uncommitted changes, existing PR, no auth). The cases below are the genuinely ambiguous ones.

| Situation | Handling |
|---|---|
| No upstream set | Use `git push -u origin HEAD` — don't prompt. |
| Branch behind base | Surface to user; do not auto-rebase or auto-merge. |
| Dirty commit history (WIP, "fix typo") | Flag in Step 4 as a clarification; offer squash as a follow-up the user runs, not as an auto-action. |
| Template present but empty/malformed | Fall back to the default body structure; note it in Step 4. |
| Multi-template repo (`.github/PULL_REQUEST_TEMPLATE/` directory) | List available templates; ask the user which one applies. |
| Issue reference is ambiguous (`#42` in a refactor commit) | Default to `Refs #42`, flag for the user. |
| User requests `--draft` | Add `--draft` to `gh pr create`; leave everything else unchanged. |
| User requests force-push | Only then, and only `--force-with-lease`; confirm the **head** (current) branch is not `main` / `master`. |

