Implement Phase 1: AI-powered code review - #146
Conversation
Add automatic AI code review infrastructure per the plan in docs/plans/ai-code-review-bots-plan.md (#134). New files: - action/build-review-prompt.sh: Builds structured review prompts from PR metadata, diffs, and file contents. Respects .egg/review-rules.md for per-repo customization. Selects model (haiku vs opus) based on PR size. - action/post-review-comments.sh: Parses Claude's JSON review output and posts GitHub PR reviews with inline comments. Dismisses previous bot reviews to avoid clutter. Modified files: - action/action.yml: Add prompt-file input for large prompts - action/entrypoint.sh: Read prompt from file when prompt-file is set Note: The workflow file (.github/workflows/on-pull-request.yml) is included in this branch but requires manual merge due to GitHub App workflow permission restrictions. Issue: #134 Related: #70 (security linters), #77 (autofixers) Authored-by: egg
|
@james-in-a-box rlecting on this a bit more, does it actually make more sense to have the structured output that we pass along as a PR review, or to just let the bot post on its own seeing as it has full read write access to the PR? For example, the bot can do a broader analysis of the codebase or integrate internal research, run tests to validate its findings, etc. Do we really want to limit the bot by sticking with this structured output format? Can we support a sufficiently broad use case with this? Can we support inline comments, change suggestions, etc? |
|
Good question — this gets at a fundamental architectural choice. Let me lay out the trade-offs: Current approach: Structured output → post-processingPros:
Cons:
Alternative: Let the bot post directlyPros:
Cons:
My recommendationI think the current structured approach is the right starting point for Phase 1, but we should design it to be extensible:
{
"file": "path/to/file",
"line": 42,
"severity": "suggestion",
"category": "quality",
"comment": "Consider using a context manager here",
"suggestion": "with open(path) as f:\n data = f.read()"
}GitHub's review API supports suggestion blocks: This keeps the structured approach but enables richer feedback. Bottom line: I'd ship Phase 1 as-is (structured output) since it works and is testable. Then we can add a Does this framing help? Happy to adjust the Phase 1 implementation if you want to go a different direction. — Authored by egg |
|
egg finished successfully. View run logs |
|
@james-in-a-box makes sense and agreed. Go ahead and add a seep-review mode to the plan PR. |
|
@james-in-a-box review this PR |
|
Done — I've added a deep-review mode to the plan PR (#140) as section 2.4 in Phase 2. Summary of what's documented:
The deliverables table now includes deep review mode with its own prompt builder ( See the updated plan: https://github.com/jwbron/egg/pull/140/files — Authored by egg |
|
egg finished successfully. View run logs |
Code ReviewThis is a solid Phase 1 implementation of AI-powered code review. The architecture is clean and the scripts are well-structured. A few issues to address: Issues Found1. Line number mapping may fail for inline comments ( The GitHub review API expects line numbers relative to the diff, not absolute file line numbers. The prompt instructs Claude to provide "actual line number in the file" but the API uses diff-relative positions. This will cause inline comments to either fail or land on wrong lines. Options:
2. Regex pattern in JSON extraction is fragile ( The pattern The Python fallback at line 81-103 is more robust but the regex patterns above it may incorrectly match partial JSON. 3. Race condition in dismiss_previous_reviews ( The 4. Potential command injection in gh_api_safe ( The error message interpolates 5. Missing error handling for base64 decode ( If the GitHub API returns malformed base64, the SuggestionsModel selection threshold ( Workflow file: Since the workflow couldn't be pushed, consider adding a What looks good
Inline Comments
This is an automated review. Please evaluate suggestions carefully. — Authored by egg |
|
egg finished successfully. View run logs |
|
@james-in-a-box address the above feedback |
Address all feedback from the automated code review: 1. Line number mapping: Add get_diff_position() to convert absolute line numbers to diff positions for GitHub's review API. Comments on lines not in the diff are now included in the review body instead of failing. 2. JSON extraction: Replace fragile regex with robust Python parser that properly handles nested braces and escapes using bracket matching. 3. Race condition: Refactor dismiss_previous_reviews to collect review IDs into arrays before processing, avoiding subshell issues with while-read pipelines. 4. Command injection: Use printf with proper quoting for error messages in gh_api_safe() to prevent issues with special characters in paths. 5. Base64 decode: Add explicit error handling with warnings when content fetch or decode fails, instead of silently returning empty strings. Also clarify prompt instructions to explain that line number conversion is handled automatically by the posting script.
|
I've addressed all the feedback from the code review: 1. Line number mapping (Issue #1)Added
Comments on lines not in the diff (e.g., context lines) are now gracefully handled - they're included in the review body under "Additional comments (lines not in diff)" instead of failing silently. 2. Fragile JSON regex (Issue #2)Replaced the
3. Race condition in dismiss_previous_reviews (Issue #3)Refactored to collect all review IDs into arrays first, then process them. This:
4. Command injection in gh_api_safe (Issue #4)Changed from direct cmd_display=$(printf "'gh api %s'" "$*")5. Base64 decode error handling (Issue #5)Added explicit error handling in
Also updated the prompt instructions to clarify that line number conversion is handled automatically by the posting script. — Authored by egg |
|
egg finished successfully. View run logs |
|
@james-in-a-box the workflow has been added. Review it. |
Workflow ReviewThe workflow file has been added and looks good overall. Here's my review: What looks good
Issues to address1. HEAD_SHA may not match after checkout ( The workflow captures Fix: After checking out the PR branch, capture the actual HEAD: - name: Capture actual HEAD SHA
id: head
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Post review comments
...
env:
HEAD_SHA: ${{ steps.head.outputs.sha }}2. Missing When a PR comes from a fork, Fix: For fork PRs, you need to explicitly specify the repository: - name: Checkout PR branch
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}However, this introduces a security consideration: the "Run egg review" step would then execute code from an untrusted fork. The current design (checkout trusted main → build prompt → checkout PR branch → run Claude) is intentional to keep prompt building secure, but Claude would still see untrusted code. This is acceptable since Claude only reviews, doesn't execute arbitrary code from the PR. 3. Token scope for fork PRs The SuggestionsAdd workflow_dispatch for manual testing: on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: trueThis makes it easier to re-run reviews or test on specific PRs. SummaryThe workflow is well-designed with proper security boundaries. The two issues above (HEAD_SHA race and fork support) should be addressed before relying on this for production reviews. The HEAD_SHA issue can cause inline comments to fail; the fork issue will cause reviews to fail entirely on fork PRs. — Authored by egg |
|
egg finished successfully. View run logs |
|
@james-in-a-box address the feedback in the last comment |
Workflow Update RequiredI attempted to address the feedback from the workflow review, but the push failed due to GitHub App permission restrictions (no Changes made (commit 46297d9)1. Added on:
pull_request:
types: [opened, synchronize, ready_for_review, reopened]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: number2. Added fork PR support with - name: Checkout PR branch
uses: actions/checkout@v4
with:
repository: ${{ github.event.pull_request.head.repo.full_name }}
ref: ${{ github.event.pull_request.head.ref }}3. Fixed HEAD_SHA race condition by capturing actual HEAD after checkout: - name: Capture actual HEAD SHA
id: head
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"And updated the HEAD_SHA: ${{ steps.head.outputs.sha }}Options to apply these changes
— Authored by egg |
|
egg finished successfully. View run logs |
|
Applied the workflow fixes directly. Changes pushed in 006beda:
Also updated concurrency group and all — Authored by egg |
Summary
Implements Phase 1 of AI-powered code review per the plan in #140.
action/build-review-prompt.shto construct review prompts from PRmetadata, diffs, and full file contents
action/post-review-comments.shto parse Claude's JSON output andpost GitHub PR reviews with inline comments
prompt-fileinput to the egg action for large prompts.github/workflows/on-pull-request.ymlworkflow (see note below)Key features
.egg/review-rules.mdfor per-repo customization[skip-review]in titlecancel-in-progressto abort stale reviews on new pushesWorkflow file limitation
The workflow file (
.github/workflows/on-pull-request.yml) is in thisbranch but could not be pushed due to GitHub App permission
restrictions. Options:
workflowspermission to the GitHub AppIssue: #134
Related: #140 (plan), #70 (security linters), #77 (autofixers)
Test plan
promptandprompt-fileinputsactor on a test repositoryAuthored-by: egg