| name | pr-creator |
| description | Use when the user wants to create or update a pull request or merge request, open a PR/MR, push changes for review, update a PR description, or mark a draft as ready. Triggers on: "create pr", "open pull request", "make a pr", "submit mr", "merge request", "push for review", "ready for review", "/pr", "open mr", "ship it", "send for review", "update the pr", "update the description", "mark as ready".
|
| license | Complete terms in LICENSE.txt |
Pull Request / Merge Request Skill
Core principle: Read the actual diff before writing anything. Every sentence in the description
must come from code you read, not from branch names or assumptions.
Operating mode: automatic by default. Do not stop to confirm routine choices (branch name, commit message, draft body) — derive them from the diff and execute. Only stop for the destructive / ambiguous cases listed under Hard Stops. Showing a draft "for approval" before creating is not a hard stop; the user can gh pr edit after the fact.
Quick Reference
| Action | GitHub | GitLab |
|---|
| Create | gh pr create --title "..." --body "..." | glab mr create --title "..." --description "..." |
| Update | gh pr edit <number> --title "..." --body "..." | glab mr update <number> --title "..." --description "..." |
| Mark ready | gh pr ready <number> | glab mr update <number> --draft=false |
| Base branch | --base <branch> | --target-branch <branch> |
| Draft | --draft | --draft |
| Push | git push -u origin HEAD | git push -u origin HEAD |
Worktree / autonomous invocation
Detect both up front — they change preflight rules.
git rev-parse --git-dir
git worktree list
You are in autonomous mode when this skill was invoked by a parent skill (e.g. devpilot:resolve-issues, devpilot:auto-feature) rather than directly by a human. In autonomous mode:
- The "stop and ask the user" gates below become "return control to the parent with the question" — never deadlock waiting for human input that isn't coming.
- Replace "show the draft to the user before creating" with "include the draft in your final response" so the parent skill can surface it.
- Do not
cd out of the worktree; the parent owns cwd.
Base branch. Always diff and log against origin/<default-branch> (typically origin/main), not local main. In a worktree the local main ref may be stale or absent. Run git fetch origin <default-branch> before reading the diff so the comparison is honest.
Preflight Checks
Before anything else, run these in parallel:
git remote get-url origin
git rev-parse --abbrev-ref HEAD
git rev-parse --git-dir
git fetch origin <default-branch> --quiet
git status
git log origin/<default-branch>..HEAD --oneline
git diff --name-only origin/<default-branch>...HEAD
git ls-remote --heads origin <branch>
gh pr list --head <branch>
Auto-recover: on main/master
If HEAD is on main/master, do not stop — recover automatically:
- Confirm none of the local commits ahead of base have been pushed to
origin/main. If git log origin/main..HEAD is empty AND the working tree is clean, there is nothing to PR — exit. If commits ahead of base have already been pushed to origin/main, stop: the PR window has passed (see Hard Stops).
- Pick a feature branch name (see Branch naming).
git checkout -b <name> — this carries any uncommitted changes onto the new branch and leaves main untouched.
- If there are uncommitted changes that belong in the PR,
git add the relevant files (those whose paths overlap the intended PR scope) and commit with a conventional-commit message derived from the diff. Leave unrelated dirty files alone.
- Continue with the normal flow.
Never run git reset, git push --force, git push --force-with-lease, or any history rewrite on main/master — not as a recovery, not as an "option," not ever.
Auto-recover: dirty working tree overlapping the PR diff
If modified/staged files overlap the PR diff, do not stop — stage and commit them as part of the PR with a conventional-commit message derived from the changes. Files outside the PR diff stay untouched.
Hard Stops
These are the only cases where you must stop. In autonomous mode, return the question to the parent instead of blocking:
- Work already pushed to
origin/main/origin/master. The PR window for those commits has passed. Do not try to "rescue" it with history rewriting. Tell the user.
- No commits ahead of base AND no uncommitted changes. Nothing to PR.
- Open PR already exists for this branch. Switch to update flow (see below) — this isn't really a stop, just a branch in logic.
- Remote branch diverged.
git log HEAD..origin/<branch> is non-empty after fetching. Reconcile by inspecting; never force-push.
Do NOT block on: untracked files, or modified files outside the PR diff. These are common in worktrees (test artifacts, scratch logs, leftovers from a parent agent) and are already excluded from origin/<base>...HEAD. Note them in your report and proceed.
Branch naming
Derive deterministically — do not ask:
- If there are commits ahead of base, parse the latest commit subject. Take its conventional prefix (
feat, fix, chore, docs, refactor) and slugify the rest: <type>/<kebab-slug> (max ~50 chars).
- Otherwise (only uncommitted changes), pick the prefix from the change shape —
fix: for bug language in modified code, docs: for .md-only, chore: for config/tooling, else feat:. Slug from the most-changed top-level directory or filename stem.
- If a branch by that name already exists locally, append
-2, -3, etc.
Branch already on origin, but no open PR (common after a draft-escalation push from devpilot:resolve-issues):
- Only enter this branch if
git ls-remote --heads origin <branch> returned a SHA. If it was empty, skip — git push -u origin HEAD will create the remote ref normally.
git fetch origin <branch> — see if remote has commits you don't.
- If
git log HEAD..origin/<branch> is non-empty, stop — the remote diverged. Reconcile by inspecting; never force-push.
- Otherwise
git push -u origin HEAD will fast-forward (or be a no-op). Then create the PR normally.
gh Account Consistency (multi-account / EMU environments)
git push succeeding does NOT mean gh can create the PR. They use different auth paths:
git push goes over SSH; a host alias in the remote URL (github-personal:, github-emu:) selects the key. It knows nothing about gh.
gh pr create goes over the HTTPS API using gh's own single "active" account token — unrelated to the SSH alias. When multiple accounts are logged in under the same host (common with a work/EMU account plus a personal account, both under github.com), gh keeps only ONE active account and has no built-in "switch by remote." If the active account can't see the target repo, you get:
GraphQL: Could not resolve to a Repository with the name 'OWNER/REPO'. (repository)
This almost always means the active gh account is wrong, NOT that the repo is missing.
Preflight consistency check (best-effort, warn-only — never mutate global gh state without cause). Only bother when gh auth status shows more than one account for the host; a single-account setup can't hit this, so skip it:
git remote get-url origin
gh api user -q .login
gh auth status
If the origin owner ≠ the active login and the owner isn't an org the active account has access to, warn: "gh active account may not be able to create this PR."
On Could not resolve to a Repository — do not give up. Auto-recover once:
- Run
gh auth status. If only one account is logged in, this is a genuine access/permission issue — skip to step 3. If multiple accounts exist, try to match one to the target owner.
- Switch to that account and retry the
gh pr create once. Use the host from git remote get-url origin (e.g. github.com, or a GitHub Enterprise Server host), not a hardcoded one:
gh auth switch --hostname <host> --user <login>
- If it still fails, report: "Confirm you're logged into a gh account with access to
OWNER/REPO (gh auth login)." Do not conclude the repo doesn't exist.
In autonomous mode, prefer switching back to the original active account after creating the PR so you don't leave the user's global gh state changed unexpectedly (note the switch in your report either way).
GitLab (glab) equivalent: the same principle holds — glab uses its own configured token, independent of the SSH remote. Multi-account is rarer, but if glab mr create returns a not-found/permission error on a repo you can push to, the configured glab token is the likely cause (glab auth status / glab auth login), not a missing project.
Read the Diff (Required)
git diff origin/<default-branch>...HEAD
git log origin/<default-branch>..HEAD --oneline
You MUST read and understand the actual changes before writing the description.
From the diff, determine:
- What files were added, modified, or deleted
- What the changes do functionally (bug fix? feature? refactor?)
- Whether there are test changes
- Whether there are breaking changes
Red flags — you're writing a bad description if:
- You're inferring what changed from the branch name instead of the diff
- You're using generic phrases like "implements skill definition and supporting logic"
- Your test plan mentions things not visible in the diff
- Your description would be the same for a completely different set of changes
Find the Template
Check for existing project templates first:
GitHub: .github/pull_request_template.md, .github/PULL_REQUEST_TEMPLATE.md, docs/pull_request_template.md, PULL_REQUEST_TEMPLATE.md, or files in .github/PULL_REQUEST_TEMPLATE/
GitLab: .gitlab/merge_request_templates/Default.md or files in .gitlab/merge_request_templates/
If a project template exists, use it. Fill it in based on the diff. Remove irrelevant sections entirely.
If no project template exists, read ONE template based on what you found in the diff:
Only read the template you need. Do not read all four.
Write the Description
Title: Under 72 characters. Use conventional commit prefix (feat:, fix:, refactor:, docs:, chore:). Be specific — "fix: auth redirect loop in OAuth callback" not "fix: bug".
Review Guide (required): Every PR must include a Review Guide section:
- Which file to start reviewing first
- Suggested review order for large diffs
- Any tricky logic or non-obvious decisions to watch for
Body guidelines:
- Lead with what changed and why, based on the actual diff
- Reference specific files, functions, or behaviors you saw in the code
- Run the project's lint/test commands and report results in the checklist
- Leave "For Reviewers (human)" items unchecked — those are for humans
- For bug fixes, describe the bug, root cause, and fix separately
Do not stop to "show the draft for approval." Write the strongest title and body you can from the diff and create the PR directly. Report the URL afterward; the user can gh pr edit <number> if they want to tweak. In autonomous mode (invoked by a parent skill), include the final body inline in your response so the parent can surface it.
Create and Report
Push the branch if needed, create the PR/MR, and share the URL.
git push -u origin HEAD
gh pr create --title "..." --body "..."
glab mr create --title "..." --description "..."
Optional hand-off — drive the PR to green. Creating the PR does not guarantee it is
mergeable or that CI passes. If the user asked to "make sure CI passes," "keep it green,"
or "get it merged" — or you are in autonomous mode and the parent wants a mergeable result —
hand off to devpilot:pr-guard with the new PR number. It polls checks, resolves merge
conflicts against the base, fixes failing checks, and re-polls in a bounded loop. Do not
inline that logic here; this skill's job ends at a created/updated PR with its URL reported.
Update an Existing PR/MR
When preflight finds an open PR for the current branch, or the user explicitly asks to update:
1. Read the current PR state:
gh pr view <number>
glab mr view <number>
2. Read the full diff (same as creating — the description must reflect ALL commits, not just new ones).
3. Decide: preserve or rewrite.
- New commits added to an existing PR → rewrite the full description to cover all commits. Don't just append — re-read the complete diff and write a cohesive description.
- Reviewer feedback on description → address the specific feedback while keeping the rest.
- Draft → Ready → update description if it was a WIP placeholder, then mark ready.
4. Execute the update directly (do not stop for approval):
gh pr edit <number> --title "..." --body "..."
glab mr update <number> --title "..." --description "..."
5. Mark ready (if transitioning from draft):
gh pr ready <number>
glab mr update <number> --draft=false
Common Mistakes
| Mistake | Fix |
|---|
| Description based on branch name, not diff | Read git diff first. Always. |
| Generic test plan ("verify no regressions") | Reference specific test files or manual steps from the diff |
| Auto-checking all checklist items | Run lint/test commands for verifiable items; leave human items unchecked |
| No Review Guide section | Always tell reviewers where to start and what to watch for |
| Generic bug fix description ("fix bug") | Describe the bug symptom, root cause, and fix separately |
| Leaving irrelevant sections as "N/A" | Remove the section entirely |
| Force-pushing main to create a retroactive branch | Never offer this as an option. If work is on main and pushed, the PR opportunity has passed |
| Creating duplicate PR for branch with existing PR | Check gh pr list --head <branch> first — update instead |
| Blocking on untracked/unstaged files unrelated to the PR | Only block when the dirty files appear in origin/<base>...HEAD. Untracked debris in a worktree is common and already excluded |
Diffing against local main in a worktree | Local main may be stale or absent in a worktree — always use origin/<default-branch> |
| Force-pushing because the branch already exists on origin | Fetch first; if remote diverged, reconcile, never force. Fast-forward push is fine |
| Appending to PR description instead of rewriting | Re-read the full diff and write a cohesive description covering all commits |
| Stopping to ask "should I create a feature branch?" when on main | Don't. Auto-create per Auto-recover: on main. The only main-related stop is when the work was already pushed to origin/main |
| Stopping to "show the draft for approval" before creating | Don't. Create directly; user edits after via gh pr edit |
| Asking the user to pick a branch name | Derive it per Branch naming. Don't prompt |
Treating Could not resolve to a Repository as "repo doesn't exist" | In multi-account/EMU setups it means the wrong gh account is active. gh auth switch to the owner's account and retry once — see gh Account Consistency |
Assuming git push success means gh pr create will work | Different auth paths (SSH key vs gh active-account HTTPS token). A working push says nothing about gh API access |
Red Flags — you are over-confirming
If you catch yourself about to write any of these, stop and just execute:
- "Want me to create a feature branch?"
- "Here's the draft — should I proceed?"
- "What should I name the branch?"
- "Should I commit these changes first?"
The only legitimate stops are listed under Hard Stops. Everything else is automatic.
Tips
- For stacked PRs, mention the dependency chain.
- If the diff is large, highlight the most important files for reviewers.
- Respect the user's language — if they write in Chinese, write the PR in Chinese (unless the project convention is English).