Skip to main content

pr-reply

Post replies to PR review comments from a manifest, read each back, and resolve its thread only on a match. Use when a workflow or agent must answer bot or human review comments on a pull request.

Source facts

Repository
hathach/agentrc
Last source activity
October 7, 2026 at 06:09
Detected SKILL.md language
English
Stars
1
Forks
2

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
pr-reply
description
Post replies to PR review comments from a manifest, read each back, and resolve its thread only on a match. Use when a workflow or agent must answer bot or human review comments on a pull request.
# Replying to PR review comments `scripts/reply.py` is the only way a reply reaches a PR. It takes a manifest of `{commentId, body, digest}` entries and, for each: finds which of three things on the PR the id names (an inline review comment, an issue comment, or a review whose body carries the finding), reuses an identical reply of ours if one is already there, otherwise posts the body once, reads the posted comment back, and resolves the review thread only when body, thread, author and PR all match. An issue comment and a review body have no thread: the reply is a PR comment quoting the original's URL, and nothing is resolved. Any other reply of ours to the comment (in its thread after it, or quoting it) blocks the post: its receipt names that reply with `verified: false`, for the caller to reconcile. An entry with `"secondAnswer": true`, for a comment edited after we answered it, may go beside our inline reply; a quoting reply of ours that gives the same kind of answer (a `Fixed in ` note, or anything else) still blocks it. Its receipts are the evidence; a `201` from GitHub is not. ```bash R=~/.claude/skills/pr-reply/scripts/reply.py python3 $R --pr <N> --manifest <file.json> # file.json: {"replies": [{"commentId": 4013179956, "body": "...", "digest": "<8 hex>"}]} python3 $R --digest "$body" # the digest of a body, for a manifest written by hand python3 $R --pr <N> --inspect <commentId>:<replyId> ... # read our replies, post nothing python3 $R --pr <N> --inspect <commentId> # our newest reply; its `original` and `originalDigest` too, # also on exit 1 "no reply of ours": how to read the comment itself python3 $R --pr <N> --reuse <file.json> # file.json: {"reuses": [{"commentId": ..., "replyId": ..., "bodyDigest": "...", "originalDigest": "..."}]} python3 $R --pr <N> --edit <file.json> # file.json: {"edits": [{"commentId": ..., "replyId": ..., "body": "...", "digest": "...", "bodyDigest": "...", "originalDigest": "..."}]} python3 $R --pr <N> --manifest <file.json> --receipt <path> # also --reuse, --edit: replay a saved run ``` Every entry carries the body's digest (FNV-1a, 32-bit, over code points); the script refuses an entry whose body does not match it, so a body copied wrong never reaches the PR. A workflow computes the digests itself; by hand, use `--digest`. A reply's digest, in a receipt, an inspection or a `--reuse` or `--edit` entry, is always its text's, the quote line left out, so a posting receipt's `digest` settles that reply under `--reuse`. The original's digest is `scripts/comment_digest.py`'s, the one pr-babysit harvests with: what CodeRabbit rewrites at its comment's end does not change it. An inspection or a saved receipt from before these rules may carry an older digest: inspect again, with a fresh receipt path. The last stdout line is `{"receipts": [...], "seal": ...}`, one receipt per manifest entry (the seal is pr-babysit's check that a relayed copy is exact): `kind` (`review`, `issue` or `review-body`; `none` when all three were searched and the id is on none of them, so the caller owes it nothing; `null` when a lookup failed before that was known), `replyId`, `digest`, `sent` (a POST was issued; with `replyId` null the response was lost and the reply may exist), `posted` (false when an identical reply was reused), `verified` (true, false on a mismatch, null when the read-back could not be fetched), `resolved` (true when the thread was resolved, false when GitHub refused to resolve it, left out when unknown: for the two kinds without a thread, or when an API error cut the resolve short), `error` (left out when there is none). Exit 0 when every reply is verified and every review thread resolved, 1 otherwise, 2 for a bad manifest or an unreachable repo. `sent` and `posted` describe the run that recorded them, so a rerun that finds its earlier post reports both false; `verified` and `resolved` say whether the reply stands. A caller that may lose a run's output passes `--receipt <path>`: the same path again to get that run's receipt back, a fresh path when the replies must be read back anew. ## Judgment - **The body is the caller's.** Write the manifest with the exact text you were given; do not paraphrase, shorten, quote or annotate it. A reply that is a PR comment gets the original's URL as a quote line above the text, so the reader can find what it answers; the script adds that itself. - **Once.** Never post or edit by hand with `gh api`, never a trial or placeholder comment, never a delete. If a run's outcome is unknown, run the script again with the same manifest: it reuses what it finds and posts only what is missing. - **Receipts, verbatim.** Return the JSON line unchanged to whoever asked. A receipt with `verified: false` and a `replyId` is a reply that exists with the wrong content; that is a repair, not a reason to post again. It is settled on that reply only when someone judged the body `--inspect` returned to answer every point the comment is owed now: `--reuse` with the digests from that inspection reads both again, posts nothing and resolves the thread. A reply your task's own recorded attempt posted may instead be put right with `--edit`, the offered body or an evidence-backed correction of it, and the same inspection's digests: it reads both again, edits only that reply, reads it back and resolves the thread. Otherwise it stays for the caller. - **A reply is not agreement.** A resolved thread means our answer was published, not that the reviewer accepted it; what the reviewer says next is a new comment to read, not something this script knows about.
View on GitHub