One skill for create and update. Make the title + body match the branch as it is now. Do not strip media from an existing description.
Steps
git status/git diff/git log/git diff <default>...HEAD(and remote tracking) so you know the full change set — not just the latest commit.- Detect an existing PR/MR for this branch (
gh pr view/glab mr view).- None → create (push upstream with
-uif needed). - Exists → edit title + body in place. Do not open a duplicate.
- None → create (push upstream with
- Draft a title and body from all commits/files in the PR, not one commit.
- If updating: fetch the current body first. Preserve every media item exactly (see below). Then rewrite text so Summary / Test plan (or the repo's usual sections) stay accurate.
- Apply with
gh pr create/gh pr edit(orglabequivalents). - End with the PR/MR as a markdown link — the number and the full forge
URL (
[#123](https://github.com/org/repo/pull/123), GitLab!equivalent). Never a bare#123. This is the one place the rule is written down; the other skills just follow it.
Title + body
- Title: concise, why-focused; match repo PR style when obvious.
- Body: use the repo's template when one exists; otherwise:
## Summary
<1-3 bullets of what changed and why>
## Test plan
- [ ] <concrete checks>
- Run the prose through
no-tropesbefore publishing. - Do not invent reviewers, labels, or milestone unless asked.
Commits
Shape the branch's commits as part of opening/refreshing the PR.
-
Check effective
user.nameanduser.emailbefore committing. GitHub login does not set commit attribution. If email is unset or Git infers a local-host address, stop before publishing and confirm an account-associated email. Never publish after ignoring Git's inferred-identity warning. -
One concern per commit. Default to a topical split (2–5 is typical) even if not asked; don't dump everything into one blob unless the user wants it.
-
Match the repo's recent commit style (
git log --oneline -15); subject = why. No "WIP" / "fix stuff". -
Rebuild with soft reset + path-staged commits (no
git rebase -i— needs a TTY). Show the finalgit log --oneline <default>..HEADbefore force-push. Two traps in that recipe:- Soft-reset to the branch's real base SHA (
git merge-base HEAD origin/<default>), never toorigin/<default>itself — it moves mid-task and will stage other people's commits as yours. git reset <base> -- <path>leaves that path unstaged, so the nextgit commitsilently captures its pre-edit version. Verify the content landed (git show <sha>:<path> | grep <new symbol>) before force-push.
- Soft-reset to the branch's real base SHA (
-
Keep authorship when reshaping others' work (
Co-authored-by/ cherry-pick), especially duringpr-triagesalvage. -
Don't mix pure formatting with logic, commit secrets/
.env, or rewrite commits already on the default branch without asking.
Preserve media (hard rule)
When a PR/MR already has a body, never delete media.
Treat as media (keep verbatim, same URLs/markup/order when possible):
- Markdown images / links to images or video (
,[...](...)to media) - HTML
<img>,<video>,<source>,<br>used between media blocks - GitHub/GitLab upload / user-attachments / moved-image URLs
- Image/video-only paragraphs or HTML comments wrapping media
Update flow:
- Read the existing body. Extract JSON descriptions to plain Markdown with
jq -r '.description'before using line-oriented file tools; one long escaped JSON string can be truncated even when the overall file fits. Reject truncated content rather than rebuilding a partial description. - Extract and keep the media blocks.
- Rewrite textual sections so they match the current diff.
- Re-attach the preserved media (same block(s), typically at the end unless they were interleaved on purpose — then keep interleaving).
- Before submit, diff old body vs new: every media URL/markup from the old body must still be present.
If a refresh would drop media, stop and keep the old body (or only edit the title) rather than publishing a media-stripped description.
Scope
- In: open PR/MR, push if needed for create, shape commits, retitle, rewrite description, preserve media, print URL.
- Out: rebase, CI, and review threads (
pr-ready), triage/salvage (pr-triage), merging.
Forge cheatsheet
# GitHub — read
gh pr view --json url,title,body,baseRefName,headRefName
# GitHub — create
gh pr create --title "…" --body "$(cat <<'EOF'
…
EOF
)"
# GitHub — update (body from file avoids shell-eating newlines/media)
gh pr view --json body -q .body > /tmp/pr-body.md
# …edit /tmp/pr-body.md carefully…
gh pr edit --title "…" --body-file /tmp/pr-body.md
# GitLab
glab mr view
glab mr create
glab mr update <N> --title "…" --description-file /tmp/pr-body.md