# AI code review in GitHub Actions, without a bot.

> Add AI code review to a GitHub Actions workflow with no GitHub App to install: inline PR comments, a severity gate, or a policy gate, using your own provider key.

Published October 27, 2026 by CommitBrief (https://commitbrief.com)

Canonical URL: https://commitbrief.com/blog/ai-code-review-in-github-actions-without-a-bot/
Tags: github, ci, workflow

---

AI code review in GitHub Actions without a bot means the review runs as a step in your own workflow, on your own runner, with your own provider key, instead of through a third-party GitHub App that you install and grant repository access. CommitBrief ships this as one composite action, `CommitBrief/commitbrief-action`, and the same commands run on your laptop.

> **In short:** one workflow file, one repository secret. Pick `comment` mode for inline review comments, `gate` mode for a pass/fail check, or `guard` mode for a per-severity budget.

"Bot" needs a precise reading here. In `comment` mode the review comments are still posted to the pull request, but by your workflow's own `GITHUB_TOKEN`, not by an installed app with its own webhook and its own copy of your diff. Nothing is installed on the repository, and there is no vendor account in the loop beyond the LLM provider you chose. `comment` mode drives the same `remote pr` command described in [reviewing GitHub PRs from the terminal](/blog/reviewing-github-prs-from-the-terminal). For the longer version of that trade-off, see [why a CLI and not a GitHub App](/blog/cli-vs-github-app) and the broader [comparison of AI code review tools](/compare/ai-code-review-tools/).

## The workflow file

Add `.github/workflows/commitbrief.yml`, and add your provider key as a repository secret (`ANTHROPIC_API_KEY` in this example):

```yaml
name: CommitBrief
on:
  pull_request:
    types: [opened, synchronize, reopened]

permissions:
  contents: read
  pull-requests: write        # comment mode posts the review

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: CommitBrief/commitbrief-action@v1
        with:
          provider: anthropic
          api-key: ${{ secrets.ANTHROPIC_API_KEY }}
```

`comment` is the default mode. The Action downloads the prebuilt CLI for the runner, checks its SHA-256 against the release's `checksums.txt`, and reviews the pull request. The checkout step is not optional: the Action does not check out the repository for you. The [Action reference](/docs/1.x/github-action) lists every input.

Each finding is posted as an inline comment, then a review verdict is submitted. By default that verdict is only ever `approve` or `comment`, and the step exits `0` once the review is submitted, whatever the findings were. Posting comments is not a gate.

## Choosing a mode

| Mode | What it runs | Result | Needs |
|---|---|---|---|
| `comment` (default) | `commitbrief remote pr <number>` | Inline comments plus a verdict | `contents: read`, `pull-requests: write` |
| `gate` | `commitbrief diff <base>...<head> --fail-on=<severity>` | Pass or fail the job | `contents: read` |
| `guard` | `commitbrief guard --diff <base>...<head> --policy <path>` | Pass or fail against a per-severity budget | `contents: read` |

You can run more than one. A common split is `comment` for the human-readable feedback and `gate` as a separate job for the merge check.

### Make the check fail

```yaml
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0             # both PR endpoints must be local
      - uses: CommitBrief/commitbrief-action@v1
        with:
          provider: openai
          api-key: ${{ secrets.OPENAI_API_KEY }}
          mode: gate
          fail-on: high
```

`fetch-depth: 0` matters. On a `pull_request` event the default shallow checkout does not contain the base and head commits, and `commitbrief diff` fails on the missing objects. `fail-on: high` fails the job on a high or critical finding. The values are `critical`, `high`, `medium`, `low`, `info`, and `any`; [Severity and CI gating](/docs/1.x/severity#the---fail-on-flag) defines each. The reasoning behind a threshold is in [the `--fail-on` post](/blog/fail-on-ci-gate).

### Let the review request changes

```yaml
      - uses: CommitBrief/commitbrief-action@v1
        with:
          provider: anthropic
          api-key: ${{ secrets.ANTHROPIC_API_KEY }}
          request-changes-on: high
```

This turns a high or critical finding into a `request-changes` review. It does not change the step's exit code, which stays `0`. If you want a red check, use `gate`.

### A budget instead of a threshold

`guard` mode evaluates a committed `.commitbrief/policy.yml`, for example zero critical and zero high findings but up to five medium ones. A missing or malformed policy blocks rather than passes. `guard` needs `fetch-depth: 0` on the checkout, like `gate`, and since CommitBrief adds `.commitbrief/` to `.gitignore`, the policy file must be un-ignored explicitly with a `!.commitbrief/policy.yml` line or it never reaches the runner. See the [CI gating guide](/docs/1.x/ci-gate), [Policy gate](/docs/1.x/policy-gate), and [the policy gate for AI-authored PRs](/blog/policy-gate-for-ai-authored-prs).

## Reproducing a CI failure locally

Every mode shells out to a command you can run yourself, so a red check is reproducible without pushing:

```sh
commitbrief diff origin/main...HEAD --fail-on=high
```

## Limits to know before you turn it on

- **Pull requests only.** The Action reads the PR number and the base and head SHAs from the `pull_request` event and fails without one. It is not a `push`-event tool. GitHub does not pass repository secrets to the runner for pull requests from forks, and gives `GITHUB_TOKEN` read-only permissions there ([GitHub's event reference](https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows)), so the review only works on branches in the same repository.
- **API providers only.** The Action accepts `anthropic`, `openai`, `gemini`, `deepseek`, `mistral`, `cohere`, and `ollama`. The CLI-backed providers `claude-cli`, `gemini-cli`, and `codex-cli` are rejected, because a runner has no locally authenticated host CLI. `ollama` needs a reachable server, so it fits a self-hosted runner.
- **Every review is a paid call.** The response cache lives inside the checkout, so each job starts cold.
- **Large diffs can abort on the cost preflight.** With no TTY, CommitBrief aborts instead of prompting when the estimate exceeds `cost.warn_threshold_usd` (default `$0.50`). The Action has no `--no-cost-check` input; the ceiling is raised in a committed `.commitbrief/config.yml`, which must never contain an `api_key` and has to be un-ignored the same way as the policy file. See [Safety, cost, and cache](/docs/1.x/safety-and-cost).
- **A model that returns unparseable output skips the gate.** CommitBrief degrades to plain text and `--fail-on` is skipped by design, so a green `gate` run is not proof that the diff is clean.
- **It does not replace a human reviewer.** It reads the diff; it does not know why you made the change.

## One action

Copy the first workflow into a branch, add the secret, and open a pull request against it. Check what the review posted before you decide whether to add a `gate` job.