Athena PR Reviewer — Workflow Edition
Background-mode PR review — the default athena reviewer. The heavy lifting (7 parallel Opus specialists + 7 batched Sonnet verifiers + 1 Sonnet synthesis pass) runs inside a Workflow, so main-thread context only sees the curated final report. Prompts and scripts are bundled in this skill (~/.claude/skills/athena-pr-reviewer-workflow/{prompts,scripts}) — no other skill is required.
When to invoke
Any time the user asks to review a PR, branch, or Jira story. Examples:
- "review PR 2923"
- "review this branch"
- "review CSD-2591"
- "workflow review PR 2923" / "background review CSD-2591" / "/athena-workflow"
Progress tracking
Initialize a short todo list:
TodoWrite([
{content: "Resolve PR target", status: "in_progress", activeForm: "Resolving PR target"},
{content: "Resolve repo path", status: "pending", activeForm: "Resolving repo path"},
{content: "Determine PR ownership", status: "pending", activeForm: "Determining PR ownership"},
{content: "Launch workflow", status: "pending", activeForm: "Launching workflow"},
{content: "Wait for completion", status: "pending", activeForm: "Waiting for workflow"},
{content: "Present report", status: "pending", activeForm: "Presenting report"},
{content: "Add main-thread opinion", status: "pending", activeForm: "Forming opinion on findings"},
{content: "Post-review flow (fix walkthrough or verdict + comments)", status: "pending", activeForm: "Running post-review flow"},
])
Update as each step completes.
1. Resolve PR target + Jira ticket
Parse the user's message:
- Explicit PR number (
PR 123,#123): use directly. - Jira ticket (
PROJ-123):gh pr list --search "PROJ-123" --json number --jq '.[0].number'. - Current branch:
gh pr view --json number --jq '.number'. - Otherwise: extract Jira from branch with
git branch --show-current | grep -oE '[A-Z]+-[0-9]+'and search.
If still no PR, ask the user via AskUserQuestion.
Detect the Jira ticket from the PR (only needed if the workflow can't infer it itself, but passing it is cheap and explicit):
gh pr view ${PR_NUM} --json title,headRefName --jq '.title + " " + .headRefName' | grep -oE '[A-Z]+-[0-9]+' | head -1
2. Resolve repo path
The workflow's gather agent runs gh pr view, gh pr diff, and git blame without --repo, so it must be invoked from inside the PR's repo checkout.
Detection order:
- Current working directory: if
git remote get-url originmatches the PR's repo (gh pr view ${PR_NUM} --json url --jq '.url'→ theowner/repoportion), usepwd. - Common locations: search under
~/Projectsfor a.gitwhose origin matches the PR's repo:find ~/Projects -maxdepth 5 -name .git -type d 2>/dev/null | while read g; do d=$(dirname "$g") r=$(cd "$d" && git remote get-url origin 2>/dev/null) if [[ "$r" == *${OWNER}/${REPO}* ]]; then echo "$d"; break; fi done | head -1 - If still nothing, ask via AskUserQuestion for the absolute path.
2b. Determine PR ownership
This decides the post-review flow (section 6). Compare the PR author to the authenticated GitHub user:
PR_AUTHOR=$(gh pr view ${PR_NUM} --repo ${OWNER}/${REPO} --json author --jq '.author.login')
ME=$(gh api user --jq '.login')
# isMine = ( "$PR_AUTHOR" == "$ME" )
Remember isMine (and PR_AUTHOR) for section 6:
isMine == true→ your own PR: run the fix/explain walkthrough (6a).isMine == false→ someone else's PR: give a verdict + offer to comment (6b). Do NOT offer to edit their code.
If the author can't be resolved (deleted account, API hiccup), default to isMine == false (the safer, read-only branch) and note the assumption to the user.
3. Launch the workflow
Workflow({
scriptPath: "~/.claude/skills/athena-pr-reviewer-workflow/workflows/review.js",
args: {
prNumber: <number>,
jiraTicket: "<ticket>",
repoPath: "<absolute path>"
}
})
The tool returns immediately with a runId and task ID. Tell the user the workflow is running in background and they can watch progress in /workflows. Do NOT poll — wait for the task notification.
4. Wait for the task notification
When the notification arrives (a <task-notification> block), parse the result.
If status is failed, surface the error to the user and stop. Common failure: gather agent couldn't run gh (auth / wrong directory).
If status is completed, parse result as JSON. Expected shape:
{
"ok": true,
"prNumber": 2923,
"jiraTicket": "CSD-2591",
"workDir": "/tmp/athena-review-2923",
"reviewersRun": ["comment-analyzer", ...],
"reviewersWithNoFindings": [],
"totals": {
"rawFindings": 64,
"verified": 59,
"partial": 5,
"rejected": 0,
"groupsAfterSynthesis": 24,
"multiReviewerGroups": 6,
"finalAfterConfidenceFilter": 19
},
"themeCounts": {"<theme>": 1, ...},
"findings": [
{
"theme": "...",
"title": "...",
"severity": "Critical|High|Medium|Low",
"confidence": 95,
"reviewers": ["test-analyzer", "requirements-checker"],
"reviewersCount": 2,
"file": "...",
"line": 42,
"issue": "...",
"impact": "...",
"fix": "...",
"memberCount": 5
}
],
"partialFindings": [{"file","line","severity","confidence","issue","fix","reviewer","verdictReason"}]
}
Pull the workflow usage block from the notification (<usage><agent_count><subagent_tokens><tool_uses><duration_ms>) for the stats section.
5. Present the report
Group findings by theme. Within each theme, sort by severity then confidence (workflow already sorts globally; preserve that order when grouping). Format:
# PR Review (workflow): #{prNumber}{jiraTicket ? ` — ${jiraTicket}` : ''}
**Pipeline:** {reviewersRun.length} reviewers → {totals.rawFindings} raw → {totals.verified} verified ({totals.partial} partial, {totals.rejected} rejected by verifier) → {totals.groupsAfterSynthesis} groups → **{totals.finalAfterConfidenceFilter} final** ({totals.multiReviewerGroups} multi-reviewer)
## Findings
### {theme 1}
- [ ] **{severity}** `{file}:{line}` — {title}
- Reviewers: {reviewers.join(', ')} ({reviewersCount})
- Issue: {issue}
- Fix: {fix}
### {theme 2}
...
## Suggestions (partial findings — verifier flagged inaccuracies but core issue is real)
- `{file}:{line}` **{severity}** ({reviewer}, conf {confidence}) — {issue}
- Verifier note: {verdictReason}
- Suggested fix: {fix}
## Workflow stats
- Agents: {agent_count}
- Subagent tokens: {subagent_tokens}
- Tool uses: {tool_uses}
- Wall clock: {duration_ms / 1000}s
- Work dir (debug): {workDir}
Multi-reviewer groups (reviewersCount >= 2) deserve emphasis — they're the strongest quality signal in the pipeline. Surface that fact in the theme heading if applicable: ### {theme} — flagged by N reviewers.
If totals.verified === 0, present a brief "no findings" summary and skip the "My take" section. Then:
isMine→ nothing to address; stop.- not
isMine→ the verdict is a clean Pass; jump to 6b and offer to post an approving / "LGTM" review.
5b. Your opinion (main-thread synthesis)
Before handing control to the user, add your own take. The workflow agents only saw the PR diff + context.md — you have more: the surrounding repo, prior conversation, the user's intent, what's been touched recently, what's reasonable to fix now vs. later. Use that.
After the findings table, write a section like:
## My take
{2-4 sentences. Pick the most important angle.}
- **Worth fixing now:** {findings or themes you'd prioritize, and why — reference file:line}
- **Worth deferring or skipping:** {findings that look real but aren't worth the churn here, and why — reference file:line}
- **Partial findings I'd surface:** {any from the Suggestions section that look genuinely useful}
- **What the workflow may have missed:** {anything you notice that the reviewers couldn't see — e.g. how this PR interacts with code outside the diff, prior decisions in this repo, an in-flight refactor}
Be specific. "All findings look real" is not opinion — it's a non-answer. If you genuinely have no extra signal beyond the report, say so explicitly ("Nothing to add — the report covers it") and move on.
If isMine == false, angle the take toward the merge decision — what actually blocks vs. what's a nit — since it becomes the rationale for your section-6b verdict.
Read files from the repo when needed to ground your opinion (the workflow's workDir artifacts are also available for inspection: reviews/<key>.json, verdicts/<key>.json, synthesis.json).
6. Post-review flow (branches on PR ownership)
Use isMine from section 2b:
isMine == true→ 6a. Fix / explain walkthrough (you're the author — help land fixes).isMine == false→ 6b. Verdict + offer to comment (you're the reviewer — give a verdict and offer to record it on the PR; never edit their code).
The "My take" from 5b feeds both branches — for 6a it prioritizes what to fix; for 6b it's the basis of the verdict.
6a. Your PR — fix / explain walkthrough
After the report, ask via AskUserQuestion:
How would you like to address the findings?
Options:
- Walk through one by one (Recommended): present each theme's findings, decide fix/skip per item.
- I'm done: keep the report, no fixes.
Walk through: Replace todos with one per theme:
TodoWrite([
{content: "Theme 1 ({N} issues)", status: "in_progress", activeForm: "Addressing Theme 1"},
{content: "Theme 2 ({N} issues)", status: "pending", activeForm: "Addressing Theme 2"},
...
])
For each theme, walk through its findings one at a time:
- Present the finding with file:line and current code snippet (Read the file).
- Explain the issue and your opinion.
- Propose a fix.
- Ask: fix or skip?
- If fix: implement, then commit immediately. Do NOT batch changes.
- Move to the next finding.
Once a theme's findings are all addressed (fixed or skipped), mark its todo completed.
Do not accumulate uncommitted changes across findings. Each fix is its own commit (small, isolated, easy to revert).
Done: stop. The report stands as-is.
6b. Someone else's PR — verdict + offer to comment
You're the reviewer, not the author. Do not edit their code or offer to. Instead give a verdict and offer to record it on the PR.
Step 1 — Decide a verdict (your recommendation, grounded in the "My take" opinion):
- Request changes — any VERIFIED finding is Critical or High (or a High flagged by ≥2 reviewers). Something in this PR should not merge as-is.
- Pass — only Medium/Low findings, or none. Note remaining nits but nothing blocking.
Present it on its own line with one sentence of rationale:
## Verdict: Request changes
{one-sentence rationale — name the blocking finding(s) by file:line}
Step 2 — Offer to record it via AskUserQuestion:
I recommend {verdict}. How should I record this on PR #{prNumber} by @{PR_AUTHOR}?
Options:
- Post a review with inline comments (event = {verdict}) — (Recommended) one PR review: each finding as an inline comment on its
file:line, plus a summary body carrying the verdict + any findings that don't map to a diff line. - Post one summary comment — a single general PR comment with all findings + verdict, no approval state.
- Don't post — verdict + opinion stay in this chat.
(The user can pick "Other" to flip the verdict — e.g. "post it but as Approve".)
Step 3a — Post a review with inline comments. Map verdict → event: Request changes → REQUEST_CHANGES, Pass → APPROVE (or COMMENT if the user prefers not to approve). Build the payload — inline comments only for findings whose file + line fall inside the PR diff (a line outside the diff makes GitHub reject the whole review with 422). Put line: null findings, partial findings, and anything off-diff into the body instead.
Write the payload to ${workDir}/pr-review-payload.json:
{
"event": "REQUEST_CHANGES", // or APPROVE / COMMENT
"body": "## Athena review — {verdict}\n\n{summary + any off-diff findings, markdown}",
"comments": [
{ "path": "src/foo.ts", "line": 42, "side": "RIGHT",
"body": "**High** — {issue}\n\nSuggested fix: {fix}" }
]
}
Post it:
gh api --method POST repos/${OWNER}/${REPO}/pulls/${PR_NUM}/reviews \
--input ${workDir}/pr-review-payload.json
If it fails with 422 (a comment line isn't in the diff), move the offending comment(s) into body and retry, or fall back to Step 3b. Report the posted review URL from the API response.
Step 3b — Post one summary comment. Build the same findings + verdict as markdown and post a single general comment:
gh pr comment ${PR_NUM} --repo ${OWNER}/${REPO} --body-file ${workDir}/pr-comment.md
Step 3c — Don't post. Stop; the verdict stands in the conversation.
Confirmation: posting a review, an approval, or a comment is an outward-facing action on someone else's PR — only do it through the AskUserQuestion choice above. Never post without that explicit selection.
Examples
User: "workflow review PR 2923" (PR authored by the user)
- PR 2923, Jira CSD-2591 extracted from title
- Repo path resolved (cwd or search)
- Ownership:
author == me→isMine = true - Workflow launched, runId returned
- Wait for notification (typically 3-8 min from scratch, faster on resume)
- Themed report + "My take" presented with multi-reviewer emphasis
- 6a — offer the fix/explain walkthrough
User: "review PR 4102" (PR authored by a teammate)
- PR 4102 resolved
- Repo path resolved
- Ownership:
author != me→isMine = false - Workflow launched → report + "My take" presented
- 6b — verdict (e.g. "Request changes" for a High finding), then offer to post a review with inline comments, a summary comment, or nothing
User: "background review CSD-2591"
gh pr list --search CSD-2591→ PR found- Repo lookup → ownership check → workflow launched
- Same flow as above, branching on ownership
User: "review PR 2923"
- Same flow — this is the default reviewer. No workflow keyword needed.
Notes
- The workflow's
args.prNumberis required;args.repoPathis required.args.jiraTicketis optional but recommended. - Resume support: if a workflow needs to be re-run after a script edit, invoke with
{scriptPath, resumeFromRunId: "<id>"}. Completed agents return cached results instantly. - The workflow does NOT use external LLMs (Gemini/Codex) in v1. Only the 7 Claude specialists.