REQUIRED for all pull requests. Always use when opening PRs, creating merge requests, or executing gh pr create / glab mr create commands. Enforces conventional branch names and conventional-commit PR titles.
TRIGGER
user asks to open/create a PR or MR, mentions pushing and opening a PR, references gh/glab commands, or discusses pull request workflow.
DO NOT SKIP
applies to all PR creation regardless of repository or context.
Open Pull Request (Conventional Branch + Conventional Title)
This skill extends the usual workflow (inspect state → branch → commit or amend → confirm all tracked work is committed → push → open PR) so branch names follow Conventional Branch and PR titles follow the same rules as Conventional Commits—aligned with the commit-message-guide skill for commits.
IMPORTANT: When This Skill Applies
This skill is mandatory for:
Any request to open, create, or draft a pull request or merge request
Commands like gh pr create, glab mr create, or GitLab/GitHub UI PR creation
Workflows involving "push and open PR" or "create PR from branch"
Branch naming when the branch will be used for a PR
Do not create PRs through other means or skip this workflow.
Non-Negotiable Requirements
Every PR must:
Use conventional branch naming (<type>/<description>)
Have a conventional commit title (<type>(<scope>): <subject>)
Be opened as --draft (unless explicitly requested otherwise)
Be assigned to @me (the user)
Have all changes committed before push
Workflow
Check existing PR status: Before starting work, check if the current branch already has an open or merged PR associated with it.
GitHub: gh pr list --head $(git branch --show-current) to check for open PRs, and gh pr list --head $(git branch --show-current) --state merged for merged PRs.
GitLab: glab mr list --source-branch $(git branch --show-current) for open MRs, and glab mr list --source-branch $(git branch --show-current) --state merged for merged MRs.
If a PR/MR exists (open or merged): This branch has already been used. Do not add new commits to it. Instead:
Stash any uncommitted changes: git stash
Switch to the main branch: git checkout main (or master/develop as appropriate)
Fetch latest changes: git pull origin main (or appropriate remote/branch)
Proceed to step 2 to create a new branch for the new work
Branch (if needed): If on main/master/develop or the user wants a new branch, create one using the naming rules below. If already on a correctly named branch (with no existing PR per step 1), keep it.
Commit: Stage changes, then record history using the commit-message-guide for message text. Prefer few commits on the branch—see Commit history below. Every change that belongs in the PR must end up committed on this branch; uncommitted work will not appear on the PR.
Pre-push (required): Do not push to upstream until every change Git already tracks (and every new file that should be in the PR) is committed. Run git status; if you see unstaged changes, staged changes waiting for a commit, or deletions not yet committed, resolve via amend, fixup, or a new commit (per Commit history) until there is nothing left to commit for work that should ship. Untracked files stay out until you intentionally git add and commit them.
Sync with main: Fetch remote refs, guard against a dirty working tree, and rebase the branch onto the latest refs/remotes/origin/main before pushing. Run each command as a standalone Bash call — do not chain with && or ;. Pipes are permitted only for data transformation.
6a. Fetch remote refs
Run: git fetch origin
This updates remote-tracking refs without modifying the working tree.
6b. Guard against a dirty working tree
Run: git status --porcelain
If the output is non-empty, stop and tell the user: "Working tree is dirty. Commit or stash your changes before syncing." (At this point in the workflow, changes should already be committed per step 5 — this is a safety net.)
6c. Rebase onto refs/remotes/origin/main
refs/remotes/origin/main is used instead of the origin/main shorthand to avoid resolution ambiguity when a local branch named main exists.
6c.1 — Run: git rebase refs/remotes/origin/main
If the rebase exits with zero → proceed to step 7 (Push).
If the rebase exits non-zero → continue to 6c.2.
6c.2 — Apply the procedure in claude/references/conflict-resolution-rebase.md. In this
skill's context, "incoming branch" is the PR's branch and "upstream" is main. The reference
handles detection, resolution, and the git rebase --continue cycle including all abort and
round-counter cases. After the procedure completes successfully (the reference reports the rebase
is complete), proceed to 6d (re-validate). If the procedure aborts at any point, propagate
the abort and stop — do not proceed to 6d or push.
6d. Re-validate if conflicts were resolved
If any conflicts were resolved during sub-step 6c.2 (i.e., the rebase did not complete cleanly in 6c.1), re-run the validate-before-pr skill before proceeding to step 7 (Push). Conflict resolution can modify file contents in ways that introduce lint or formatting violations that the earlier validation already cleared.
If validate-before-pr fails on re-run, stop — do not push or open a PR. Report the failures and request fixes.
Push: git push -u origin <branch> (or your remote/branch convention) to upstream. If you amended or rebased commits that were already pushed, use git push --force-with-lease instead of a plain push. The PR compares the default branch to this branch, so all commits you pushed are what the PR contains.
Open PR (always draft, assign to the user):
GitHub: gh pr create --draft --assignee @me --title "..." --body "..."
Use @me so the PR is assigned to the person opening it (the user’s GitHub account). Adjust only if the repo uses a different assignee rule.
GitLab: glab mr create --draft --assignee @me (or your login) with the same title/body rules; use the web UI only if you mirror draft + assignee there.
Never omit --draft unless the user explicitly asks for a ready-for-review PR.
Commit history (keep the count small)
Prefer to update existing commits instead of stacking more, so the PR stays easy to review.
git commit --amend: Use when the new work belongs with the latest commit (same intent, same type/scope, follow-up edits, typo fixes, small adjustments). Amend updates that commit in place; adjust the message if the title line no longer fits.
New commit: Add only when the change is logically separate or has a different scope (type/scope in the subject) than any commit already on the branch—so history stays one commit per coherent slice of work, not one commit per save.
git commit --fixup=<commit> (and later git rebase -i --autosquash <upstream>): Use to attach tweaks to an earlier commit on the branch without rewriting the message by hand—Git lines up fixups to squash into the right parent. Typical flow: make fixup commits, then rebase onto the branch base with autosquash so fixups fold in.
After rewriting history that was already on the remote, push with --force-with-lease so you do not overwrite others’ work blindly.
PR title (must match Conventional Commits)
Use the same format ascommit-message-guidefirst line:
Scope: optional; module or area (api, auth, ui, …)
Subject: imperative, lowercase after the colon, no trailing period, ~50 chars ideal (72 max)
Default: Set the PR title to the subject line of the primary commit on the branch (the one that best describes the whole change). With a lean history (amend/fixup), this is often a single commit; if several commits remain, pick one title that summarizes the branch without contradicting them, or tighten history first.
Examples:
feat(auth): add oauth callback handler
fix(api): handle empty pagination cursor
chore(deps): bump eslint to 9.x
Avoid: vague titles (Updates, Fix stuff), past tense (Added login), or titles that only list filenames.
Branch names (Conventional Branch)
Structure:
<type-prefix>/<description>
Prefixes (pick one synonym where alternatives exist and stay consistent with the repo):
Purpose
Prefix
New functionality
feat/ or feature/
Bug fix
fix/ or bugfix/
Urgent production fix
hotfix/
Release prep
release/ (e.g. release/v1.2.0)
Maintenance, deps, docs-only, tooling
chore/
Description segment (after /):
Lowercase a-z, digits 0-9, hyphens- between words
For release branches, dots are allowed in version segments (e.g. release/v1.2.0)
No underscores, spaces, or consecutive/leading/trailing hyphens or dots
Optional ticket id: feat/jira-123-add-export
Mapping from commit type → branch prefix (when creating a branch from intent):
Commit / work type
Typical branch prefix
feat
feat/ or feature/
fix
fix/ or bugfix/ (use hotfix/ if urgent)
perf
feat/ or fix/ depending on whether it reads as enhancement vs correction
docs, build, ci, chore, style, test
chore/
refactor
chore/ unless the change is user-visible, then feat/
Examples:
feat/user-profile-settings
fix/null-guard-in-parser
chore/update-playwright
release/v2.0.0
Optional team prefix (only if the repository already uses it): username/feat/foo or team/fix/bar. Do not invent a prefix unless the project standard requires it.
PR description
Keep it short (2–5 sentences), impact-first: problem solved, user or system benefit, notable risks or rollout notes. Do not mirror the file list; that is visible in the PR UI. Match the tone of commit-message-guide bodies: explain why when the title is not enough; omit noise (test pass claims, AI attribution, line counts).
Closing keywords: If the task description, session context, or commit messages on this branch contain any GitHub issue-closing keyword (Closes #N, Fixes #N, Resolves #N, including the Close/Closed/Fix/Fixed/Resolve/Resolved variants), append the matching line(s) verbatim to the end of the PR body so GitHub auto-closes the linked issue(s) on merge. Do not invent a closing keyword; only propagate what the upstream context supplied. If the same Closes #N keyword appears in multiple sources, emit it only once in the PR body.
Optional issue-link prompt: If the scan in the Closing keywords paragraph above found no keyword in any upstream source, the executing agent offers to file a brand-new issue and link it to this PR instead of opening the PR unlinked. This prompt runs after workflow step 7 (Push) has succeeded and immediately before workflow step 8 (Open PR) — once the branch is pushed and the PR is essentially certain to open, right before the PR body is constructed for gh pr create — so that an aborted earlier step (e.g., step 6's rebase) cannot orphan a freshly-filed issue.
Prompt: Ask the user, via AskUserQuestion, a single strictly binary yes/no question: "File one now and link it? (y/n)" — file a brand-new GitHub issue, or skip.
On "yes": Page in and execute claude/references/draft-issue-protocol.md (the same invocation /feature --file-issue uses; the protocol requires no changes), then append the resulting Closes #N line (derived from the issue number the protocol returns) verbatim to the end of the PR body, exactly as an upstream-supplied closing keyword would have been appended.
On "no": Proceed unchanged — the PR is opened with no linked issue and no closing keyword.
Mid-flow abort/cancel/decline fallback:draft-issue-protocol.md was written for the top-level /draft-issue session, so two of its branches end the whole session — its gh-auth pre-flight ("### Pre-flight: gh auth status check") on a non-zero gh auth status, and its final confirmation ("### User confirmation before delegation") if the user rejects the drafted issue. When the protocol is invoked from /open-pr, those "end the session" branches are reinterpreted as "return control to /open-pr and proceed on the no path" — open the PR with no linked issue and no closing keyword. This reinterpretation is caller-side only and does not alter draft-issue-protocol.md; no abort, cancel, decline, or gh-auth failure during the inline protocol may terminate the PR-opening flow.
Standing guardrails: (a) the prompt is strictly binary — filing a brand-new issue or skipping; there is no path to look up, search, or enter an existing issue number (deferred to a future iteration); (b) a "no" decline is not persisted — no state is stored, and a later retry will ask again.
Examples (end-to-end)
After push, open with draft + assignee, e.g. gh pr create --draft --assignee @me --title "feat(reports): add csv export for quarterly view" --body "...".
Commit / PR title: chore(deps): bump axios to 1.7.x
Pre-flight checklist
GitHub account and commit author: Verified per the account probe in claude/references/github-auth-probe.md (extract {owner}/{repo}, probe with gh api, switch accounts if needed, verify commit author email)
Branch has no existing PR: Verified that the current branch has no open or merged PR—if one exists, switched to main, fetched latest, and created a new branch
Before push: all tracked changes (and intended new files) are committed—git status shows nothing that still needs committing for work going into the PR
Synced with main: Fetched origin, rebased onto refs/remotes/origin/main; if conflicts were resolved, validate-before-pr was re-run and passed
History is compact: prefer --amend / --fixup + autosquash; new commits only when scope or topic differs
Branch matches <prefix>/<description> and Conventional Branch character rules
PR title is a conventional commit subject line (and matches the main commit when single-commit)
PR body adds context, not a file inventory
If the task description or commit history contains a closing keyword (Closes #N / Fixes #N / Resolves #N etc.), the PR body includes the matching line at the end (deduplicated if the same keyword appears in multiple sources)
If no upstream closing keyword was found, the optional "file & link an issue" prompt was offered after the push step and before opening the PR; if accepted and the inline protocol completed, the resulting Closes #N was injected into the PR body; if declined or the inline protocol aborted/cancelled/failed, the PR was opened unlinked
PR is opened as a draft and assigned to the user (@me or equivalent)
No AI/tool attribution in title or body
After PR Creation
1. Implementation review
The PR is in draft state and not ready to merge. Ruinor code review runs as a mandatory next step; treat PR creation as the beginning of the review phase, not the end of the implementation phase.
2. Acting on reviewer feedback
When inline comments or change requests arrive:
Read all feedback in full — inline comments, review body, and general comments — before making any changes
Address all requested changes in focused commits; do not introduce unrelated refactors or cleanups alongside feedback responses
Re-run validate-before-pr after implementing feedback, before requesting re-review
Do not remove the draft flag or request re-review until all feedback has been addressed
Relationship to other skills
Commits: Follow commit-message-guide for message bodies and footers. It also documents WIP and fixup! subject lines—pair fixup commits with git rebase -i --autosquash to merge them into the target commit.
Sync with main: Step 6 fetches remote refs and rebases the branch onto refs/remotes/origin/main with automated conflict resolution before pushing. The conflict-resolution algorithm is defined in claude/references/conflict-resolution-rebase.md; step 6c.2 delegates to that reference. The /sync-pr command performs the same rebase logic independently for post-PR-creation syncing. If conflicts were resolved during the rebase, validate-before-pr is re-run before proceeding to push.
MCP / automation: Skills named like “open-pull-request” on catalogs (e.g. MCP Market) usually wrap the same steps; this document defines naming and titles so any tool or CLI you use stays consistent.