Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions .github/workflows/ai-review-claude.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
description: 'Maximum agentic turns'
required: false
type: number
default: 30
default: 35
prompt:
description: 'Custom review prompt (overrides prompt file if provided)'
required: false
Expand Down Expand Up @@ -104,8 +104,11 @@ jobs:

Output your review findings in markdown format. Do NOT post a PR comment yourself - just output the review content.

# always(): a run that hits --max-turns fails the step above, and without
# this the review it already wrote is thrown away and the PR just gets a
# red check with no comment.
- name: Post review comment
if: steps.claude-review.outputs.execution_file != ''
if: always() && steps.claude-review.outputs.execution_file != ''
uses: actions/github-script@v7
env:
EXECUTION_FILE: ${{ steps.claude-review.outputs.execution_file }}
Expand All @@ -127,13 +130,27 @@ jobs:
const data = JSON.parse(fs.readFileSync(execFile, 'utf8'));
// Find the result message (last message with type "result")
const resultMsg = data.filter(m => m.type === 'result').pop();
const review = resultMsg?.result || '';
let review = resultMsg?.result || '';
let note = '';

// A failed run (error_max_turns, API error) carries no `result`, so
// fall back to the last thing Claude wrote and flag it as partial.
if (review.trim() === '') {
const texts = data
.filter(m => m.type === 'assistant')
.flatMap(m => (m.message?.content || [])
.filter(c => c.type === 'text')
.map(c => c.text || ''));
review = texts.pop() || '';
const reason = resultMsg?.errors?.join('; ') || resultMsg?.subtype || 'run did not finish';
note = `\n\n> Partial review: ${reason}.`;
}

if (review && review.trim() !== '') {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request?.number || context.payload.issue?.number,
body: `## 🤖 Claude Code Review\n\n${review}\n\n---\n*Automated review by Claude (Anthropic) · ${model}${customPrompt}*`
body: `## 🤖 Claude Code Review\n\n${review}${note}\n\n---\n*Automated review by Claude (Anthropic) · ${model}${customPrompt}*`
});
}
14 changes: 13 additions & 1 deletion .github/workflows/ai-review-codex.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ on:
description: 'Codex model to use'
required: false
type: string
default: 'gpt-5.4'
default: 'gpt-5.6-terra'
safety_strategy:
description: 'Codex safety strategy (drop-sudo, permissive, etc.)'
required: false
Expand Down Expand Up @@ -49,6 +49,18 @@ jobs:
fetch-depth: 0
ref: ${{ github.event.pull_request.head.sha || format('refs/pull/{0}/head', github.event.issue.number) }}

# Codex runs with --sandbox workspace-write, which keeps .git read-only.
# checkout leaves LFS-tracked files as pointers, so in repos that use LFS
# every git command runs the LFS filters, which write to .git/lfs/tmp and
# fail with "read-only file system" (exit 128). Detach the filters here,
# outside the sandbox; the review only needs to read files.
- name: Detach git LFS filters
run: git lfs uninstall --local || true

# Without it, codex logs a warning and falls back to its bundled copy.
- name: Install bubblewrap
run: sudo apt-get update -qq && sudo apt-get install -y -qq bubblewrap

- name: Load prompt
id: prompt
run: |
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Automated PR code review using various AI providers. Each workflow posts review
| Workflow | Provider | Model |
|----------|----------|-------|
| `ai-review-kimi.yml` | [Moonshot AI](https://platform.moonshot.ai/) | kimi-k2.5 |
| `ai-review-codex.yml` | [OpenAI](https://platform.openai.com/) | gpt-5.4 |
| `ai-review-codex.yml` | [OpenAI](https://platform.openai.com/) | gpt-5.6-terra |
| `ai-review-claude.yml` | [Anthropic](https://console.anthropic.com/) | sonnet |

### Quick Start
Expand Down Expand Up @@ -104,7 +104,7 @@ jobs:
secrets:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
with:
model: 'gpt-5.4' # Codex model
model: 'gpt-5.6-terra' # Codex model
safety_strategy: 'drop-sudo' # Codex safety strategy
prompt: '' # Custom prompt (overrides prompt file)
```
Expand All @@ -119,7 +119,7 @@ jobs:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
with:
model: 'sonnet' # sonnet, opus, or haiku
max_turns: 30 # Max agentic turns
max_turns: 35 # Max agentic turns
allowed_tools: '...' # Allowed Claude tools
prompt: '' # Custom prompt (overrides prompt file)
```
Expand Down