# 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.

CommitBrief docs · v1.x · Operations

Canonical URL: https://commitbrief.com/docs/1.x/timeouts

---

`--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).

```sh
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.

```yaml
# ~/.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](/docs/1.x/safety-and-cost#cost-preflight) or the
[secret scanner](/docs/1.x/safety-and-cost#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:

```sh
commitbrief --timeout 30s doctor
```

### `mcp`

On the [MCP server](/docs/1.x/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](/docs/1.x/providers) — per-provider behavior and setup.
- [Configuration](/docs/1.x/configuration) — every config key, including
  `review.timeout`.
- [Troubleshooting](/docs/1.x/troubleshooting) — when a run fails for
  some other reason.