| name | respond-to-comment |
| description | Triage and respond to comments on a PR. Fix if actionable, reply either way. Load repo-setup first. |
| license | Apache-2.0 |
| metadata | {"audience":"autonomous-agents"} |
Respond to Comment
Triage a comment on a PR the bot is involved in. Load repo-setup first.
Addressing guard
Before triaging, confirm the comment is actually for you:
- If the comment author equals your identity (
$ME — see agent identity
setup), stop: SKIPPED: own comment.
- If the body explicitly
@-mentions a specific other user and does NOT
@-mention $ME, the question is aimed at someone else — stop:
SKIPPED: directed at @<user>. Applies to inline and top-level
comments alike. Exceptions (keep going): the comment also @-mentions
$ME, it's a direct reply to one of your own comments, or it's a
comment on a jared-labeled issue (the router resumes resolve-issue
for those, so answers to your own questions are never dropped even if
they @-mention a helper).
- A comment with no
@-mention of another user is not affected by this
guard — proceed to triage as normal.
Triage
Default to doing what the reviewer asked. A concrete request on your own PR
is an instruction to carry out, not a proposal to debate.
- Actionable: any direct change request, real bug, missing test, or valid
concern → fix it and push.
- Genuinely not actionable: only when the request would clearly break
something, contradict an explicit project rule, or is factually wrong. Reply
with one short, specific reason; if the reviewer repeats the request, do it.
- Approval thumbs-up (short body, no code refs): don't reply, stop
Don't push back — do the work
- Never argue the same point twice. A restated request is a cue to act, not to
re-explain the original choice.
- Do not declare a requested change out of scope when the reviewer has
explicitly expanded the scope. Investigate and implement the smallest safe
path.
- Before responding to review feedback, enumerate unresolved review threads and
work through each one. Do not leave a thread unresolved without either a
pushed fix or a one-line reason and a human owner.
gh api graphql --paginate -f query='query($o:String!,$r:String!,$n:Int!,$endCursor:String){repository(owner:$o,name:$r){pullRequest(number:$n){reviewThreads(first:100,after:$endCursor){nodes{isResolved path comments(first:1){nodes{databaseId author{login} body}}}pageInfo{hasNextPage endCursor}}}}}' \
-f o=<OWNER> -f r=<REPO> -F n=<N> \
--jq '.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved==false) | {path,body:.comments.nodes[0].body[0:80]}'
Workflow
-
Check PR authorship — only push to your own PR's branch.
-
If actionable on your own PR: implement the fix, load deslop, commit, and
push. Verify the remote branch contains the same commit before replying:
git push origin HEAD
test "$(git rev-parse HEAD)" = "$(git rev-parse @{u})"
Then reply on the thread with the commit SHA, resolve the thread (see below),
and leave one 🎉 reaction on the triggering comment. After all fixes, request review only after required checks are green.
-
If actionable on someone else's PR: reply with a suggestion block
or description. Don't push.
-
If not actionable: reply on the thread with the reason and leave it open
for a human to resolve.
Durable discussion inbox
The webhook prompt can include a PR discussion inbox. Those are durable
messages that still need a real response, even if they arrived before the
current event or were compacted out of the conversation history.
- Inspect the live PR and answer every inbox item in its correct GitHub
channel. Do not send generic acknowledgements, status-only comments, or a
canned reply. The response must address that author's actual question.
- Choose the outcome from the work you did:
addressed after a fix, explained
after a considered answer, or needs-human after asking the one concrete
decision you cannot safely make.
- After the substantive response, append the exact hidden marker shown for that
item:
<!-- jared-discussion:<ID>:<outcome> -->. GitHub delivers your reply
back to Outpost, which verifies this marker and removes only that item from
the inbox. Never add a marker before the visible response exists.
- An inline thread is resolved only after a real code fix. An explanation or
needs-human response deliberately leaves it open for the reviewer.
Ownership, not advisement
For an actionable item on your own PR, carry the work through the workflow
yourself. Do not ask whether to push, offer a copy-paste patch, or stop at a
test plan when you can make the bounded change. A short acknowledgement of a
fix you proposed — including “yes”, “do it”, or “take control” — means execute
the fix now, not propose it again.
Before committing, run the relevant checks and review the resulting diff. If
they reveal another bounded problem, fix and re-check it before replying. Ask a
human only for a genuine blocker: contradictory requirements, missing authority,
or no safe, defensible implementation after investigation.
Replying to comments
There are two kinds of comments — reply to each in its own channel. Never
use gh pr comment to answer an inline review comment; that posts a
top-level PR comment that isn't attached to the thread.
Inline review comment (pull_request_review_comment, or a comment inside a
pull_request_review) — reply on the thread via the replies endpoint:
gh api -X POST \
"repos/<OWNER>/<REPO>/pulls/<N>/comments/<COMMENT_ID>/replies" \
-f body="Fixed in <SHA>."
<COMMENT_ID> must be the top-level comment of the review thread — the one
with in_reply_to_id unset; GitHub does not support replies to replies. For a
durable inbox item, use the supplied top-level comment ID, not the message
ID shown in parentheses.
Top-level PR comment (issue_comment on a PR, not tied to a line) — reply
with:
gh pr comment <N> --body "..."
Completion reaction
Once the requested work is actually complete (not when it is skipped or
blocked), add one 🎉 reaction to the original trigger:
gh api -X POST repos/<OWNER>/<REPO>/pulls/comments/<COMMENT_ID>/reactions -f content=hooray
gh api -X POST repos/<OWNER>/<REPO>/issues/comments/<COMMENT_ID>/reactions -f content=hooray
gh api -X POST repos/<OWNER>/<REPO>/issues/<NUMBER>/reactions -f content=hooray
Resolving a thread (only after you fixed it)
Resolve a review thread only when you pushed a code change that addresses
it. Leave won't-fix / not-actionable threads open with an explanatory reply.
-
Find the thread node id for the comment you addressed:
THREAD_ID=$(gh api graphql --paginate -f query='
query($owner: String!, $repo: String!, $pr: Int!, $endCursor: String) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $pr) {
reviewThreads(first: 100, after: $endCursor) {
nodes { id isResolved comments(first: 1) { nodes { databaseId } } }
pageInfo { hasNextPage endCursor }
}
}
}
}' -f owner=<OWNER> -f repo=<REPO> -F pr=<N> \
--jq '.data.repository.pullRequest.reviewThreads.nodes[]
| select(.comments.nodes[0].databaseId == <COMMENT_ID>) | .id')
-
Resolve it:
gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: { threadId: $threadId }) {
thread { isResolved }
}
}' -f threadId="$THREAD_ID"
Re-requesting review
After pushing fixes for a reviewer's feedback, check the required checks:
gh pr checks <N> --required
Do not re-request review or describe the PR as ready while required checks are
pending or failing. Leave it open for the CI-completion webhook to resume the
work. Only re-request review after required checks are green:
gh api -X POST "repos/<OWNER>/<REPO>/pulls/<N>/requested_reviewers" \
-f "reviewers[]=<REVIEWER_LOGIN>"
Keep replies concise and natural — write like a teammate, not a
support bot. No filler phrases, no emoji unless the thread uses them.
Don't push to others' branches. Don't force-push. Don't merge.