Personal
$10/month
- 50M tokens a week
- 20 requests per minute
- For one person
Reviews wait on a busy teammate, and small logic bugs slip through. Add one job to your workflow. It takes the pull request’s diff, has a coding agent read it and posts what it found as a comment. Claude Code, Codex and Continue each do it with a base URL, a key and the model name pareto. Pareto is Unbiased’s model: it selects frontier and open models for each request and blends their outputs into one answer.
Review commands tested live with Claude Code 2.1.305, Codex CLI 0.162.1 and Continue CLI 1.5.47Workflow YAML not run in Actions
Each of these talks to Pareto with a base URL, an API key and the model string pareto. Pick the one you already use.
claude -p --bare with every tool turned off. Three environment variables point it at Pareto.Pareto in Claude Code: setup guide →codex review --base is a built-in review command. One provider table in config.toml points it at Pareto.Pareto in OpenAI Codex CLI: setup guide →cn -p --readonly runs git to read the diff itself and writes the review. One model entry points it at Pareto.Pareto in Continue: setup guide →Each tab is a complete workflow file. All three take the same steps: check out the pull request with full history, run one headless review command against origin/<base branch>, write review.md, and post it. We ran each review command three times on a pull request with a real bug, and every run flagged it. We did not run the workflows in GitHub Actions.
Choose a plan, then create a key in the Unbiased platform. New accounts are reviewed and approved by a person before the key works. Save it as a repository secret named UNBIASED_API_KEY.
actions/checkout with fetch-depth: 0 fetches every branch, so origin/main exists and git diff origin/main...HEAD shows exactly what the pull request changes.
Claude Code: ANTHROPIC_BASE_URL=https://api.unbiased.ai (no /v1), the key in ANTHROPIC_AUTH_TOKEN, ANTHROPIC_MODEL=pareto. Codex: a provider table with https://api.unbiased.ai/v1. Continue: provider: openai with the same base URL. Type pareto by hand: Unbiased does not list models at /v1/models.
claude -p --bare --tools "" --setting-sources user, codex review --base or cn -p --readonly. Each prints the review to stdout, which the step writes to review.md. Claude Code has no tools and loads only your user settings, not settings files from the pull request. Continue and Codex can run shell commands: Continue with no sandbox, Codex in a read-only sandbox with no network.
The step first checks that review.md does not contain your key. gh pr comment --edit-last --create-if-none then posts one comment and updates it on each new push instead of adding another. The job needs pull-requests: write for that.
pareto. Claude Code (claude -p --bare --tools "" --setting-sources user), Codex and Continue each flagged the inverted expiry check in the pull request and said to return False, 3 runs out of 3 each. With a pull request that added .claude/settings.json pointing ANTHROPIC_BASE_URL at a local server, the --bare-only command sent the step's token to that server; with --tools "" --setting-sources user it sent nothing there. Run record.The diff is piped in, so Claude Code needs no tools to read it. --bare skips hooks, MCP servers, plugin sync and CLAUDE.md files, but on its own it still starts with Bash, Edit and Read. --tools "" turns off every built-in tool. --setting-sources user stops Claude Code from loading .claude/settings.json and .claude/settings.local.json from the checkout, so a pull request cannot change its permissions or set ANTHROPIC_BASE_URL to send your key to its own server.
npm install -g @anthropic-ai/claude-code (Node.js 22 or later).claude/settings.json setting ANTHROPIC_BASE_URL to a local server: without the two flags Claude Code sent the key to that server; with them it sent nothing there and started with an empty tool listpareto; the run finishes normallyANTHROPIC_AUTH_TOKEN. It worked in all our runs, but Claude Code documents only ANTHROPIC_API_KEY and apiKeyHelper for --barename: Pareto review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm install -g @anthropic-ai/claude-code
- name: Review the diff with Pareto
env:
ANTHROPIC_BASE_URL: https://api.unbiased.ai
ANTHROPIC_AUTH_TOKEN: ${{ secrets.UNBIASED_API_KEY }}
ANTHROPIC_MODEL: pareto
BASE_REF: ${{ github.base_ref }}
run: |
git diff "origin/$BASE_REF...HEAD" | claude -p --bare --tools "" --setting-sources user \
--append-system-prompt "You are reviewing a pull request. Report real bugs only: file, line, what goes wrong and the fix. If there are none, say LGTM." \
"Review this diff." > review.md
- name: Post the review on the pull request
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
KEY: ${{ secrets.UNBIASED_API_KEY }}
run: |
if grep -qF "$KEY" review.md; then
echo "review.md contains the API key, not posting it" >&2
exit 1
fi
gh pr comment "$PR" --edit-last --create-if-none --body-file review.md# On the pull request branch, with main fetched
export ANTHROPIC_BASE_URL=https://api.unbiased.ai
export ANTHROPIC_AUTH_TOKEN=your-unbiased-api-key
export ANTHROPIC_MODEL=pareto
export BASE_REF=main
git diff "origin/$BASE_REF...HEAD" | claude -p --bare --tools "" --setting-sources user \
--append-system-prompt "You are reviewing a pull request. Report real bugs only: file, line, what goes wrong and the fix. If there are none, say LGTM." \
"Review this diff." > review.md
cat review.mdIf ANTHROPIC_API_KEY is set on the runner, remove it from this step so Claude Code sends your Unbiased key. We do not show anthropics/claude-code-action here because its documentation lists no way to set a base URL.
codex review is Codex’s own non-interactive review command. It diffs against the base branch, reads the files it needs in a read-only sandbox and prints prioritized comments.
npm install -g @openai/codexpareto and uses its defaults; the review still runsname: Pareto review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm install -g @openai/codex
- name: Point Codex at Unbiased
run: |
mkdir -p ~/.codex
cat > ~/.codex/config.toml <<'TOML'
model = "pareto"
model_provider = "unbiased"
[model_providers.unbiased]
name = "Unbiased"
base_url = "https://api.unbiased.ai/v1"
env_key = "UNBIASED_API_KEY"
wire_api = "responses"
TOML
- name: Review the diff with Pareto
env:
UNBIASED_API_KEY: ${{ secrets.UNBIASED_API_KEY }}
BASE_REF: ${{ github.base_ref }}
run: |
codex review --base "origin/$BASE_REF" > review.md
- name: Post the review on the pull request
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
KEY: ${{ secrets.UNBIASED_API_KEY }}
run: |
if grep -qF "$KEY" review.md; then
echo "review.md contains the API key, not posting it" >&2
exit 1
fi
gh pr comment "$PR" --edit-last --create-if-none --body-file review.md# On the pull request branch, with main fetched
export CODEX_HOME=$(mktemp -d) # leaves your own ~/.codex alone
cat > "$CODEX_HOME/config.toml" <<'TOML'
model = "pareto"
model_provider = "unbiased"
[model_providers.unbiased]
name = "Unbiased"
base_url = "https://api.unbiased.ai/v1"
env_key = "UNBIASED_API_KEY"
wire_api = "responses"
TOML
export UNBIASED_API_KEY=your-unbiased-api-key
export BASE_REF=main
codex review --base "origin/$BASE_REF" > review.md
cat review.mdThe provider table goes in the user-level ~/.codex/config.toml, which is why the workflow writes it there. In our test, a pull request that added its own .codex/config.toml with a different provider and base URL did not change where Codex sent requests. We did not check what else Codex reads from that file. The key is set on the review step only, as the Codex docs advise. Codex’s docs point GitHub Actions users to openai/codex-action; we do not show it because it documents no base URL or provider input. Our Codex runs were on macOS, so its Linux sandbox on ubuntu-latest was not tested.
Continue’s docs say cn takes piped input as context, but in our test cn 1.5.47 ignored it, so the prompt names the diff and cn runs git itself. --readonly starts it in plan mode, which removes the file-edit tools but still allows shell commands, which is how it runs git.
npm i -g @continuedev/cli$RUNNER_TEMP, which GitHub empties at the end of each jobname: Pareto review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-node@v7
with:
node-version: 22
- run: npm i -g @continuedev/cli
- name: Review the diff with Pareto
env:
UNBIASED_API_KEY: ${{ secrets.UNBIASED_API_KEY }}
BASE_REF: ${{ github.base_ref }}
run: |
cat > "$RUNNER_TEMP/continue.yaml" <<YAML
name: Unbiased
version: 0.0.1
schema: v1
models:
- name: Pareto
provider: openai
model: pareto
apiBase: https://api.unbiased.ai/v1
apiKey: $UNBIASED_API_KEY
roles:
- chat
YAML
cn -p --silent --readonly --config "$RUNNER_TEMP/continue.yaml" \
"Review the changes in git diff origin/$BASE_REF...HEAD. Report real bugs only: file, line, what goes wrong and the fix. If there are none, say LGTM." > review.md
- name: Post the review on the pull request
env:
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.number }}
KEY: ${{ secrets.UNBIASED_API_KEY }}
run: |
if grep -qF "$KEY" review.md; then
echo "review.md contains the API key, not posting it" >&2
exit 1
fi
gh pr comment "$PR" --edit-last --create-if-none --body-file review.md# On the pull request branch, with main fetched
export UNBIASED_API_KEY=your-unbiased-api-key
export RUNNER_TEMP=$(mktemp -d)
export BASE_REF=main
cat > "$RUNNER_TEMP/continue.yaml" <<YAML
name: Unbiased
version: 0.0.1
schema: v1
models:
- name: Pareto
provider: openai
model: pareto
apiBase: https://api.unbiased.ai/v1
apiKey: $UNBIASED_API_KEY
roles:
- chat
YAML
cn -p --silent --readonly --config "$RUNNER_TEMP/continue.yaml" \
"Review the changes in git diff origin/$BASE_REF...HEAD. Report real bugs only: file, line, what goes wrong and the fix. If there are none, say LGTM." > review.md
rm -r "$RUNNER_TEMP" # the config file holds your key
cat review.mdThe only functional change makes expired coupons valid, directly breaking the documented purpose of `coupon_is_valid` and enabling expired discounts to be applied. Review comment: - [P1] Return True for expired coupons — /private/tmp/uc-smoke/ai-code-review-in-ci/ci/coupons.py:7-8 The newly added expiry check inverts the intended behavior: when `now` is after `expires_at`, `coupon_is_valid` returns `True`, allowing `apply_coupon` to apply a discount that should have expired. This should return `False` (or the early expiry guard should be removed if not part of the intended change).
The test pull request added an expiry check to coupon_is_valid() that returns True when the coupon has expired. All nine reviews named the file and the lines, said expired coupons now count as valid, and said to return False. Wording and detail varied from run to run.
A review costs what the agent reads and writes, and that grows with the diff and with how many files it opens. On our two-line test diff, two extra runs of the Claude Code command reported 406 and 525 tokens. That is a floor, not an estimate for your pull requests, so this section shows plan allowances only.
We measured tokens only for the Claude Code command on one two-line diff, so this page makes no per-review estimate. A large pull request can cost many times more. Rates and limits are on Pricing. Run record.
Pick a monthly allowance, or pay per token on Team.
$10/month
$100/month
Pay as you go
Subscriptions are for one person and are not unlimited. New API accounts are reviewed by a person before access turns on, and commercial or production use needs a separate written agreement. Rates and limits are on Pricing.
Not with this workflow. GitHub does not pass repository secrets to pull_request runs from forks, so the review step has no key and fails. It runs on pull requests from branches in your own repository. Avoid switching to pull_request_target to get around this: that trigger has secrets and write access while the job checks out code someone else wrote.
Claude Code, as set up here, gets the diff on stdin and starts with no tools, so it cannot edit files or run commands. With --bare it loads no hooks, MCP servers or CLAUDE.md, and with --setting-sources user it ignores settings files in the checkout. cn --readonly (plan mode) removes the Edit and Write tools but still allows its Bash tool, with no sandbox, so it can run any command, including the pull request’s code. In our runs it ran only git and read files. codex review can also run commands, including the pull request’s code, but inside a sandbox that blocks file writes and network access. In 1 of our 3 Codex runs it imported the changed module with python3 to check the bug. No tool edited a file in our runs.
No. We ran each review command on a local clone with the same environment variables the workflow sets, three times per tool, on October 20, 2026. The checkout, install, secrets and gh pr comment steps follow GitHub’s and each tool’s documentation but were not run. Run record.
No, and the review is not a test suite. In our runs all three tools caught a planted logic bug every time, but one Codex review also made a wrong side claim about unexpired coupons, and one Continue review cited lines 6 to 7 instead of 7 to 8. Treat the comment as a second reader, not a gate.
It could try. The key is in the review step’s environment, and Continue’s config file holds it, so text in a pull request could ask the agent to print it into review.md, which is then posted. The post step checks review.md for the key and stops instead of posting if it finds it. That catches the key as written, not an encoded copy, and not a key that cn’s unsandboxed shell sends over the network, so run the review only on pull requests from people you trust and rotate the key if a review ever prints it.
Personal and Personal Max are for one person. A review bot on a company’s repositories is production use: Team is pay as you go, and plan selection does not itself authorize production use, so confirm it in a separate written agreement with Unbiased. See Pricing for the rates.
No. With these settings Claude Code, Codex and Continue send requests to Unbiased with your Unbiased key, and your Unbiased plan pays for them. Format compatibility is not a promise that every feature of each tool works, so tell us if one doesn’t.
Requests over your plan’s limits return an HTTP 429 error. Personal includes 50M tokens a week and 20 requests per minute. Personal Max raises that to 600M a week and 60 requests per minute for $100/month. Team uses prepaid pay-as-you-go credits with no weekly token cap.
No. You send every request to one model string, pareto. Pareto selects frontier and open models for each request and blends their outputs into one answer.
Personal and Personal Max are not our zero data retention tier: prompts and responses may be kept up to 30 days, as section 5(c) of the Terms explains. For work that must not be kept, ask about the Zero Data Retention API on the Private AI page.
Same key, same model string, different job. See every use case. Or find your tool on Works with.
Product names belong to their owners. Unbiased is not affiliated with or endorsed by the makers of the tools on this page.
One workflow file, one secret and the model string pareto. Pareto starts at $10 a month for 50M tokens a week.