pr-suggestion
Skill2 starsChanged 6 months agoApache-2.0View on GitHub
Post a GitHub review comment as an applyable "suggested change" — a ```suggestion block the author commits with one click — and, first, decide whether a finding should be a suggestion at all. `gh` has no native support for inline comments or suggestions, so this drives the REST reviews API directly. Use when a finding is a small, literal edit to a line the PR already changed. It is deliberately the WRONG tool for structural, additive, or unchanged-context findings; the decision rule below tells them apart so you never post an unappliable "Commit suggestion" button.
In this repository43 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- break-glassSkill
- claim-ledgerSkill
- contract-parity-auditSkill
- counterfactual-auditSkill
- design-doc-reviewSkill
- diagram-gen-emergentSkill
- diagram-gen-specSkill
- doc-triageSkill
- explain-workSkill
- feature-implSkill
- finding-triageSkill
- first-party-auditSkill
- gh-token-rotateSkill
- handoffSkill
- implementSkill
- jj-stackSkill
- linear-escalation-triageSkill
- mache-usageSkill
- park-workSkill
- pr-boardSkill
- pr-bucketsSkill
- prior-art-cartographerSkill
- problem-decomposerSkill
- pr-review-kitSkill
- pr-reviewSkill
- readme-restructureSkill
- repo-description-polishSkill
- repo-homepage-setSkill
- repo-social-previewSkill
- repo-topic-taggerSkill
- review-prepSkill
- review-queueSkill
- reviewSkill
- self-auditSkill
- structural-pr-reviewSkill
- surveySkill
- taskfile-ci-paritySkill
- test-fidelitySkill
- workflow-auditSkill
- work-scopeSkill
- writing-pr-descriptionsSkill
The file
We split this skill into the rules it gives an agent
3 rules. About 0 are common, 2 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 55
If it fails the rule: post a normal described comment (or hand a git apply patch for larger structural/additive fixes).
- Very specific: line 137
Only lines printed with a + by this walk are addable/changed and therefore anchorable.
- Distinctive: line 230
Don't batch unrelated suggestions into one giant review: if the author is iterating round-by-round.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
pr-suggestion — turn a review finding into a one-click applyable change
The spine, one question:
Is this finding a literal replacement of a line the PR already changed? If yes, post it as a
suggestionso the author applies it with one click. If no, post a described comment — a suggestion here would be broken or wrong.
Posting gate (repo-wide rule, same as pr-review-kit): nothing in this skill is posted to GitHub without explicit human authorization. Prepare the payloads, show what will be posted and where, and call the API only on an explicit go.
A suggestion is a gift when it fits and a trap when it doesn't. A wrong or unappliable suggestion is worse than a clear description: the author clicks "Commit suggestion," gets a broken commit or a no-op, and learns to distrust your review. Match the tool to the finding.
The suggestability decision rule (run this before writing anything)
A finding is suggestable only if all three hold:
- In-diff — the line(s) you'd replace are on the RIGHT side of the diff (added/changed in the PR head). Unchanged context lines cannot host a suggestion at all — the API rejects them.
- Contiguous — the fix is one continuous line range, not edits scattered across the file. A suggestion replaces exactly the anchored range.
- Literal replacement — you can write the full new text for that range. A suggestion is a verbatim swap, not a diff or an instruction.
| Finding shape | Suggestable? | Why |
| Wrong constant / operator / off-by-one on a changed line | ✅ yes | literal edit, in-diff, contiguous |
Missing nil/error check right after an added line | ✅ (append trick) | replace the added line with itself + the new line |
| Rename a field the PR introduced | ✅ if contiguous | literal, in-diff |
| Change happens in code the PR didn't touch | ❌ no | not in the diff — nothing to anchor |
| Architectural swap spanning multiple regions | ❌ no | not contiguous |
| Add a whole new function/test out of band | ❌ (usually) | addition, not replacement — describe or hand a patch |
If it fails the rule: post a normal described comment (or hand a git apply
patch for larger structural/additive fixes). Do not force a suggestion.
What the comment around the fence says
A suggestion ships with prose above the fence, and that prose is the review. The fence says what to change; the sentence above it is the only place the author learns whether they have to, and why:
<!-- @include-begin _shared/comment-craft.md -->Every finding carries a severity tag whose merge impact is explicit, so the author never has to guess whether a comment is a gate or a thought:
| Tag | Means | Merge impact |
[Blocking] | Correctness, security, or data integrity. | Blocks merge. |
[Non-blocking] | A real improvement, the author's call. | Does not block. |
[Question] | A design clarification — you may be the one missing context. | Does not block. |
[Observation] | Informational, for the next reader. | No action implied. |
Lead with the TL;DR in plain language, before any detail: what you found, whether it blocks, and what you would do. Burying the verdict under three paragraphs of trace makes the author read the whole comment to learn it was a nit.
Frame findings as questions rather than commands — "It looks like X — would it be worth considering Y?" rather than "You should do X." The imperative is only honest when you are certain, and you are certain less often than you feel; the question costs the same characters and leaves the author room to answer "no, because…" without it reading as defiance.
Every finding cites evidence: a file:line, another PR, a ticket, a doc URL, or the output of an experiment you actually ran. A finding with no citation is an opinion wearing a severity tag.
Never flag style, formatting, or naming. The formatter and the linter own those. A review that spends its first three comments there teaches the author to skim the rest of it.
Match the tone to the author. Someone senior in this code wants the mechanism and nothing around it; someone newer needs the why and a pointer to the pattern the codebase already uses. The finding is identical either way — only the scaffolding changes.
<!-- @include-end _shared/comment-craft.md -->The severity tag matters more here than anywhere else, because a one-click
"Commit suggestion" button reads as an instruction whatever the words say. A
[Non-blocking] suggestion the author declines should cost them one click of
"dismiss," not a justification.
Why gh can't, and what to use instead
gh pr review only sets a top-level body (--body/--comment) — no inline
comments, no suggestions. Inline comments (suggestions included) go through the
REST API:
- New review with suggestions:
POST /repos/{owner}/{repo}/pulls/{N}/reviewswith acomments[]array; each comment'sbodycontains the fence. - Turn an existing inline comment into a suggestion:
PATCH /repos/{owner}/{repo}/pulls/comments/{comment_id}with a newbody.
A suggestion is just an inline comment whose body is:
```suggestion
<the full replacement text for the anchored line(s)>
```Procedure
1. Find the anchor (the RIGHT-side line number in the diff)
The line must be a changed line in the head commit. Discover it from the diff
rather than guessing — line numbers drift:
gh pr diff <N> --repo <owner/repo> --patch | awk '
/^diff --git/ { f=$3; sub(/^a\//,"",f) }
/^@@/ { match($0,/\+[0-9]+/); rl=substr($0,RSTART+1,RLENGTH-1)+0; next }
/^\+/ && !/^\+\+\+/ { print f":"rl": "substr($0,2); rl++; next }
/^ / { rl++ }' # context lines advance the RIGHT counter but are NOT anchorableOnly lines printed with a + by this walk are addable/changed and therefore
anchorable. If your target isn't in the list, it's unchanged context → not
suggestable (see the rule).
2. Build the payload with jq (never hand-escape)
The fence content has backticks, quotes, and newlines — assemble with jq
--rawfile so escaping is correct. Write each comment body to a file first.
Single-line suggestion (replaces one line):
jq -n --rawfile s1 body1.md --rawfile summary summary.md '
{ event:"COMMENT", body:$summary, comments:[
{ path:"path/to/file.go", line:42, side:"RIGHT", body:$s1 }
]}' > payload.json
gh api repos/<owner>/<repo>/pulls/<N>/reviews --input payload.jsonA comment body that IS a suggestion (body1.md):
Off-by-one: the cap is inclusive, so this should be `<=`.
```suggestion
if requested <= maxPageSize {
```Multi-line suggestion (replaces a range) — add start_line:
{ "path":"f.go", "start_line":40, "line":42, "start_side":"RIGHT", "side":"RIGHT", "body":"...fence..." }The fence must contain the full replacement for lines 40–42 inclusive.
Addition-append trick (a suggestion can only replace, so to add a line, anchor to a real changed line and include it plus the new content):
```suggestion
existingAddedLine := foo()
if existingAddedLine == nil { return errX } // the line you're adding
```3. Choose the review event
COMMENT— deliver suggestions without approving (default when unsure; never infer approval).APPROVE/REQUEST_CHANGES— only when the human said so. Suggestions attach to any event, including a laterPATCHonto an existing review comment.
4. Verify it landed
gh api repos/<owner>/<repo>/pulls/<N>/comments \
--jq '.[] | select(.user.login=="<me>") | "\(.path):\(.line) \(.body[:60])"'Confirm the comment shows the ```suggestion fence and sits on the intended line.
Automation — scripts/pr-suggest.sh
The mechanics above (anchor discovery → validate in-diff → build payload → post →
verify) are deterministic and live in scripts/pr-suggest.sh. The script owns
the mechanical half and enforces the in-diff gate — it refuses (nonzero
exit) if --line is unchanged context, so an unappliable "Commit suggestion"
button is impossible to post. What it does not decide stays with you: whether
the finding is suggestable at all (the rule above), the replacement text, and
whether to APPROVE.
# Preview (dry-run by default — posts nothing):
pr-suggest.sh --pr owner/repo#N --file path/f.go --line 42 \
--replacement /tmp/fix.txt [--start 40] [--note /tmp/why.md]
# Post it (COMMENT review) once you've eyeballed the payload:
pr-suggest.sh --pr owner/repo#N --file path/f.go --line 42 \
--replacement /tmp/fix.txt --note /tmp/why.md --postSplit of labor: the script is ~90% of this skill (the reproducible I/O + the
enforceable gate); the prose above is the ~10% it can't decide — should this be
a suggestion, and what should it say. Run --dry-run (the default) and read the
payload before --post; the dry-run output is also the canonical example of a
well-formed suggestion payload.
Gotchas
- Unchanged context is unanchorable. The single most common mistake: the ideal fix lives in code the PR didn't touch. You cannot suggest there. Anchor the comment to the nearest changed line that carries the same intent and describe the fix, or hand a patch.
- Stale head. A suggestion is bound to a commit; if the PR head moves, the suggestion (and any approval) may be dismissed. Post against the current head.
- Exact bytes matter for the surrounding code, not the fence. The fence is a replacement, so its indentation must match the file's (tabs vs spaces). Copy the leading whitespace from the target line.
sidedefaults to RIGHT; only setLEFTto comment on a deleted line (you cannot suggest on a deleted line — there's nothing to replace).- Don't batch unrelated suggestions into one giant review if the author is iterating round-by-round; small, per-line suggestions are easier to accept or reject individually.
Cross-references
- Upstream:
structural-pr-review/pr-review-kitproduce the findings; this skill is the posting mechanic their gated Phase-8 step can call for the findings that pass the suggestability rule. - Sibling: for structural/additive findings that fail the rule, hand a
verified
git applypatch instead (build + test it first), or leave a described comment.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

