Imported from stormlightlabs/thunderstorm (
payloads/claude/skills/commits-and-prs/SKILL.md). Install upstream withnpx skills add stormlightlabs/thunderstorm --skill commits-and-prs. Copyright stays with the author.
Commits and pull requests
Write for the person reading git log in a year with no memory of this work.
They are skimming for one change among hundreds. Every line you add is a line
they read before they find it.
Use the writing-docs skill for the prose, and check the draft against its
tells catalogue before you commit or open anything. A commit message, a pull
request body and a review comment are all read by a person, so all three get
that pass. tstorm check commit-message checks shape, not prose: it will pass
a message full of tells. tstorm check prose <file> reads the draft against
part of the catalogue, and what it reports is worth reading before the commit
rather than after.
Everything here is in addition to that.
Length
The pull request title and body become the squash commit, verbatim. This
repository merges with squash_merge_commit_title=PR_TITLE and
squash_merge_commit_message=PR_BODY, so there is one text to get right and
one place to get it right: the pull request. A branch's own commit messages are
discarded at merge and are checked for shape alone.
| Text | Target | Where the number comes from |
|---|---|---|
| Pull request title | 53 characters | 59 allowed, less the (#NN) |
| Pull request body | 20 lines | It is the commit body |
| Pull request comment | 100 words | A reply, not a report |
| Review comment | 200 words | Ten findings; see review |
| Edit reply | 150 words | Ten outcomes; see revise |
The body is a commit body, so wrap it at 72 columns and use no headings:
## What reaches git log as the literal characters ## What. One shape, at
one size.
Comments are counted in words because GitHub soft-wraps them. A 40-line comment
there is 400 words, which is how the old line targets were met and missed at
once. writing-docs carries that rule for everything else.
tstorm check commit-message --pr --title-file <f> --body-file <f> reports the
title and the body, and CI runs it on every edit to either.
Commit messages
<type>: <what changed, imperative, lowercase, under 60 characters>
<why it changed, wrapped at 72 characters>
Types used here: feat, fix, docs, refactor, test, chore, perf.
tstorm check commit-message checks the shape: the type, the 60-character
subject, the blank line, and the 72-column body. Fenced blocks, trailers, and
unbreakable strings such as URLs are exempt from the column limit.
Run it before you commit. To have git run it for you, write a commit-msg
hook that calls it and point git at the directory holding it:
mkdir -p .githooks
cat > .githooks/commit-msg <<'HOOK'
#!/bin/sh
exec tstorm check commit-message "$1"
HOOK
chmod +x .githooks/commit-msg
git config core.hooksPath .githooks
Set core.hooksPath only after the directory holds the hook. It replaces
.git/hooks wholesale, so pointing it at an empty or missing directory turns
off every hook the repository already had, silently.
CI can run the same script in --pr mode over the title and body, which is
the text that lands, and report without failing: both stay editable until the
merge, so naming a problem is worth more than blocking on it.
Length is reported and rejected by neither, under Length.
Authorship
Every commit here is authored by the repository owner. Agents work under their direction, and which one typed a given commit was never checkable, so the log does not try to say.
Leave the trailers a harness writes exactly as it wrote them, and add none by hand. Name no model in a subject or a body. The message describes the change, not what produced it.
Review comments carry a model tag. The first line names the model and reasoning
level the pass ran at, under the review skill, because which reviewer found a
defect is a question a reader of the thread asks.
Pull request bodies
A reviewer wants to know what to look at and whether it works. Say that, and
stop. The body is scaffolding for one review, and it never reaches git log,
so nothing in it is a record.
Most changes need only this:
Closes #<issue>
One paragraph: what changed, and what behavior it produces.
Verified with `<command>`: <result>.
Not covered: <what was left, with a link>.
There is no second, longer form. A body with headings reaches git log with
its ## characters intact, and four headings over a six-line body is a form
rather than a description: a reviewer reads the headings, finds a sentence
under each, and learns less than the one paragraph would have told them. A
change too large to describe in twenty lines needs a document in the
repository's documents tree, and a link to it.
Requirements:
Verifiednames actual commands and actual results. "Tests pass" without the command is not verification. If a check was not run, say so.Not coveredis required and may not be empty. WriteNothingonly when you have looked for gaps and found none. One line is a complete answer.- Any test that was changed, removed, or narrowed gets a line explaining why.
- Twenty lines, wrapped at 72 columns. It is the commit body, and the reader
is skimming
git logfor one change among hundreds.
Do not restate the diff. Do not recount the path you took to the change: the dead ends, the thing you tried first, the file you read. A reviewer is deciding about the code in front of them.
Pull request comments
A comment is a reply in a conversation. A hundred words is already long for one, and GitHub soft-wraps, so count words rather than lines.
The harness appends its own footer. That is the harness's line, not a signature; add none of your own.
- Answer the question that was asked. Do not summarize the change again.
- One comment per review pass, not one per finding. The
reviewskill sets what a pass posts. - Say what you changed and where.
Fixed in <sha>beats a paragraph. - Skip the acknowledgement-only comment. Resolving the thread says it.
- No status tables, no progress checklists, no restating the plan. If a reviewer needs the state of the branch, CI is the state of the branch.
Do not
- Pad a body to look thorough. Length reads as effort and costs the reader.
- Narrate the work: what you tried first, what you read, what you ruled out. The result is the deliverable.
- Restate in the pull request what the commits already say, or in a comment what the pull request already says.
- Claim a check ran when it did not.
- Sign a commit body as a model, or name one in it.
- Write a pull request body with headings. It is the commit message.