Review with OpenRouter¶
OpenRouter is a key-based gateway to many model
vendors behind one API. Add an OPENROUTER_API_KEY, then pick any model
OpenRouter offers using its vendor/model name.
Contents¶
- Get an API key
- GitHub Action
- Run locally
- Choosing the model
- Credit reservations
- Persist non-secret defaults
Get an API key¶
Create a key at https://openrouter.ai/keys. In your repository, add it as an
Actions secret named OPENROUTER_API_KEY
(Settings → Secrets and variables → Actions → New repository secret).
GitHub Action¶
Copy examples/workflows/review-openrouter.yml to
.github/workflows/lgtmaybe.yml. The core step is:
- uses: MattJColes/lgtmaybe@v2
with:
provider: openrouter
model: anthropic/claude-sonnet-4-6
api_key: ${{ secrets.OPENROUTER_API_KEY }}
That review runs on pull_request_target, so the secret is available while PR
code is never checked out. lgtmaybe only reads the diff via the API. See
Use as a GitHub Action for the full workflow,
including who can trigger a review.
Run locally¶
export OPENROUTER_API_KEY=sk-or-...
lgtmaybe review --provider openrouter --model anthropic/claude-sonnet-4-6
You can pass the key inline with --api-key sk-or-... instead of the env var.
The key is read from the environment or the flag and is never persisted to
config.
Choosing the model¶
OpenRouter models are named vendor/model. Pick whichever fits your budget and
quality bar, for example:
anthropic/claude-sonnet-4-6openai/gpt-5.5z-ai/glm-4.6
Browse the full catalogue and per-model pricing at https://openrouter.ai/models.
One catalogue quirk: a model can accept JSON-schema mode through OpenRouter yet
return replies that parse as empty, so a review comes back with zero findings
and no error (seen with anthropic/claude-fable-5.1). If a model is silent on
everything, try one diff with --no-structured-output — see
Configure .lgtmaybe.yml — before
writing the model off.
Credit reservations¶
OpenRouter checks your balance before it generates anything, costing the worst case: the prompt plus the most tokens the reply could use. A request that sends no cap is assumed to want the model's full output ceiling, so a review can be refused for credit it was never going to spend:
This request requires more credits, or fewer max_tokens.
You requested up to 65536 tokens, but can only afford 25905.
OpenRouter reviews send a default cap of 16384 tokens per call, so the
reservation already matches a realistic findings payload rather than the model's
full ceiling. If a refusal still names a number larger than that, something has
overridden the default — check the per-call budget resolved log line, which
names the ceiling and where it came from:
per-call budget resolved timeout_s=1800 max_tokens=16384 max_tokens_source="provider default"
Top up, or lower the cap further so the reservation fits your balance:
max_tokens: 8192
--max-tokens 8192 does the same for one run, and max_tokens is a GitHub
Action input too. Set it lower with care: a cap set too low truncates the
findings JSON mid-object, and reasoning models spend this same budget on thinking
tokens, so they need more headroom than a plain model. max_tokens: 0 removes
the cap entirely and puts the reservation back to the model's full ceiling.
lgtmaybe treats this refusal as permanent and stops after one attempt — your balance cannot grow mid-review, so retrying every lens would only waste runner time before reporting the same failure.
Rate limits¶
A capacity 429 is different: it is temporary, and lgtmaybe handles it for you.
Rate-limited calls back off on a 5s–60s ladder — long enough to reach a fresh
per-minute window — and honour OpenRouter's own Retry-After when it sends one
(clamped at 120s). A lens still failing on the provider when the fan-out drains
is re-run once more. That rescue is only for provider-side failures: unparseable
output, a blown max_tokens ceiling, a batch the oversized-diff split already
retried, an unrecoverable failure like a spent quota, and any ceiling you set
(max_review_seconds, max_review_tokens, a cancelled job) are all left alone,
because a second attempt would buy the same answer at full price. You will
usually see none of this; a review that could not recover says so in its
summary, and names the lens it lost.
If you are seeing rate limits, the review's own burst is worth a look before
the model is. Every (batch, lens) call shares one concurrency pool and one API
key, so a wide fan-out can meter itself:
max_concurrency: 3
Beyond that it is an account question rather than a lgtmaybe one. OpenRouter's
limits on free model variants (the :free suffix) are account-wide rather
than per-model, and the daily allowance depends on how much credit the account
has bought — so the same review is far more likely to be throttled on a free
variant than a paid one. Paid models carry no OpenRouter platform request
cap, though the upstream provider behind a given model can still rate-limit you.
Neither is the same thing as a per-key credit spending cap, which limits what a
key may spend, not how often it may call.
Persist non-secret defaults¶
provider: openrouter
model: anthropic/claude-sonnet-4-6
With that file in place, lgtmaybe review needs no flags. See
Configure .lgtmaybe.yml for every knob.