Fetches and displays PR review comments from GitHub, grouped by priority, and allows the user to reply to or resolve individual threads.
Scanned 5/27/2026
Install via CLI
openskills install Obsidian-Owl/specwright---
name: sw-review
description: Fetches and displays PR review comments from GitHub, grouped by priority, and allows the user to reply to or resolve individual threads.
argument-hint: "[pr-number]"
allowed-tools:
- Read
- Bash
- Grep
- AskUserQuestion
---
# Specwright Review
## Goal
Surface PR review comments, triage autonomously per Google severity framework
(`protocols/decision.md`), draft replies, and present for approval before
posting. When the associated Specwright work can be resolved safely, use
`review-packet.md`, `approvals.md`, and unit evidence as the primary reply
context instead of reasoning from the diff alone. Stateless with respect to
Specwright state — never modifies workflow.json.
Fetch all comment types, group by status, apply autonomous triage:
- Functional issues (API misuse, missing validation): fix code and draft reply
- Nits (style, naming): acknowledge, apply if <2 minutes
- Suggestions: apply if they improve code health, push back with reasoning if not
- Conflicting comments: follow the one most aligned with constitution/spec
The PR itself is the review surface — reviewers see replies directly. When no
associated work can be matched, say so explicitly and use a diff-only fallback.
## Inputs
- `{projectArtifactsRoot}/config.json` — `git.prTool` and `git.baseBranch` settings
- Current branch: detected via `git branch --show-current`
- GitHub PR: discovered via `gh pr list --head {branch}`
- PR comments fetched via `gh api` REST and GraphQL endpoints
- Associated Specwright work when it can be matched safely from PR number or branch:
- `{repoStateRoot}/work/*/workflow.json`
- `{workDir}/review-packet.md`
- `{workArtifactsRoot}/{workId}/approvals.md`
- `{workDir}/evidence/*.md`
## Outputs
- Grouped display of all PR comments by status and type:
- Unresolved threads (highest priority, shown first)
- Open issue comments (general PR conversation)
- Resolved or addressed threads (shown last)
- Each comment shows: author, timestamp, file path, line number (where applicable), and body
- When associated work is available, replies and findings use the review packet,
approval lineage, and evidence as first-class context
- User responses posted via `gh api` POST to the appropriate endpoint
- Resolved threads marked via `resolveReviewThread` GraphQL mutation
## Constraints
**PR detection (MEDIUM freedom):**
- Detect the current branch with `git branch --show-current`. If the result
is empty or HEAD is detached, report the detached HEAD condition and stop.
- Discover the associated PR using `gh pr list --head {branch} --json number,title,url`.
If no open PR is found, retry with `--state merged` as a fallback for merged PRs.
- If multiple PRs are returned and interactive questioning is available, use
AskUserQuestion to disambiguate. In headless mode, use the most recent and
record the fallback choice in output.
- If a PR number is passed as an argument, use it directly instead of detecting
from the current branch.
- Read `config.git.prTool` before invoking `gh`; if the value is not `gh` or is
unset, degrade to URL display. sw-review only supports the `gh` CLI.
**Comment fetching (MEDIUM freedom):**
- Fetch all three comment types via `gh api`:
- Issue comments (general PR conversation): `GET /repos/{owner}/{repo}/issues/{n}/comments`
- Review comments (inline code comments): `GET /repos/{owner}/{repo}/pulls/{n}/comments`
- Thread resolution state: GraphQL query on `reviewThreads` with `isResolved` field.
To correlate: match REST review comment `id` against GraphQL
`reviewThreads.comments.nodes[].databaseId`. If correlation fails, treat
as unresolved.
- Cap fetched comments at 50 per type using `--per-page 50`. If exactly 50
results are returned, assume more may exist and display: "Showing first 50 —
view full thread at {url}." Pagination state is in `Link` response headers,
not in the JSON body.
- Display each comment with: author (`user.login`), timestamp (`created_at`),
file path and line number (`path`, `line`) for review comments, and body text.
**Comment grouping and prioritization (MEDIUM freedom):**
- Present unresolved review threads as the highest priority group at the top.
- Group comments into categories: unresolved threads, general issue comments,
resolved threads. Do not interleave types.
- Within each group, order by timestamp (newest first for unresolved, oldest
first for general comments).
**Associated work context (MEDIUM freedom):**
- Resolve the associated work from PR context by matching the explicit PR
number when provided, then `workUnits[].prNumber`, then the PR head branch
against `workflow.json.branch`. If more than one work matches, report the
ambiguity and fall back instead of picking one silently.
- When a unique associated work is found, load `review-packet.md`,
`approvals.md`, and unit evidence before drafting replies or validating bot
comments.
- Use `review-packet.md` as the primary reviewer-response context. Use
`approvals.md` to verify approval lineage claims and evidence files to verify
gate-status claims. Do not default to diff-only reasoning when these audit
artifacts are available.
- If no work match is available, say so explicitly and use diff-only fallback.
**Responding and resolving (MEDIUM freedom):**
- To post a reply to a review comment, use `gh api` with an HTTP POST:
`gh api --method POST /repos/{owner}/{repo}/pulls/{n}/comments/{id}/replies`.
- To post a new top-level PR conversation comment, POST to
`/repos/{owner}/{repo}/issues/{n}/comments` with a `body` field. Issue
comments have no threading — there is no `in_reply_to_id` for this endpoint.
- To resolve a review thread, call the `resolveReviewThread` GraphQL mutation
via `gh api graphql`. The `gh pr edit` command is for PR metadata only — it
cannot post replies or resolve threads; always use `gh api` instead.
- In clone-local work-artifact mode, replies must quote or paraphrase the
relevant packet/evidence summary instead of depending on local-only file
links. In tracked work-artifact mode, replies may reference tracked audit
artifact paths or sections when that improves reviewer navigation.
- After the user responds, re-fetch the relevant comment to confirm the reply
was posted.
**Graceful degradation without gh (LOW freedom):**
- If `gh` is not available or not installed, degrade gracefully: construct the
PR URL from the `git remote` URL (convert SSH or HTTPS remote to a browser
URL), display it, and inform the user: "Install gh CLI to fetch and respond
to comments from the terminal." Do not abort or STOP — present the URL as a
fallback so the user can open the PR in a browser.
- In headless mode, follow `protocols/headless.md`.
**Stateless utility (LOW freedom):**
- This skill is stateless with respect to Specwright state. It never writes
workflow.json, never claims exclusive workflow ownership, and makes no state
changes to the Specwright workflow. GitHub comment replies and resolutions
are allowed, but the skill never writes Specwright project or runtime state.
- It is not a core workflow stage and never claims top-level work ownership.
- Reading config.json for `prTool` is permitted. No writes to
`{projectArtifactsRoot}`, `{workArtifactsRoot}`, `{repoStateRoot}`, or
`{worktreeStateRoot}`.
## Protocol References
- `protocols/decision.md` — autonomous decision framework (Google severity triage, external reply gate)
- `protocols/git.md` — PR operations, remote URL conventions, gh CLI patterns
- `protocols/evidence.md` — gate evidence as canonical detail
- `protocols/approvals.md` — approval lineage contract
- `protocols/review-packet.md` — reviewer packet contract for reply context
- `protocols/headless.md` — non-interactive execution and result file format
- `protocols/context.md` — logical-root config loading
## Failure Modes
- **Detached HEAD** — `git branch --show-current` returns empty. Report "Cannot
detect branch: HEAD is detached. Check out a branch and try again." Do not proceed.
- **No PR found** — `gh pr list --head` returns no results and the `--state merged`
fallback also returns nothing. Report "No pull request found for branch
`{branch}`" and exit without error.
- **No comments** — PR exists but all three comment type queries return zero
results. Report "No review comments found on this PR." and exit cleanly.
- **Rate limit exceeded** — `gh api` returns HTTP 429, or HTTP 403 with
`X-RateLimit-Remaining: 0`. Surface the error message and the
`X-RateLimit-Reset` time. Ask the user to retry after the reset window.
- **Authorization failure** — `gh api` returns HTTP 403 without rate-limit
headers. Report "Access denied. Run `gh auth status` to check token scopes
and repository access." Do not retry automatically.
- **gh CLI not available** — Degrade gracefully: construct PR URL from remote
URL, display it, and print "Install gh CLI to enable full comment review from
the terminal." Do not abort.
No comments yet. Be the first to comment!