GitHub Action that reviews a single commit with Claude, GPT, and Gemini in parallel, deduplicates findings, files them as a GitHub Issue, and optionally opens a draft PR with high-confidence fixes that multiple models agree on.
Designed to be called inside a per-commit matrix on push events. The action reviews one commit per invocation — your workflow handles enumeration.
name: AI Commit Review
on:
push:
branches: [main]
permissions:
contents: write
issues: write
pull-requests: write
jobs:
enumerate:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.commits.outputs.matrix }}
count: ${{ steps.commits.outputs.count }}
steps:
- uses: actions/checkout@v6
with: { fetch-depth: 0 }
- id: commits
env:
BEFORE: ${{ github.event.before }}
AFTER: ${{ github.event.after }}
run: |
if [[ "$BEFORE" == "0000000000000000000000000000000000000000" ]]; then
SHAS=$(git log --format='%H' -1 "$AFTER")
else
SHAS=$(git log --format='%H' "${BEFORE}..${AFTER}")
fi
MATRIX=$(echo "$SHAS" | jq -R -s -c 'split("\n") | map(select(. != "")) | map({sha: .})')
echo "count=$(echo "$MATRIX" | jq 'length')" >> "$GITHUB_OUTPUT"
echo "matrix=${MATRIX}" >> "$GITHUB_OUTPUT"
review:
needs: enumerate
if: needs.enumerate.outputs.count != '0'
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
commit: ${{ fromJson(needs.enumerate.outputs.matrix) }}
steps:
- uses: actions/checkout@v6
with: { fetch-depth: 0 }
- uses: leek/ai-commit-review@v1
with:
commit-sha: ${{ matrix.commit.sha }}
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}Any provider whose API key is empty is skipped. Run with one, two, or all three.
Claude and OpenAI can also run through their local coding CLIs instead of direct API calls:
- Claude CLI mode runs
claude -pthrough Claude Code. - OpenAI CLI mode runs
codex execthrough Codex. The provider is still namedopenaiin reports so existing digesting and agreement logic keeps working. - Gemini remains API-key only for now.
The default auth mode for Claude and OpenAI is auto, which preserves existing workflows:
- Claude uses CLI mode when
claude-code-oauth-tokenis set; otherwise it usesanthropic-api-key. - OpenAI uses CLI mode when
codex-access-tokenorcodex-auth-jsonis set; otherwise it usesopenai-api-key. - Set
claude-authoropenai-authtoapiorclito force a mode.
The action installs missing claude and codex commands when CLI mode is selected. Set install-cli-tools: false if your runner already has them.
CLI modes run from the caller's checked-out repository and receive the commit-sha explicitly. Use actions/checkout with fetch-depth: 0 so the CLIs can inspect the commit and surrounding repository context. Unlike API mode, CLI mode does not embed the filtered diff in the prompt; Claude and Codex inspect the commit from the checkout themselves. Claude is limited to read/search/git shell tools. Codex defaults to codex-sandbox: danger-full-access because its Linux read-only sandbox depends on user namespaces that may be unavailable on GitHub-hosted runners. The action verifies afterward that the checkout has no tracked changes and no unexpected untracked files.
Codex CLI mode writes project_doc_fallback_filenames = ["CLAUDE.md"] to CODEX_HOME/config.toml, so repositories that use CLAUDE.md instead of AGENTS.md are still picked up by Codex's project-doc discovery.
The default Claude model is claude-opus-4-8. If you set install-cli-tools: false, make sure the runner's Claude Code install supports Opus 4.8.
- uses: leek/ai-commit-review@v1
with:
commit-sha: ${{ matrix.commit.sha }}
claude-auth: cli
openai-auth: cli
claude-code-oauth-token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
codex-access-token: ${{ secrets.CODEX_ACCESS_TOKEN }}Use this only on trusted private automation. auth.json contains access tokens.
- uses: leek/ai-commit-review@v1
with:
commit-sha: ${{ matrix.commit.sha }}
openai-auth: cli
codex-auth-json: ${{ secrets.CODEX_AUTH_JSON }}- Claude Code: run
claude setup-token, then store the printed token asCLAUDE_CODE_OAUTH_TOKEN. Anthropic documents this in Generate a long-lived token. - Codex access token: create a token in ChatGPT admin settings and store it as
CODEX_ACCESS_TOKEN. OpenAI documents this in Codex access tokens. - Codex
auth.json: sign in locally withcodex login, then seed a trusted runner or CI secret with the file contents. By default the file is at~/.codex/auth.json; on macOS you can copy it withpbcopy < ~/.codex/auth.json. OpenAI documents the advanced workflow in Maintain Codex account auth in CI/CD.
Do not expose CLI account credentials to public repositories, fork-triggered workflows, or untrusted runners.
| Input | Default | Description |
|---|---|---|
commit-sha |
required | Commit SHA to review. Caller must actions/checkout with fetch-depth: 0. |
anthropic-api-key |
empty | Anthropic API key. Provider runs only when set. |
openai-api-key |
empty | OpenAI API key. |
gemini-api-key |
empty | Gemini API key. |
claude-auth |
auto |
Claude provider auth mode: auto, api, or cli. |
openai-auth |
auto |
OpenAI provider auth mode: auto, api, or cli. |
claude-code-oauth-token |
empty | Claude Code OAuth token from claude setup-token. Enables Claude CLI mode in auto. |
codex-access-token |
empty | Codex access token passed as CODEX_ACCESS_TOKEN. Enables Codex CLI mode in auto. |
codex-auth-json |
empty | Contents of a Codex auth.json file for Codex CLI mode. Use only on trusted private runners. |
codex-home |
empty | Optional CODEX_HOME path for Codex CLI mode. Useful for self-hosted runners with persistent auth. |
install-cli-tools |
true |
Install missing Claude Code or Codex CLI tools when a CLI mode is selected. |
claude-cli-path |
claude |
Claude Code CLI command path used in Claude CLI mode. |
codex-cli-path |
codex |
Codex CLI command path used in OpenAI CLI mode. |
codex-sandbox |
danger-full-access |
Codex sandbox mode used in OpenAI CLI mode. Use read-only only on runners where Codex's Linux sandbox can create user namespaces. |
claude-model |
claude-opus-4-8 |
Anthropic model id. |
openai-model |
gpt-5.5 |
OpenAI model id. |
gemini-model |
gemini-3.5-flash |
Gemini model id. |
claude-context-file |
empty | Project context file injected into the Claude prompt. |
openai-context-file |
empty | Project context file injected into the OpenAI prompt. |
gemini-context-file |
empty | Project context file injected into the Gemini prompt. |
prompt-file |
empty | Path to a custom prompt template. Overrides the bundled generic prompt. |
exclude-paths |
empty | Newline-separated git pathspecs excluded from the diff. Use the :!path syntax. |
max-diff-lines |
5000 |
Skip review if filtered diff exceeds this many added/changed lines. |
skip-message-patterns |
Merge* |
Newline-separated bash globs matched against the commit subject. |
skip-author-patterns |
empty | Newline-separated bash globs matched against the commit author name. |
min-severity-for-issue |
warning |
One of critical, warning, info. |
min-models-for-fix-pr |
2 |
Number of providers that must agree on a high-confidence fix before a fix PR is opened. 0 disables. |
issue-label |
ai-review |
Label applied to created issues. |
issue-title-prefix |
[AI Review] |
Issue title prefix. |
fix-pr-title-prefix |
[AI Fix] Suggested fixes for |
Fix PR title prefix. |
fix-branch-prefix |
ai-fix/ |
Fix branch prefix. Short SHA is appended. |
base-branch |
main |
Base branch for fix PRs. |
github-token |
${{ github.token }} |
Token used to create issues, comments, branches, and PRs. |
node-version |
20 |
Node.js version. |
| Output | Description |
|---|---|
reviewed |
true if the commit was reviewed, false if skipped. |
skip-reason |
Reason the commit was skipped, if any. |
diff-line-count |
Added/changed line count of the filtered diff. |
critical-count |
Critical findings after dedup. |
warning-count |
Warning findings after dedup. |
info-count |
Info findings after dedup. |
issue-url |
URL of the created issue, if any. |
fix-pr-url |
URL of the created draft fix PR, if any. |
provider-failures |
Comma-separated provider names that failed to produce a valid review. |
provider-successes |
Comma-separated provider names that produced a valid review. |
provider-skips |
Comma-separated provider names skipped because credentials or supported auth modes were not provided. |
- uses: leek/ai-commit-review@v1
with:
commit-sha: ${{ matrix.commit.sha }}
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
openai-api-key: ${{ secrets.OPENAI_API_KEY }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
claude-context-file: CLAUDE.md
openai-context-file: AGENTS.md
gemini-context-file: GEMINI.md
prompt-file: .github/ai-review-prompt.txt
exclude-paths: |
:!package-lock.json
:!yarn.lock
:!vendor/
:!node_modules/
:!tests/
skip-message-patterns: |
Merge*
build(deps)*
*skip-review*
*skip-ci*
*fix code style*
*Fix Code Style*
ai-review:*
skip-author-patterns: |
*dependabot*Pattern syntax:
skip-message-patternsandskip-author-patternsare bash glob patterns. Avoid[...]— bash treats it as a character class, not a literal substring. Write*skip-review*, not*[skip-review]*.
- Skip check — matches the commit subject and author against your skip patterns.
- Diff filter —
git diff sha~1 shawith yourexclude-pathsapplied. Skips if larger thanmax-diff-lines. - Provider fan-out — runs Claude, GPT/OpenAI, and Gemini in sequence. Claude and OpenAI can use either direct API calls or their CLI modes. Each provider receives the bundled (or custom) prompt, optional project context, and the diff.
- Digest — merges findings, dedupes by file + line proximity + severity, builds a markdown report, files it as an issue. Optionally opens a draft fix PR for high-confidence findings that multiple models agree on.
The workflow needs:
permissions:
contents: write # for the fix PR branch
issues: write # for finding issues
pull-requests: write # for the fix PR- The action does not enumerate commits. Drive the matrix from your workflow so failures isolate per-commit.
- Existing issues for the same short SHA are detected and creation is skipped.
- All API calls have two retries on 5xx responses.
- CLI modes normalize their output through the same findings parser and self-retraction filter as API modes.
- Selected providers that fail to produce valid review JSON are reported in
provider-failuresand logged as warnings when at least one other provider succeeds. The action fails only when no selected provider produces a valid review.
MIT