- created
- 2026-01-30T00:00:00.000Z
- modified
- 2026-10-02T00:00:00.000Z
- reviewed
- 2026-04-25T00:00:00.000Z
- name
- github-pr-title
- description
- Craft PR titles using conventional commits format. Use when creating PRs or
ensuring consistent PR naming. PR titles MUST follow conventional commits to
drive release-please automation and maintain consistent git history.
- user-invocable
- false
- allowed-tools
- Bash(git log *), Bash(git diff *), Bash(gh pr *), Read, Grep, Glob, TodoWrite
# GitHub PR Title
Craft clear PR titles using conventional commits format.
**CRITICAL:** PR titles must follow conventional commit format. This drives release-please version automation and ensures consistent git history when using squash-and-merge.
## When to Use This Skill
| Use this skill when... | Use the alternative when... |
|---|---|
| Authoring a `type(scope): subject` PR title that drives release-please automation | Use `git-pr` for the full PR creation workflow (body, labels, reviewers) |
| Renaming an existing PR title to fix release-please version-bump detection | Use `git-commit-workflow` to set the same conventions on commit messages |
| Selecting the right `feat`, `fix`, `perf`, `refactor`, `chore` type for a PR | Use `github-issue-writing` for issue titles (different `[Type] Component:` format) |
| Validating PR title format before merge to maintain clean git history | Use `git-commit` to fix already-committed message formats locally |
## Format
```
<type>(<scope>): <subject>
```
See [Conventional Commits Standards](../../.claude/rules/conventional-commits.md) for comprehensive format guide.
### Type Selection
| Type | Use Case | Version Bump |
|------|----------|--------------|
| `feat` | New feature | Minor |
| `fix` | Bug fix | Patch |
| `perf` | Performance improvement | Patch |
| `refactor` | Code restructure (no behavior change) | None |
| `docs` | Documentation only | None |
| `test` | Tests | None |
| `build` | Build/deps | None |
| `ci` | CI config | None |
| `chore` | Maintenance | None |
**Decision tree:** Feature → `feat` | Bug → `fix` | Performance → `perf` | Restructure → `refactor` | Docs → `docs` | Everything else → `chore`
### Scope
**The scope is required.** The Conventional Commits spec lets you omit it; this house convention does not (`.claude/rules/conventional-commits.md`), and a squash-merge lands the PR title as the commit on `main`. Use the component or plugin the change touches:
```
feat(auth): add OAuth support
fix(api): handle null response
docs(readme): update install steps
refactor(core): simplify error handling
```
**Discover repo scopes:**
```bash
gh pr list --state merged -L 30 --json title | jq -r '.[].title' | grep -oE '\([^)]+\)' | sort | uniq -c | sort -rn
```
Or from commits:
```bash
git log --format='%s' -n 50 | grep -oE '\([^)]+\)' | sort | uniq -c | sort -rn
```
### Subject
- **Imperative mood**: "add" not "adds" or "added"
- **Lowercase**: Start with lowercase after colon
- **No period**: Don't end with punctuation
- **Under 50 chars**: Keep concise
**Examples:**
| ❌ Bad | ✅ Good |
|--------|---------|
| `Added login button` | `add login button` |
| `Fixes the bug.` | `fix null pointer in auth` |
| `Update` | `update dependencies` |
| `Resolved Performance Issues` | `improve query performance` |
### Breaking Changes
Append `!` before colon:
```
feat(api)!: remove deprecated endpoints
fix!: require Node.js 18+
refactor(db)!: change schema format
```
Breaking changes trigger major version bumps.
### Reverts
```
revert: feat(auth): add OAuth support
```
## Quick Reference
| Scenario | Template |
|----------|----------|
| Feature | `feat(<scope>): add <what>` |
| Bug fix | `fix(<scope>): resolve <what>` |
| Performance | `perf(<scope>): optimize <what>` |
| Docs | `docs(<scope>): update <what>` |
| Refactor | `refactor(<scope>): simplify <what>` |
| Deps | `build(deps): bump <pkg> to <ver>` |
| Breaking | `feat(<scope>)!: change <what>` |
## Merge Strategy and the PR Body
The title only drives release-please under **squash** merge. Under rebase or
merge-commit, each branch commit lands as-is and the PR title/body are discarded.
With the repo setting *squash → PR title and description*, the **PR body becomes
the commit body** and release-please parses it: a `BREAKING CHANGE:` footer
forces a major bump, a footer line shaped like `fix(x): …` adds an extra
changelog entry, and `Release-As:` pins the version. Write the body as a commit
body (prose + `Fixes #N` footers, no checklists).
Strategy table, body shape, and post-merge repair (`BEGIN_COMMIT_OVERRIDE`):
[merge-strategies.md](merge-strategies.md).
## Why This Matters
**Conventional commit PR titles ensure:**
1. **Accurate automation** - release-please reads PR titles to determine version bumps
2. **Clean git history** - squash-and-merge uses PR title as commit message
3. **Searchable commits** - type prefix makes filtering easy
4. **CHANGELOG accuracy** - commits are grouped by type in generated changelogs
## Agentic Optimizations
| Context | Command |
|---------|---------|
| Get commits | `git log origin/main..HEAD --format='%s' -n 10` |
| Changed dirs | `git diff origin/main..HEAD --name-only \| xargs dirname \| sort -u` |
| Update title | `gh pr edit N --title "new title"` |
| Repo merge settings | `gh api repos/{owner}/{repo} --jq '{squash: .allow_squash_merge, rebase: .allow_rebase_merge, title: .squash_merge_commit_title, message: .squash_merge_commit_message}'` |
| Discover scopes | `gh pr list --state merged -L 30 --json title \| jq -r '.[].title' \| grep -oE '\([^)]+\)' \| sort \| uniq` |
## Reference
For detailed rules, patterns, and troubleshooting, see [Conventional Commits Standards](../../.claude/rules/conventional-commits.md).
Ver no GitHub