plugins/sjawhar/skills/centaur-review/SKILL.md
Collaborative code review: you narrate, Claude tracks, challenges your ideas, then we generate a friendly GitHub review together
npx skillsauth add sjawhar/dotfiles plugins/sjawhar/skills/centaur-reviewInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Human-AI collaborative code review. You lead the review by narrating your thoughts as you read the code. Claude tracks your comments, runs background analysis, and when you're done, challenges your suggestions and helps craft a polished GitHub review.
jj workspace note: You may be in a non-default jj workspace with no
.gitdirectory. Ifghcommands fail, setGIT_DIRto point to the default workspace:GIT_DIR=/path/to/default/.git gh pr view ...
1. Parse PR argument (required):
2. Fetch PR context:
gh pr view <pr> --json number,title,body,url,headRefName,baseRefName,additions,deletions,changedFiles,files
gh pr diff <pr>
Store the file list and diff in memory - you'll use this constantly to understand what the user is referring to.
3. Fetch existing reviews and comments:
# Get repo info
REPO=$(gh repo view --json nameWithOwner -q '.nameWithOwner')
# Get all reviews
gh api repos/$REPO/pulls/<number>/reviews
# Get all review comments (line-level)
gh api repos/$REPO/pulls/<number>/comments
# Get conversation comments (top-level)
gh pr view <pr> --comments
Summarize the review history:
For re-reviews, this is critical context. Analyze and categorize:
Detect if this is a re-review:
4. Extract linked issues from PR body:
Fixes #123, Closes #456, Resolves #789linear.app URLs (e.g., https://linear.app/team/issue/TEAM-123)5. Fetch issue details:
gh issue view <number> --json title,body,labels6. Launch background analysis agents (all in parallel, non-blocking):
Launch five Task agents with run_in_background: true. Do not present these results until Phase 3.
Bug Finder (subagent_type: bug-finder):
Find bugs, edge cases, and potential failure modes in this PR:
- Logic errors and incorrect assumptions
- Edge cases that aren't handled
- Error handling gaps
- Race conditions or concurrency issues
- Security vulnerabilities
Focus on significant issues. If nothing notable, say "Nothing to add."
PR diff: [include diff]
Code Simplifier (subagent_type: code-simplifier):
Review this PR for unnecessary complexity:
- Over-engineered solutions
- Abstractions that aren't needed
- Code that could be more elegant or direct
- Opportunities to simplify without losing functionality
Focus on significant issues, not style preferences. If nothing notable, say "Nothing to add."
PR diff: [include diff]
Architecture Reviewer (subagent_type: code-architect):
Review the structural/architectural implications of this PR:
- Does it change how modules interact?
- Does it introduce new patterns or deviate from existing ones?
- Are there changes that affect multiple parts of the codebase?
- Anything that deserves discussion before merging?
If nothing notable, say "Nothing to add."
PR diff: [include diff]
Requirements Checker (subagent_type: general-purpose):
Compare this PR to the linked issue requirements. Identify:
- Requirements that are implemented correctly
- Requirements that are missing or incomplete
- Things the PR does that weren't in the requirements (scope creep?)
- Deviations that might need discussion
If everything looks good, say "Nothing to add."
PR diff: [include diff]
Issue: [include issue body]
CLAUDE.md Compliance (subagent_type: general-purpose):
Check if this PR follows the conventions in the repo's CLAUDE.md file:
- Coding patterns and styles mentioned
- Architectural guidelines
- Testing requirements
- Any other repo-specific rules
First, read the CLAUDE.md file in the repo root (if it exists).
Then check the PR against those guidelines.
If compliant or no CLAUDE.md exists, say "Nothing to add."
PR diff: [include diff]
7. Display summary and enter review mode:
Show the user:
Then prompt: "Ready when you are - start narrating your thoughts as you read through the code."
Track the user's observations as they narrate. Do not show background agent results unless explicitly asked.
Maintain a comment tracker with this structure:
Comments:
1. [file:line] [SEVERITY] - comment text
2. [file:start_line-end_line] [SEVERITY] - comment text (for multi-line)
...
Line numbers must be actual file line numbers (from the new version of the file for additions, old version for deletions). These will be used directly in the GitHub API call.
Use the PR context you fetched. When the user makes an observation:
api.py, models.py, and tests/test_api.py"Never silently guess wrong. It's much better to ask than to track a comment on the wrong file.
api.py:45 as a suggestion 👍"When the user says "ready" or "done":
1. Verify comment locations:
2. Launch Red Teamer:
Use the red-teamer agent (subagent_type: red-teamer) to challenge the user's comments:
The user has reviewed this PR and made the following observations. Your job is to challenge these - push back on anything that might be wrong, questionable, or not actually a good suggestion.
For each comment, consider:
- Is this actually a problem, or is the code correct?
- Could the reviewer be misreading the code?
- Is there context in the PR that explains why it's done this way?
- Would this suggestion actually improve the code, or make it worse?
- Are there counterarguments the PR author might raise?
Be direct. If a comment is solid, say so briefly. If it's weak or wrong, explain why.
User's comments:
[list each comment with file/line and observation]
PR diff:
[include relevant portions of diff]
3. Gather background agent results:
4. Present consolidated findings:
## Your Comments
| # | Location | Severity | Comment | Red Team Notes |
|---|----------|----------|---------|----------------|
| 1 | file.py:42 | BLOCKING | ... | [any challenges] |
| 2 | file.py:55-60 | SUGGESTION | ... | [any challenges] |
## AI Findings Worth Considering
### Bug Finder
[findings or "Nothing notable"]
### Code Simplifier
[findings or "Nothing notable"]
### Architecture
[findings or "Nothing notable"]
### Requirements
[findings or "Nothing notable"]
### CLAUDE.md Compliance
[findings or "Nothing notable"]
---
## Items Needing Your Input
1. [Red teamer challenged comment #2 - do you want to keep it?]
2. [Bug finder found X - should we add this to the review?]
3. [Any other decisions needed]
Then ask: "Take a look and let me know your decisions on the items above."
After the user provides input:
1. Finalize the comment list based on their decisions
2. Write up each line-level comment:
For each comment, format as:
**[Location: file.py:42-45]**
[SEVERITY_BADGE] **[SEVERITY_WORD]**
[Clear, direct observation]
[If suggesting a change, use GitHub suggestion syntax:]
\`\`\`suggestion
[suggested code]
\`\`\`
[Optional: brief rationale or question]
Priorities (in order):
Emojis: Use liberally to lighten tone, especially on critical comments: 😂 😹 😅 🙈 🚀 💪 ⚡ 🤔 👀
Good patterns:
Avoid:
🛑 BLOCKING:
🛑 **Blocking**
I think this could throw an IndexError if `items` is empty - and based on `caller.py:30`, that's a realistic scenario.
\`\`\`suggestion
if not items:
return None
return items[0]
\`\`\`
Let me know if I'm missing context! 😅
💡 SUGGESTION:
💡 **Suggestion**
Would it make sense to extract this into a helper? Similar logic exists in `other_file.py:123` 👀
Just a thought for maintainability - not blocking!
🔍 QUESTION:
🔍 **Question**
Why `dict.get()` here instead of direct access? Is this defensive against a missing key case? 🤔
If so, maybe worth a brief comment for future readers.
😹 NITPICK:
😹 **Nitpick**
The variable name `x` is a bit mysterious - maybe `user_count`?
100% feel free to ignore 🙈
3. Write the top-level summary:
## 🎯 Review Summary
[1-2 sentence overall assessment - be genuine and direct]
### 🚧 Key Discussion Points
- [List BLOCKING and IMPORTANT items briefly]
### 📝 Inline Comments
- 🛑 X blocking | ⚠️ X important | 💡 X suggestions | 🔍 X questions | 😹 X nitpicks
Skip "What's Great" section unless something is genuinely impressive.
Display everything - all line comments followed by the top-level summary.
1. Ask for approval: "Here's the complete review. Ready to post to GitHub?"
2. If approved, post via GitHub API:
First get the commit SHA and repo info:
COMMIT_SHA=$(gh pr view <pr> --json headRefOid -q '.headRefOid')
REPO=$(gh repo view --json nameWithOwner -q '.nameWithOwner')
Post review with inline comments using -f flags with array notation:
gh api repos/$REPO/pulls/<number>/reviews \
--method POST \
-f body="## 🎯 Review Summary..." \
-f event="COMMENT" \
-f commit_id="$COMMIT_SHA" \
-f 'comments[0][path]=src/example.py' \
-f 'comments[0][line]=42' \
-f 'comments[0][body]=💡 **Suggestion**
Consider extracting this...' \
-f 'comments[1][path]=src/other.py' \
-f 'comments[1][line]=89' \
-f 'comments[1][body]=🔍 **Question**
Why is this done this way?'
Comment fields (for each comments[N]):
path (required): File path relative to repo rootline (required): Line number in the file (the new version for additions)body (required): Comment text (markdown supported)That's it. Just path, line, and body. No side, no position, no start_line.
Common errors:
"line" is not a permitted key → You're using the wrong endpoint. Use /pulls/{number}/reviews, NOT /pulls/{number}/commentsHTTP 422 → Check array notation syntax: comments[0][path], comments[0][line], comments[0][body]path matches exact file path from PR diff, and line exists in the new version of the file🛑 DO NOT silently fall back to a plain PR comment. If the API call fails, debug the JSON payload and fix it. The whole point is to post inline comments on specific lines. A single PR comment with all feedback lumped together defeats the purpose.
3. Confirm success:
| User Says | Claude Does | |-----------|-------------| | [narrates observation] | Track comment, infer file/line from PR context (ask if unclear) | | "blocking" / "nitpick" / etc. | Update severity of last comment | | "show comments" | Display current comment list | | "show analysis" | Show background agent findings (only when asked) | | "drop last" | Remove last comment | | "ready" / "done" | Move to Phase 3 (consolidation) | | [after consolidation decisions] | Move to Phase 4 (write up comments) | | "post it" / "looks good" | Move to Phase 5 (post to GitHub) |
Done when: Review is posted to GitHub and link is shared with user.
development
Use when searching flights, hotels, or rental cars; comparing fares across flexible dates; discovering cheap destinations from a fixed origin; or hunting hidden-city ticketing deals. Trigger on multi-city itineraries, fare calendars, "where can I fly cheaply", price-sensitive trip planning, or any time the user wants a sanity-check against Google Flights pricing — Skiplagged surfaces hidden-city deals other engines deliberately hide.
development
Search the web via Ceramic Search (lexical/keyword-based). Use when looking up current events, recent news, time-sensitive facts, specific people/products/companies, technical docs, or any topic requiring fresh web results. Triggers on "search the web", "look up", "find recent", "latest news", "current", or when built-in knowledge is likely stale.
tools
Use when reading WhatsApp messages, searching conversations, sending messages, listing chats, or interacting with WhatsApp workspaces
tools
Watch CI status, fix failures, and merge when green