| name | create-pull-request |
| description | Create a pull request with a structured description derived from the branch commits, plus an optional guided tour of the changed files for reviewers. |
Use this skill when the user wants to create a pull request after committing their work.
Goal
Produce a pull request whose description gives the reviewer full context from the commit history and a guided tour of the changed files in an order that builds understanding incrementally.
Rules
- Do not modify source code, planning docs, or git history as part of this skill.
- Do not invent motivation, ticket IDs, ticket URLs, tradeoffs, or future plans.
- Use the branch's commit messages as the authoritative source for the PR title and the first section of the body.
- Always confirm the proposed guided tour with the user before creating the PR, or confirm its omission on a small PR.
- If the branch has not been pushed to the remote, push it before creating the PR.
Provider
This skill is provider-agnostic. Before creating the PR, identify which source code provider hosts the repository's remote (e.g., check the origin URL), then read the matching reference file from the references/ folder adjacent to this skill for provider-specific CLI commands, flags, and formatting notes.
If no matching provider reference exists, ask the user how they would like the PR created.
Inputs To Inspect
Gather context from the branch relative to the base branch:
git log --format='%s%n%n%b' <base-branch>..HEAD — all commit subjects and bodies on the branch
git diff --name-only <base-branch>..HEAD — all changed files on the branch
git diff <base-branch>..HEAD — the full diff for understanding file relationships
Detect the default base branch by running git default-branch.
PR Title
Use the most recent commit's subject line as the PR title. This preserves any ticket prefix (e.g., [TICKET-KEY]) that the repository requires.
PR Description Structure
The full shape of a PR description is shown below. The ## For reviewers block (separator, heading, and tour) is optional and should be omitted on small PRs — see "When to skip the tour entirely" for the rule.
<commit body content>
---
## For reviewers
### Guided tour of changes:
| File(s) | Description |
| --- | --- |
| [path/to/first-file](<pr-url>/changes#diff-<hash>) | <short reason this file appears here> |
| [path/to/second-file](<pr-url>/changes#diff-<hash>) / [path/to/companion-file](<pr-url>/changes#diff-<hash>) | <short reason>; <optional second constraint> |
| [path/to/third-file](<pr-url>/changes#diff-<hash>) | |
...
The tour is a two-column markdown table. The first column is the file link (or grouped links separated by / for tightly-coupled files). The second column is the reason. Row order encodes the recommended reading order — reviewers read top to bottom.
File entries should be clickable links that jump the reviewer directly to that file's diff in the PR. Do NOT wrap file paths in backticks — keep the link text as plain text (e.g., [path/to/file](...), not [`path/to/file`](...)) so the rendered links remain clean. The link format is provider-specific and may require a two-step flow (create PR, then patch links) — consult the provider reference for details.
Tightly-coupled files (e.g., a header and its implementation, or two parallel modules that share a single rationale) may share one row separated by / in the file column, with the shared rationale in the description column.
Above the separator
Place the commit message content as the body, with one transformation: remove
the commit body's hard wrapping. Replace single-newline line breaks within a
paragraph with spaces, but preserve blank lines between paragraphs. The PR
body must contain one flowing line per paragraph rather than retaining the
commit's 72-character line breaks.
Commit messages are typically hard-wrapped at 72–80 columns for git tooling, but PR descriptions render in a wide browser column. Passing the message through verbatim produces awkward early line breaks mid-sentence. Treating two-or-more consecutive newlines as paragraph breaks (matching markdown's own paragraph rules) and collapsing single newlines to spaces yields paragraphs that flow naturally in the rendered PR.
Do not otherwise rewrite, summarize, or editorialize — the commit messages were already crafted with care. Preserve the motivation, decision, and consequence paragraphs and any ticket footer exactly.
When the branch has a single commit, use its body directly (with the unwrap transformation above).
When the branch has multiple commits, prefer the most recent commit's body if it already captures the full context (common when the user writes a final summary commit). If earlier commits contain distinct context not covered by the most recent, concatenate their bodies chronologically and confirm the draft with the user. If concatenation produces a cluttered result, distill the combined messages into the same context/decision/consequence structure used by the create-git-commit skill and confirm with the user.
Below the separator
The ## For reviewers section contains information that helps during review but does not belong in permanent git history.
Guided tour of changes
Produce a two-column table of the pivotal files a reviewer needs to read to understand the change, ordered top to bottom so that understanding builds incrementally.
This is a guided tour, not an inventory. Completeness is not the goal — signal is. A file earns a slot in the tour only if reading it changes the reviewer's understanding of the PR. Files that don't drive a decision, expose a contract, or carry meaningful logic should be omitted, not included for the sake of accounting for every diff.
When to skip the tour entirely:
Omit the ## For reviewers section (heading and all) when the PR is small enough that a reviewer can absorb it without curation — roughly three or fewer files, or a single self-contained change whose commit body already frames what to look at. In those cases a tour would just restate the diff. When skipping, drop the --- separator too so the PR body is just the commit content. Confirm the omission with the user the same way you would confirm a tour.
Ordering strategy:
For the files that do appear:
- Start with files that introduce new concepts, types, or interfaces that other files depend on.
- Follow with core implementation files that use those concepts.
- Then supporting changes (config, wiring, glue code).
- End with tests, docs, or other verification files when they meaningfully reinforce the change.
Within each tier, prefer the file that has fewer dependencies on other changed files. The goal is that by the time the reviewer reaches file N, they have already seen everything file N depends on.
Description composition:
Treat each row's description as a miniature commit body for that file's stop on the tour. It should answer why this file matters to the outcome, not what changed inside it. Assume the reviewer will open the diff — the description exists to frame what they're about to see, not narrate it.
Keep a description only if it answers at least one of:
- Why does this file anchor the change (what concept, contract, or decision does it establish)?
- Why does its position in the tour matter (what does understanding it unlock for later rows)?
- What non-obvious constraint or tradeoff shaped this file's shape?
Subtract anything the diff would already make obvious — that a module was added, that a function was renamed, that tests were written, that wiring was updated. If the description would still be true after replacing the file's contents with a stub of the same shape, it's describing the diff instead of the decision.
Length:
- Empty cell when the file is self-explanatory once its position is known. The trailing test file in a feature PR rarely needs a description — its slot at the end of the tour tells the reviewer it verifies everything above it.
- One sentence (under ~20 words) is the common case. State the one thing the reviewer should know before opening the diff.
- Two clauses separated by a semicolon only when there is a distinct constraint or non-obvious choice worth flagging in addition to the primary reason — never to elaborate on the first clause.
Anything longer than two clauses is a smell: the file probably needs an inline code comment or a richer commit message rather than PR-description framing. Keep descriptions to a single line so the table stays readable.
Weak vs. strong:
Weak, because it restates the diff:
| lib/payments/retry_service.ex | new module containing the extracted retry logic |
Strong, because it frames why the file anchors the tour:
| lib/payments/retry_service.ex | establishes the single retry contract the three controllers collapse onto; every later row is a consumer of the shape defined here |
Weak, because it narrates mechanics:
| lib/payments/payments.ex | context module wiring that exposes the new service |
Strong, because it explains the decision the file embodies:
| lib/payments/payments.ex | the seam that lets controllers stay thin wrappers during the migration window called out in the commit body |
Exclusions:
The criterion for omission is signal, not file type. Apply judgment based on the specific PR — a docs-only PR legitimately centers on a README, and a test file can be pivotal when it defines the contract being introduced. In a typical PR, however, the following commonly fall below the signal threshold and should be omitted:
- Lockfiles, generated files, and purely mechanical changes (e.g., auto-formatter diffs) unless they are central to the PR's purpose.
- README, CHANGELOG, or comment-only edits that document the change without driving any decision discussed in the PR body.
- Test or fixture files that exist only to keep the suite green and don't demonstrate a new contract or behavior worth walking the reviewer through.
- Trivial wiring (one-line registrations, re-exports) when the file it wires to is already in the tour and the wiring is obvious.
If the PR touches more than ~20 files after applying these exclusions, group related files and annotate the group rather than listing each individually.
Workflow
- Identify the source code provider and read the matching provider reference from the
references/ folder.
- Run
git default-branch to detect the repository's default branch.
- Ask the user which branch the PR should target. Present the default branch as the most likely option but let the user specify a different one.
- Read the branch's commit messages and diff relative to the confirmed base branch.
- Decide whether the PR warrants a guided tour (see "When to skip the tour entirely"). If it does, analyze file dependencies and draft the tour.
- Present the proposed PR to the user:
- Show the PR title.
- Show the base branch the PR targets.
- Show the full description (commit body content; separator and tour only when included).
- Ask the user to confirm the tour, or confirm that skipping it is the right call.
- Wait for user confirmation. Do not create the PR until the user approves.
- Ensure the branch is pushed to the remote.
- Create the PR using the provider-specific commands from the reference, targeting the confirmed base branch.
- If the provider requires a two-step flow for diff links (e.g., GitHub needs the PR URL to construct full links), capture the PR URL and immediately edit the body to inject the final links.
- Report the resulting PR URL to the user.
Clarifying Questions
Ask before proceeding when:
- The base branch is ambiguous (e.g., multiple long-lived branches exist).
- The commit messages are empty and the PR would lack meaningful description.
- Multiple commits exist and it is unclear whether to use the most recent body or concatenate.
- The user may want to add reviewers, labels, or draft status.
- No provider reference matches the repository remote.
Example
Given a branch with one commit:
[PROJ-142] Extract payment retry logic into dedicated service
The retry logic was embedded in three different controller actions
with subtle behavioral differences. Centralizing it removes the drift
risk and makes the upcoming webhook retry work possible without
touching controllers again.
Intentionally leaves the old controller methods as thin wrappers
that delegate to the new service — removing them is a separate
cleanup once downstream consumers migrate.
ticket: https://jira.example.com/browse/PROJ-142
The resulting PR:
Title: [PROJ-142] Extract payment retry logic into dedicated service
Body:
The retry logic was embedded in three different controller actions with subtle behavioral differences. Centralizing it removes the drift risk and makes the upcoming webhook retry work possible without touching controllers again.
Intentionally leaves the old controller methods as thin wrappers that delegate to the new service — removing them is a separate cleanup once downstream consumers migrate.
ticket: https://jira.example.com/browse/PROJ-142
---
## For reviewers
### Guided tour of changes:
| File(s) | Description |
| --- | --- |
| [lib/payments/retry_service.ex](https://github.com/owner/repo/pull/7/changes#diff-abc123) | establishes the single retry contract the three controllers collapse onto; every later row is a consumer of the shape defined here |
| [lib/payments/retry_policy.ex](https://github.com/owner/repo/pull/7/changes#diff-def456) | encodes the behavioral differences that previously diverged across controllers — this is where the drift risk called out in the commit body actually gets resolved |
| [lib/payments/payments.ex](https://github.com/owner/repo/pull/7/changes#diff-789abc) | the seam that lets controllers stay thin wrappers during the migration window |
| [lib/web/controllers/charge_controller.ex](https://github.com/owner/repo/pull/7/changes#diff-aaa111) / [lib/web/controllers/subscription_controller.ex](https://github.com/owner/repo/pull/7/changes#diff-bbb222) / [lib/web/controllers/invoice_controller.ex](https://github.com/owner/repo/pull/7/changes#diff-ccc333) | all three controllers move to the same delegation pattern; read once, the others mirror it |
| [test/payments/retry_service_test.exs](https://github.com/owner/repo/pull/7/changes#diff-ddd444) | |
Notice in the example above that the commit body's hard-wrapped lines have been unwrapped into flowing paragraphs, the three controllers share a single grouped row, and the test file sits at the end with an empty description because its position alone explains its role. The PR's diff also touches mix.lock, a CHANGELOG.md entry, and a routine fixture update for the new test — none appear in the tour because they don't change what the reviewer needs to understand.
Final Self-Check
Before presenting the PR draft to the user, verify:
- The title matches the most recent commit subject exactly.
- The body above the separator has no hard-wrapped commit lines: each
paragraph is one flowing line, while blank-line paragraph breaks remain
intact. Apart from that unwrapping, the commit message is preserved
verbatim.
- The decision to include or omit the guided tour matches the PR's size and shape (see "When to skip the tour entirely"). When omitted, the
--- separator and ## For reviewers heading are also absent.
- When a tour is included, it is rendered as a two-column markdown table (File(s) | Description) and rows appear in a dependency-first order, not alphabetical or diff order.
- Every row in the table earns its slot — files that don't change the reviewer's understanding (lockfiles, routine doc/test updates, trivial wiring) are omitted, not included for completeness.
- Each description cell is empty, a single sentence, or at most two clauses separated by a semicolon — never longer.
- Each description would still be useful to a reviewer who already has the diff open — it frames why the file matters to the outcome rather than narrating what changed inside it.
- No information has been invented beyond what the diff and commit messages support.
- The PR is not created until the user has confirmed the tour (or its omission).