---
name: git-pr
description: "Cleepi's PR/MR shape. Title is a single conventional commit derived from the branch name (NOT the diff). Body is 1–3 sentences plus optional bullet points. No spec link, no test plan, no risks, no Closes-N footer. Norm: PRs should be small and modular. Load when about to open a PR/MR, when reviewing one, or when asked about PR conventions."
---

# git-pr

You are about to open a pull request (GitHub) or merge request
(GitLab), or you are reviewing one. The shape below is the
whole convention. Anything beyond it is over-engineering.

## The shape

**Title** — a single conventional commit, derived from the
branch name:

```
<type>(<domain-or-ticket>): <subject>
```

Where:

- `<type>` comes from the branch name's `<type>/` prefix
  (see `git-branch`).
- The parenthetical is the ticket if the branch has one
  (`feat(AC-123): ...`), otherwise the domain from cwd
  (`chore(crew): ...`).
- `<subject>` is the kebab-case slug from the branch, turned
  into spaces.
- All `git-commit` hard rules apply: lowercase first letter
  after the colon, no trailing period, imperative present
  tense.

**Body**:

```
1–3 sentence description of what + why.

Optional bullet points of main changes (skip when the PR is
small or obvious):

- change one
- change two
- change three
```

That's it. No other sections.

## Hard rules

- **Title comes from the branch, NOT the diff.** Reading the
  diff produces variable output and costs an LLM call. Branch
  → title is mechanical. If the branch is wrong, fix the
  branch.
- **No "Spec / ticket" section in the body.** The ticket lives
  in the title via `<type>(<ticket>): ...`. If the work has a
  spec, link it inline in the description sentence if it
  matters; usually it doesn't.
- **No "Closes #N" footer.** Title carries the ticket. If you
  need GitHub's auto-close behavior, add `Closes <ticket>` to
  the description sentence, not as a separate footer.
- **No "Test plan" section.** Tests live in the diff. If
  reviewers need verification steps, the description sentence
  says how to verify in one line.
- **No "Risks / rollback" section.** If a PR has real risks,
  the description sentence names them. Boilerplate "low risk,
  easy revert" lines fail the delete test.
- **Bullets are optional.** Small or obvious PRs skip them.
  Don't pad a 2-file PR with a 5-bullet list of what those 2
  files do.

## The size norm

**PRs should be small and modular.** A PR touching 30+ files
is a smell — split it. This skill states the norm; it does
not enforce. Reviewers and reviewers' agents flag oversized
PRs the same way they'd flag missing tests.

Aiming small means the title + 1–3 sentence body fits the
work without strain. If you find yourself writing five
paragraphs, the PR is too big.

## Examples

### Small obvious PR — title only suffices

Branch: `chore/bump-prettier`

```
Title: chore(meta): bump prettier

Body:
Bump prettier from 3.2.5 to 3.3.0. No config changes.
```

### Standard PR — description + bullets

Branch: `feat/AC-123-rename-primary-button`

```
Title: feat(AC-123): rename primary button

Body:
Renames the primary action button from "Submit" to "Continue"
per the AC-123 redesign. Affects the checkout flow and the
profile-edit modal; no behaviour change.

- update Button label prop default
- update copy in checkout/profile-edit
- update snapshot tests
```

### Refactor PR — description only

Branch: `refactor/DRAFT-005-extract-merger`

```
Title: refactor(crew): DRAFT-005 extract merger

Body:
Extracts the settings-merger logic out of install-crew.ts into
its own module so DRAFT-006's per-field merger can swap it
cleanly. No behavior change.
```

## Anti-patterns

| Wrong | Why |
| --- | --- |
| Title derived from `git diff` summary | Variable, costs an LLM call, drifts from branch intent |
| Body has "## Summary" / "## Test Plan" / "## Risks" headers | Bloat. Body is plain prose + optional bullets. |
| "Closes #123" footer | Ticket is in the title; footer is redundant |
| 8-paragraph body for a 3-file PR | PR too big or body padded; both bad |
| `Co-authored-by: ...` in description | Never. Same rule as commits. |
| Emoji in title | `feat:` not `✨ feat:` |
| Trailing period in title | `rename primary button` not `rename primary button.` |

## When opening via CLI

- **GitHub:** `gh pr create --title "<title>" --body-file <tmp>`.
- **GitLab:** `glab mr create --title "<title>" --description-file <tmp>`.
- **Neither installed / unauthenticated:** print title + body
  for manual paste into the web UI.

## Tuning

Don't edit the package skill. Copy to project scope:

```bash
cp .pi/agent/skills/git-pr/SKILL.md .pi/skills/git-pr/SKILL.md
```

Project scope wins on collision.
