Timeouts — --timeout
--timeout bounds a whole CommitBrief run and raises the hard cap each provider enforces on its own — the CLI tools' 5 minutes, ollama's 5, the Anthropic SDK's 10 — because a context deadline can only cut a run short, never lengthen it.
--timeout puts a budget on a run. Unlike an ordinary deadline it can
make a run longer, because the value is handed down to the provider
and replaces the cap that provider enforces on its own. New in v1.16.0
(ADR-0038).
commitbrief --staged --cli claude --timeout 20m # let the host CLI think
commitbrief --staged --timeout 600 # bare integer = seconds
commitbrief config set review.timeout 15m # make it the default
commitbrief --staged --timeout 0 # ignore that default once
The caps it replaces
Every provider ships a hard limit you never chose and cannot see:
| Provider | Built-in cap | Enforced by |
|---|---|---|
claude-cli / gemini-cli / codex-cli |
5 minutes | the subprocess is killed |
ollama |
5 minutes | the HTTP client’s whole-request timeout |
anthropic |
10 minutes | the SDK refuses rather than waits |
openai, deepseek, mistral, cohere, gemini |
none | they follow the run’s own deadline |
doctor’s per-provider probe |
5 seconds | deliberately impatient |
Past 10 minutes the Anthropic SDK does not wait and then fail — it declines up front with “streaming is required for operations that may take longer than 10 minutes”.
On a large diff, or a mid-size local model on modest hardware, those caps are exactly what ends a run.
Why a deadline alone would not have fixed it
Worth understanding, because it explains what the flag actually does.
Wrapping a run in a deadline is the obvious implementation, and on its
own it is wrong: a deadline can only ever cut a run short. The CLI
backend derives its own child context from the caller’s, so asking for 20
minutes still yields min(5m, 20m) and dies at five. Ollama’s HTTP
timeout fires independently of the context entirely. And the Anthropic
ceiling is a pre-flight refusal, not a wait.
So --timeout does both: it sets the deadline and hands the value to
the provider, which replaces the built-in cap. Asking for more time
actually gets you more time.
Accepted values
A Go duration or a bare whole number of seconds:
90s 10m 1h30m 1500ms 600
The bare integer is supported on purpose — --timeout 600 is what CI
authors reach for, and rejecting it for a missing unit would be a papercut
with no upside.
An invalid or negative value fails before the diff is read, let alone sent to a provider. There is no wasted round-trip.
Resolution order
--timeout → review.timeout → the provider's built-in
Unset, nothing changes: every built-in cap stays exactly where it was.
--timeout 0 means “no deadline, use the built-ins”, which is how you
cancel a configured review.timeout for a single run.
# ~/.commitbrief/config.yml or <repo>/.commitbrief/config.yml
review:
timeout: "15m"
The key is a string, not a number of nanoseconds, so the file stays
readable. It is validated when you write it —
commitbrief config set review.timeout ten-minutes is rejected there
instead of breaking every later run.
What the budget covers
The whole run: diff acquisition, prompt build, the provider call, rendering — and the time you spend at a confirmation prompt like the cost preflight or the secret scanner.
That last one is deliberate rather than accidental. A review parked on a prompt nobody is there to answer is exactly as stuck as one parked on a provider. If you set a short timeout on an interactive run, expect it to be able to expire while waiting on you.
It applies to every command that can spend real time — reviews, commit,
summary, compress, remote pr, guard, leaks, map — plus two
worth calling out.
doctor
The per-provider connection probe fast-fails at 5 seconds so doctor
never leaves you staring at a blank terminal. On a high-latency network
that reports a link which is merely slow as unreachable — the wrong
diagnosis to hand someone who is already debugging their setup:
commitbrief --timeout 30s doctor
mcp
On the MCP server it is a per-tool-call
budget, not a lifetime for the process. A long-lived stdio server must
never carry a deadline, so both commitbrief mcp --timeout 10m and a
configured review.timeout bound each review call individually.
When it expires
A normal failure — exit code 1, and a message that names the duration and points back at the flag:
Error: timed out after 3s — the run was stopped by --timeout /
review.timeout, not by the provider. Pass a larger --timeout (e.g.
--timeout 20m) to allow more time, or --timeout 0 to fall back to the
provider's own limit.
Providers report a deadline in three different dialects, so CommitBrief checks the run’s own clock rather than trying to pattern-match error text. The result is that a self-inflicted deadline is never mistaken for a provider outage.
See also
- Providers — per-provider behavior and setup.
- Configuration — every config key, including
review.timeout. - Troubleshooting — when a run fails for some other reason.