Skip to content

Automatic code review

Deliverable: every time Claude Code finishes a turn with uncommitted changes, a Stop hook runs a Codex review of those changes and prints its verdict.

Prerequisites: Claude Code and Codex CLI both configured with the same MIRAPI_API_KEY (see Claude Code and Codex CLI); a git repository.

Create ~/.claude/review.sh:

#!/usr/bin/env bash
# Run a Codex review of the uncommitted changes.
set -euo pipefail
DIFF_STAT=$(git diff HEAD --stat || true)
# Exit silently when there is nothing to review.
if [[ -z "$DIFF_STAT" ]]; then
exit 0
fi
codex exec "Review the changes below for bugs, security issues, and broken invariants. Be concise.
$DIFF_STAT" 2>/dev/null || true

Make it executable:

Terminal window
chmod +x ~/.claude/review.sh

The script captures a one-line summary of the staged and unstaged changes (git diff HEAD --stat), hands it to Codex, and lets Codex print the review to the hook’s output. The trailing || true keeps a failed Codex call from surfacing as a hook error.

Add the hook to your project’s .claude/settings.json:

{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash ~/.claude/review.sh",
"timeout": 120
}
]
}
]
}
}

The Stop event fires whenever Claude Code pauses for your input, which is the moment a review is useful. The hook fields are:

Field Purpose
type "command" runs a shell command
command The command to execute (here, bash ~/.claude/review.sh)
timeout Maximum seconds the hook may run before being killed (120)

To keep the hook out of git, use .claude/settings.local.json instead; global hooks live in ~/.claude/settings.json.

First test the script on its own: change a tracked file, then run it directly.

Terminal window
bash ~/.claude/review.sh

You should see the Codex review in the terminal. Then ask Claude Code to make a change and wait for the hook output. The verdict appears in the hook’s output section once Claude Code pauses.

Claude Code and Codex CLI speak different protocols, so they use different base URLs on MirAPI:

Agent Protocol Base URL Authentication
Claude Code Anthropic Messages (POST /v1/messages) https://api.mirapi.ai (no /v1) ANTHROPIC_AUTH_TOKEN=$MIRAPI_API_KEY
Codex CLI OpenAI Responses (POST /v1/responses) https://api.mirapi.ai/v1 env_key = "MIRAPI_API_KEY"

Point the Anthropic client at the bare origin and pass the key through the auth-token variable:

Terminal window
export ANTHROPIC_BASE_URL="https://api.mirapi.ai"
export ANTHROPIC_AUTH_TOKEN="$MIRAPI_API_KEY"
export ANTHROPIC_MODEL="deepseek-chat"

Do not append /v1; Claude Code builds the /v1/messages path itself. See Claude Code for the full setup.

Register MirAPI as a provider in ~/.codex/config.toml:

model = "deepseek-chat"
model_provider = "mirapi"
[model_providers.mirapi]
name = "MirAPI"
base_url = "https://api.mirapi.ai/v1"
env_key = "MIRAPI_API_KEY"
wire_api = "responses"

Codex appends /responses to the base URL, so it needs the /v1 suffix. See Codex CLI for the full reference.

Because both agents use the same key, they draw from the same prepaid balance. To check spending:

Terminal window
curl https://api.mirapi.ai/api/log/token -H "Authorization: Bearer $MIRAPI_API_KEY"
curl https://api.mirapi.ai/api/usage/token -H "Authorization: Bearer $MIRAPI_API_KEY"

/api/log/token lists per-request rows; /api/usage/token returns account-level totals. Text is metered per token (input / output / cache read), reasoning tokens bill as output, and prompt caching is enabled automatically on OpenAI-compatible models. Reconcile against the Platform billing log (https://platform.mirapi.ai).

Status Meaning What to do
401 Key missing, invalid, or unknown Check the exported key
403 Key valid but refused (balance, whitelist, quota, or IP) Fix the cause, then retry
413 Payload too large Trim the diff sent to the model
429 Rate limited Jittered exponential backoff (1s→2s→4s, cap ~30s); no Retry-After header
500 Gateway or upstream error Idempotent requests can be retried safely

The gateway does not retry for you. Every error message ends with a MirAPI request ID; include it in support tickets.

  • Hook stdout is shown to Claude Code, so keep the script silent except for the verdict.
  • The review runs inside the hook, so a long diff delays the next turn; keep the timeout tight and the prompt concise.
  • git diff HEAD --stat covers staged and unstaged changes but not untracked files; add git add -N . (or switch to git status --porcelain) if new files matter.
  • If Codex is not logged in or misconfigured, the script exits quietly (|| true). Test it on its own first.

Each review is one short Codex turn, typically a few thousand tokens. That costs anywhere from a fraction of a cent to a few cents, depending on the diff size and the model. Exact amounts show up in the Platform usage log and GET /api/log/token.