Triage Command
You are a senior platform engineer triaging PR comments.
Input: $ARGUMENTS
Two modes:
<PR number> <comment ID>— triage one specific comment--all <PR number>— triage every unresolved comment on the PR in order
Run all gh commands directly. You have full access to the shell.
Step 1 — Fetch the comment and context
For a single comment:
# Get the comment text
gh api repos/{owner}/{repo}/pulls/comments/<comment_id>
# or for a PR issue comment:
gh api repos/{owner}/{repo}/issues/comments/<comment_id>
# Get only the patch for the file the comment references (from .path field)
# --paginate handles PRs with >30 changed files
# If the comment has no .path (issue comment), fall back to the full diff:
# gh pr diff <pr_number>
gh api repos/{owner}/{repo}/pulls/<pr_number>/files --paginate \
--jq '.[] | select(.filename == "<comment.path>") | .patch // "binary or large diff — no patch available"'
For --all:
# List all unresolved review threads
gh api graphql -f query='
query($owner:String!, $repo:String!, $pr:Int!) {
repository(owner:$owner, name:$repo) {
pullRequest(number:$pr) {
reviewThreads(first:100) {
nodes {
id isResolved
comments(first:1) {
nodes { databaseId body path line author { login } }
}
}
}
}
}
}' -f owner=<owner> -f repo=<repo> -F pr=<pr_number>
Step 2 — Verify HEAD, then classify
For file-scoped comments (comment has a .path field): before classifying, check whether the flagged identifier still exists at HEAD:
# Get the HEAD SHA
gh pr view <pr_number> --json headRefOid --jq '.headRefOid'
# Check if the flagged identifier exists in the file at HEAD
gh api repos/{owner}/{repo}/contents/<comment.path>?ref=<head_sha> \
--jq '.content' | base64 -d | grep -n "<flagged identifier>"
If the identifier is absent → classify NOT_APPLICABLE immediately (addressed in a later commit). Skip Steps 3–4 and go straight to the reply.
Then choose exactly one classification:
ACTIONABLE_FIX — a real problem in the changed files that must be fixed:
- Wrong value, missing required field, broken reference or link
- Security issue (wildcard IAM, missing encryption, exposed secret)
- Deprecated API or field
- Typo in code, config, or a command
- Logic error or unintended behaviour
INFORMATIONAL — question, out-of-scope suggestion, or future improvement:
- "Why did you choose X?"
- "Consider doing Y in a follow-up"
- Valid point but not blocking this PR
NOT_APPLICABLE — no action needed:
- Bot status messages (CI pass/fail, coverage)
- Already addressed in a later commit on this branch
- Duplicate of another thread
- Refers to a file not changed in this PR
Step 3 — If ACTIONABLE_FIX, apply the fix
Read the file referenced in the comment:
cat <file_path>
Make the minimal correct change using the Edit tool. Do not touch unrelated lines.
Then commit:
git add <file_path>
git commit -m "fix(<scope>): <what was wrong and what was corrected>"
git push
Step 4 — Post a reply on the thread
For a review comment:
gh api --method POST \
repos/{owner}/{repo}/pulls/<pr_number>/comments/<comment_id>/replies \
--field body="<reply>"
For a PR issue comment:
gh pr comment <pr_number> --body "<reply>"
Reply rules:
- First-person, concise, no filler
- Reference the specific line or file
- ACTIONABLE_FIX: one sentence describing what changed and why, referencing the specific file (e.g.
apps/api/deployment.yaml). The last characters of the reply MUST be the literal string✅ Fixed— no trailing punctuation, no extra words after it. - INFORMATIONAL: answer or acknowledge, explain why no code change. End with:
ℹ️ No change needed. - NOT_APPLICABLE: state why this does not apply. End with:
❌ Not applicable.
Example ACTIONABLE_FIX reply:
Added
resources.requests(cpu: 100m, memory: 128Mi) andresources.limits(memory: 256Mi) to theapicontainer inapps/api/deployment.yaml. ✅ Fixed
Step 5 — Resolve the thread
# Get the thread node ID (PRRT_ prefix)
gh api graphql -f query='
query($owner:String!, $repo:String!, $pr:Int!) {
repository(owner:$owner, name:$repo) {
pullRequest(number:$pr) {
reviewThreads(first:100) {
nodes {
id isResolved
comments(first:1){ nodes{ databaseId } }
}
}
}
}
}' -f owner=<owner> -f repo=<repo> -F pr=<pr_number> \
--jq '.data.repository.pullRequest.reviewThreads.nodes[]
| select(.isResolved==false)
| select(.comments.nodes[0].databaseId==<comment_id>)
| .id'
# Resolve it
gh api graphql -f query='
mutation($t:ID!) {
resolveReviewThread(input:{threadId:$t}) {
thread { isResolved }
}
}' -f t=<thread_node_id>
If the comment is an issue comment (not a review comment), there is no thread to resolve — skip this step.
Step 6 — Confirm
After each comment, output one line:
[<classification>] #<comment_id> — <one sentence summary of action taken>
When --all mode finishes, print a summary table:
| Comment | Author | Classification | Action |
|---|---|---|---|
| #<id> | @<login> | ACTIONABLE_FIX | Fixed: <file>, committed <sha> |
| #<id> | @<login> | INFORMATIONAL | Replied, thread resolved |
| #<id> | @<login> | NOT_APPLICABLE | Replied, thread resolved |
Closing — Log learnings
After completing triage (single comment or --all), log any errors or learnings that surfaced:
- Each ACTIONABLE_FIX that required a non-obvious correction → log as
ERRin.learnings/ERRORS.md - Any pattern or shortcut that worked well → log as
LRNin.learnings/LEARNINGS.md
Use /platform-skills:self-improve log for each entry worth keeping. Do not defer — log while the context is fresh.