Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
SSkills DirectorySkills Directory
Is that skill safe to install?
Are you the author of Open Pull Request?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/alkofu-open-pull-request)
---
name: open-pull-request
description: 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](https://conventional-branch.github.io/) and **PR titles** follow the same rules as [Conventional Commits](https://www.conventionalcommits.org/)—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:
1. Use conventional branch naming (`<type>/<description>`)
2. Have a conventional commit title (`<type>(<scope>): <subject>`)
3. Be opened as `--draft` (unless explicitly requested otherwise)
4. Be assigned to `@me` (the user)
5. Have all changes committed before push
## Workflow
1. **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
- **If no PR/MR exists**: Continue to step 2.
2. **Inspect state**: `git status`, `git branch --show-current`, confirm remote and default branch.
3. **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.
4. **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.
5. **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.
6. **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.
7. **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.
8. **Open PR (always draft, assign to the user)**:
- **GitHub**: `gh pr create --draft --assignee @me --title "..." --body-file -` (body on stdin via heredoc)
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 as** `commit-message-guide` **first line**:
```
<type>(<scope>): <subject>
```
- **Types**: `feat`, `fix`, `refactor`, `perf`, `style`, `test`, `docs`, `build`, `ci`, `chore`
- **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
Short Markdown that is quick to scan: a one- or two-sentence lead, then bullets. Use this shape:
```markdown
<1–2 sentences: the problem solved and why it matters>
## Changes
- <one line per logical change, imperative mood>
## Notes
- <risks, rollout steps, follow-ups, or manual verification still needed>
Closes #N
```
- **Lead**: impact-first — the problem and the user or system benefit. No heading above it.
- **Changes**: 3–5 bullets, one line each. Describe changes, not files; the file list is visible in the PR UI. Use backticks for code identifiers and paths.
- **Notes**: include only when there is something to say; never write an empty or "N/A" section.
- No other headings, no checklists, no tables, no emoji. A trivial PR may be the lead sentence alone.
- Omit noise: test pass claims, AI attribution, line counts.
- Pass the body with `--body-file -` and a heredoc rather than inline `--body "..."`, so newlines, backticks, and quotes survive shell quoting.
**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.
**Issue filing is opt-in:** The PR is opened unlinked by default. Never ask whether to file an issue. Only when the user's request explicitly asks for an issue to be opened (e.g. "open a PR and file an issue") does the executing agent file a brand-new issue and link it to this PR. This step runs **after workflow step 7 (Push) has succeeded and immediately before workflow step 8 (Open PR)**, so that an aborted earlier step (e.g., step 6's rebase) cannot orphan a freshly-filed issue.
- **Explicit request:** 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. If an upstream closing keyword already exists, do not file another issue.
- **No explicit request:** Proceed unchanged — the PR is opened with no linked issue and no closing keyword beyond any upstream-supplied ones.
- **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 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 guardrail:** filing is limited to a brand-new issue; there is no path to look up, search, or enter an existing issue number.
## 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-file -` with the body in a heredoc.
**Feature**
- Branch: `feat/export-csv`
- Commit / PR title: `feat(reports): add csv export for quarterly view`
**Bugfix**
- Branch: `fix/chart-tooltip-position`
- Commit / PR title: `fix(ui): correct tooltip placement near viewport edge`
**Chore**
- Branch: `chore/bump-axios`
- 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 follows the lead + `## Changes` (+ optional `## Notes`) shape and 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)
- [ ] No issue-filing question was asked; an issue was filed only if the user explicitly requested one, in which case the resulting `Closes #N` was injected into the PR body, and if 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](https://mcpmarket.com/tools/skills/open-pull-request)) usually wrap the same steps; this document defines **naming** and **titles** so any tool or CLI you use stays consistent.