Imported from Hallmanac/hall9k (
.claude/skills/pr-summary/SKILL.md). Install upstream withnpx skills add Hallmanac/hall9k --skill pr-summary. Copyright stays with the author.
PR Summary Generator
Write the title and description the way a colleague who respects the reviewer's time would: plain
language, oriented up front, organized around what a reviewer needs to think about rather than the
order the commits happened to land in. The output is the deliverable: never run gh pr create
or gh pr edit, and never open a PR — the Hall9k daemon opens PRs (PullRequestOpener); agents
are forbidden from doing so.
The primary use is a build session's own closing PR SUMMARY: block (Decisions Log
#163). The headless build prompt's last step asks for it, and the daemon puts what
you write straight into the pull request it opens: your title becomes the pull request's title, and
your body sits verbatim between the platform's own bookkeeping. Write it into the final message
under a line reading exactly PR SUMMARY:, placed before the HANDOFF: block, with Title: <one line> as its first line, a blank line, then the body.
The platform adds four things around your text, so leave all four out of it:
Work item: <url>as the body's first line, when the task carries an external reference. A work-item line of your own is dropped rather than shown twice.- The acceptance-criteria checklist, in a collapsed
<details><summary>Acceptance criteria</summary>block below your prose. - Any residual note the review loop left (
**Left unfixed:**,Review ride-alongs:, a reduced review-stage composition), below that. - The
---rule and theHall9k run `<id>` · <tokens> tokensfooter, last.
A repo's own PR-description rule wins for the prose. When the target repository ships one —
arx-platform's .claude/commands/git/pr-description.md is the known case, and a PR-description or
pr-summary skill under the repo's own .claude/skills/ counts too — take the voice, the section
shape, and the title convention from there, and use this skill only for what that rule does not
say. Only when the repository ships none is this skill's own "How it should read" the whole answer.
The owner's own voice wins for the prose. When the owner has named a voice skill
(h9k owner set --voice-skill <name>), the prompt that asked you for this block names it: load that
skill and its contexts/code-review.md context before writing, and write in it. That settles the
sentences, not the shape — the repository's own PR-description rule above still decides the
structure, and the platform still adds the four things below around whatever you write.
The second use is replacing the body on an already-open PR, or drafting one for a PR opened
outside Hall9k's own dispatch entirely. For an already-open Hall9k PR, read the current body first
(gh pr view <number> --json body -q .body), because it carries the real footer and, whenever the
review loop left something behind, a **Left unfixed:** or Review ride-alongs: paragraph
(Decisions Log #87) that has to survive into the replacement's ## For the reviewer section rather
than being silently dropped. Hand the drafted text back for a human to apply; this skill never
edits a pull request itself.
Process
-
Gather the change (in parallel):
- Commits on this branch vs the base:
git log --oneline origin/main..HEAD(base ismainunless told otherwise) - Full messages and bodies:
git log origin/main..HEAD - Change shape:
git diff --stat origin/main..HEAD - The diff itself for anything the commit messages describe vaguely — a description assembled from commit subjects alone reads like a changelog and tells a reviewer nothing the commit list didn't already.
- Commits on this branch vs the base:
-
Find the linked work item, if any. Check
task.md'sexternal-reference:frontmatter line when this branch was cut for a Hall9k task — but not in the worktree itself: a task's worktree never containstask.md, which lives at<project home>/tasks/<shortid>-<slug>/task.md, a sibling ofrepo/. A dispatched session's own prompt names the project home under "Where this project lives"; readtask.mdfrom there. Otherwise check whatever the caller already knows about a linked card or issue. Theexternal-reference:value already names which kind it is:jira:<KEY>is a Jira card,github:<owner>/<repo>#<number>is a GitHub issue. Use whichever one is present; when neither is, there is no work-item line at all — never invent one, and never fall back to a bare issue number with no source for it. A Jira key is not itself a URL: resolve it as<site>/browse/<KEY>, with<site>read fromh9k connection list's Site column — never guess the host. A GitHub reference maps directly:github:<owner>/<repo>#<number>ishttps://github.com/<owner>/<repo>/issues/<number>. -
Work out what a reviewer actually needs, same two questions in this order:
- What does this change, described so someone who hasn't read the diff understands its shape?
- What here would a competent developer be puzzled by, disagree with, or waste time re-deriving? That is the only "why" worth writing down.
-
Name what you cannot determine, rather than inventing it. If the reason for a decision is genuinely not in the commits, the diff, the linked work item, or the code comments, say so under "For the reviewer" — a dispatched session has no one to ask;
h9k ask/h9k answerare Slice 2 and not built yet (AGENTS.md). -
Write the body per "How it should read" below, then output the final title and description in a fenced code block so it can be copied or consumed verbatim. In a build session, that block goes into the final message under the
PR SUMMARY:line described at the top; the daemon reads it back from there and tolerates the fence.
How it should read
Audience: a colleague reviewing this on GitHub who hasn't read the diff yet.
The work-item line, conditional and first — and only for the second use. One line,
Work item: <url>, when step 2 found one and you are replacing an already-open PR's body or
drafting one for a PR opened outside Hall9k. A task carries at most one external reference, so use
whichever it carries; when neither is present, the line is omitted entirely rather than left empty
or guessed at. In a build session's own PR SUMMARY: block, leave it out: the daemon writes it,
and a second copy is dropped.
Then a sentence or two of orientation. What this PR is and where it came from — a review, a
ticket, a bug someone hit, a field report. Get into it from there. No ## Summary heading
restating the title.
The change in prose, grouped by what a reviewer thinks about, not by commit order. A run of
independent changes is a bulleted list; a single decision that needs justifying is a paragraph.
Group bullets by reviewer concern — the endpoints together, the data-shape change together, the
test changes together — rather than the sequence the commits happened to land in, which is rarely
how a reviewer reasons about the diff. One idea per bullet, written as a full sentence:
Success responses now use ApiEnvelope<T> rather than the older ApiResponseType., not
Envelope: ApiEnvelope<T>. A telegraphic fragment isn't concision, it just moves the work of
reconstructing the meaning onto the reader.
Spell out an acronym the first time it appears, then use the short form afterward:
the Pull Request (PR) queue, then PR from there. Skip it for ones so ubiquitous spelling them
out reads as noise (API, URL, ID).
Include the "why" inline, next to the change it explains, and only when it earns its place. A
reason attached to the change it explains gets read; a reason parked in a ## Why section three
paragraphs later doesn't. Skip it entirely when the change explains itself. Write it when the
change looks wrong without it, when an obvious alternative was rejected, when it prevents someone
"fixing" it back, or when it's subtle enough a reviewer wouldn't spot it unprompted.
A ## For the reviewer section, when there's something worth flagging — this is often the
most valuable part of the description:
- Things that will bite: ordering constraints, a migration that must run first, a dependency on another PR, a follow-up deliberately left for later.
- Deliberate omissions, each with the card or issue that owns the rest of the work — not a vague "more to do here", but the actual tracking reference.
- Judgment calls, with the reasoning behind them, so a reviewer who'd have chosen differently can see why this one was made rather than re-deriving it from the diff.
- A carried-forward residual note, when replacing an already-open PR's body: whatever
**Left unfixed:**orReview ride-alongs:paragraph (Decisions Log #87) the current body already carries survives into this section unchanged, per the note at the top of this skill.
Leave the section out entirely only when none of the four apply — including no carried-forward residual note to place; an empty or padded heading isn't worth the reviewer's scroll.
A short provenance note, plus the run/token footer — the note composed from what you actually
know, the footer carried forward, never invented. Both apply only to the second use above,
replacing the body on an already-open Hall9k PR: that is the only case where you have both
a task id (from task.md) and an existing footer to read back.
- The provenance note verbatim, with the task id you were actually given (from
task.md's frontmatter, or the caller's own context): "Composed by an agent session from Hall9k task<id>." Compose it yourself — the daemon never writes one, on a fresh PR or an already-open one, so there is nothing to read back here, only the task id itself, which you do know and state plainly rather than guess at. It says the work was agent-assisted and points at where to find the full record (h9k task show <id>/h9k logs <id>), and stops there. It never narrates what the session did step by step, and never reproduces build or test output. - The footer line —
Hall9k run `<run-id>` · <tokens> tokens— only when replacing an already-open PR's body: read it back from the current body (gh pr view <number> --json body -q .body) rather than composing a new one. Unlike the provenance note, this one you cannot compose yourself even with the run id in hand:PullRequestBody.Buildsums the run's own token accounting at the moment the daemon opens the PR, while the run is still live, so the figure is a snapshot that goes stale as the same PR gathers later review and follow-up work (draft task9f6284bcnames the field incident this caused: a footer that kept naming the original run and its original token count through twelve later generations). Carry the existing figure forward rather than trying to recompute it, reformatting it with underscore separators (18_401_309rather than the daemon's own ungrouped18401309). This reformatting is this skill's own convention, not yet the platform's: the daemon's PR-open formatter andh9k status's own spend-pressure line render token counts differently from each other today (ungrouped and comma-grouped, respectively), and unifying them is draft task9f6284bc— underscore-grouping here is a deliberate deviation from both until that lands, not a claim that either already matches it.
Omit both from a build session's own PR SUMMARY: block, where the daemon writes the real footer
itself and no provenance note belongs, and from a PR opened entirely outside Hall9k's dispatch —
there's no task id to compose the note from and no existing footer to carry forward.
Keep out
- Section scaffolding for its own sake. No
## Summary/## Key Changes/## Technical Detailsskeleton imposed on every PR. Use headings when the PR is big enough to need navigating, and name them after the actual content. - The acceptance-criteria checklist, restated. The task's criteria are Hall9k bookkeeping, not something a reviewer checks off against the diff.
- Run narration. No walkthrough of what the agent did and in what order — that's what the provenance note replaces.
- A build and test transcript. "Tests pass" belongs in CI, not the description. Mention coverage only when it's the point of the PR, and then briefly.
- A section per commit. Describe the change as a whole, grouped by reviewer concern.
- Restating the diff. Don't walk file by file. If a file needs explaining, explain the decision in it, not its existence.
- Padding. No "This PR aims to…", no re-summarizing in a closing paragraph, no per-item significance ("this is important because…").
- Any reference to Claude, Claude Code, or AI assistance beyond the provenance note above. No
Co-Authored-By, no "Generated with". The provenance note names the run, not the model.
Example
The shape end to end: title, work-item line, orientation, grouped bullets with inline whys, a
reviewer section, and, as when replacing an already-open PR's body, a composed provenance note plus
the footer carried forward from the PR being replaced. Also note the house style this skill and
every other authored PR description follows: no em dashes, commas or periods or parentheses
instead. That rule is a project setting now, not only a line in the operator's own
~/.claude/CLAUDE.md (which --setting-sources project drops from a dispatched session):
h9k project show prints this project's own writing conventions, h9k project set <project> --writing-conventions changes them, and every prompt that asks for a PR SUMMARY: block carries
them verbatim. The platform re-checks the mechanical half immediately before it posts, so an em
dash that slips through is rewritten rather than published, but a body that needed rewriting is a
body that read as somebody else's.
Title: Compose PR bodies a colleague would write, not a run transcript
Work item: https://github.com/Hallmanac/hall9k/issues/184
PR #1990's daemon-composed body read as an agent transcript: title restated, the
acceptance-criteria checklist, a run narration, then build/test output. This PR is the fix: the
canonical pr-summary skill now composes a body a colleague would write instead.
Most of the change is to the skill's own instructions:
- The process gathers the linked work item before anything else, so the body can lead with it
instead of burying it in a footer.
- The "How it should read" section replaces the generic Summary/Why/Key Changes scaffolding with
orientation-first prose grouped by reviewer concern, matching the house style in
`~/.claude/commands/git/pr-description.md`.
- A new `For the reviewer` section carries the things worth flagging by name, rather than leaving
them implicit in the diff.
The provenance note stays short by design (a pointer, not a transcript), because the run record
already holds the full one.
## For the reviewer
This only changes the skill's own text; nothing in `PullRequestBody.cs` (the daemon's automatic
PR-open formatter) changed, so the two can drift out of visual sync until that formatter also
underscore-groups its token counts, which draft task `9f6284bc` owns.
---
Composed by an agent session from Hall9k task `f99153c9`.
Hall9k run `01a06cb3-caf6-76c5-a899-105d1fb07e62` · 42_017 tokens
Title
One line, describing the change rather than the activity. Include the ticket if the commits or
branch name carry one, in the usual form (ABC-1234: <title>). Prefer what the change does over
what was done to the code: Send mass messages from the configured specialist address over
Refactor MassMessagingService.
Write the key in yourself rather than leaving it to the platform. For a Jira-referenced task the
daemon puts it there when it is missing, idempotently, but a title you wrote the key into is a
title in your own wording throughout; one it had to repair is not. A GitHub issue reference is
never prefixed at all, by you or by the daemon: the work-item line cross-references it, and a bare
#42 on a squash-merge subject is an issue link nobody meant to make.