1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# Embedded provider CATALOG (arch §4.2, config §3.2). Parsed through the SAME
# `toml::from_str::<PartialConfig>` path as a user config file — the lowest-
# precedence operand of the resolution fold, never a bootstrap special case
# (config §3.5). A unit test parses this file so a malformed edit fails the
# build, not a user run.
#
# Every row here is a PRESET: it says how to reach a provider, not that you use
# it. A preset enters the routing table — what a bare `bz "q"` or a model prefix
# can reach, and what `--list-providers` prints — only once an act of yours
# touches it: you name it in your config file (`[[provider]] name = "ollama"`
# is enough; the preset fills the rest), or a credential resolves for it (a
# `bz --login`, the vendor env var named by `ambient`, a sibling tool's sign-in,
# or an inline --api-key). Until then it costs nothing and is reachable only by
# explicit `--provider`. `bz --login` with no `--provider` lists the presets
# that can sign in.
#
# Rows with `auth = "bearer"` / `"oauth2"` name no `api_header`: a bearer token
# rides `Authorization: Bearer …` (RFC 6750), so resolution supplies that header
# and the row states the fact once (auth §3.1). `api_key` rows must still name
# their vendor header.
# The transport SILENCE budget in whole seconds (config §4.3, architecture §13.15).
# The single home for this number — `bz` reads it off the resolved config and, via
# `timeouts()`, fans it onto ureq's connect + response-header + inter-chunk-idle
# budgets, so the bin holds no magic constant. It abandons an upstream that makes no
# progress (sends no bytes) for this long — applied per phase — WITHOUT capping total
# stream length, so a long-but-live generation is never cut (it is NOT a wall-clock
# total). Override in your config file / env / flag; delete this line to unbound it.
= 120
[[]]
= "anthropic"
= "https://api.anthropic.com"
= "anthropic_messages"
= "api_key"
= { = "x-api-key", = "raw" }
= [["anthropic-version", "2023-06-01"]]
= { = 4096 } # Anthropic requires max_tokens; the row's sane default, overridable via config/flag (config §4.1)
= ["claude-"] # owns the claude- family, so `bz -m claude-… "q"` routes here with no --provider (arch §4.3)
= { = "api_key_env", = "ANTHROPIC_API_KEY" } # vendor-conventional key alias as a ROW-SCOPED, store-miss source — below BRAZEN_API_KEY/--api-key, can't leak cross-vendor or shadow a stored cred (auth §5.5)
[[]]
= "openai"
= "https://api.openai.com/v1"
= "openai_chat"
= "bearer"
= ["gpt-", "chatgpt-", "o1", "o3", "o4"] # the OpenAI families; openai-responses (same models, other protocol) ships none, so it stays explicit (arch §4.3)
= { = "api_key_env", = "OPENAI_API_KEY" } # the vendor's conventional key var, row-scoped (auth §5.5) — and the act that puts this preset in the table
# Mistral speaks the OpenAI chat dialect verbatim — the severability proof: one
# row, ZERO Rust (providers §2). Reuses the OpenAiChat protocol + bearer auth.
[[]]
= "mistral"
= "https://api.mistral.ai/v1"
= "openai_chat"
= "bearer"
= ["mistral-", "ministral-", "magistral-", "codestral-", "pixtral-"]
= { = "api_key_env", = "MISTRAL_API_KEY" }
[[]]
= "openai-responses"
= "https://api.openai.com/v1"
= "openai_responses"
= "bearer"
= { = "api_key_env", = "OPENAI_API_KEY" } # the same key as `openai`: one var puts both OpenAI presets in the table
# No model_prefixes: openai-responses serves the SAME OpenAI model ids as `openai`
# over a different protocol. Claiming them would make every gpt-… ambiguous (78),
# so this alternate-protocol row stays opt-in via explicit --provider (arch §4.3).
# Local Ollama needs no auth: `auth = "none"` reads no credential and writes no
# header, so a keyless row carries no `api_header` (providers §5.1).
[[]]
= "ollama"
= "http://localhost:11434"
= "ollama_chat"
= "none"
# The installed Claude Code CLI as a pure model pass-through (claude-code spec): an
# EXEC-transport row — `exec` substitutes for base_url, `claude` carries its own
# OAuth so auth = "none". The five listed canonical fields have no wire slot on the
# CLI (spec §4.1), so they strip pre-encode. No model_prefixes: `anthropic` owns
# `claude-`; this alternate-transport row stays opt-in via explicit --provider,
# like openai-responses (arch §4.3.1).
[[]]
= "claude-code"
= "claude_code"
= "none"
= "claude"
= ["max_tokens", "temperature", "top_p", "stop", "output"]
# The ONE built-in OAuth row: "Sign in with ChatGPT" (auth §10). It ships so that
# `bz --login --provider openai-chatgpt --browser` works on a bare install — without
# it the binary offers NO reachable browser sign-in and a first-time user's only path
# to a credential is hand-authoring an api key into a config file (operator ruling
# 2026-08-16, reversing §10.5's deferred recommendation; §7's "no built-in OAuth row"
# is now "no built-in row whose vendor restricts third-party use" — see below).
#
# Shipping it compiles in NO vendor login policy: every field is row DATA the
# vendor-blind `OAuth2` impl reads off `AuthCtx` (auth §1.3, §7.1), so this row is
# severable — delete it and the capability goes with it, no Rust changes. The
# `client_id` is Codex's PUBLISHED PUBLIC client, and every value here was validated
# live end to end (auth §10.7).
#
# It is LAST and claims NO model_prefixes, so it moves nothing: `anthropic` stays the
# head row a bare `bz "q"` reaches, and this row — like `openai-responses`, whose
# models it serves over the same protocol — stays opt-in via explicit --provider
# (arch §4.3.1).
#
# NOT shipped, deliberately: an Anthropic subscription-OAuth row. That vendor's terms
# restrict third-party use of its subscription tokens, so neither the row nor a
# turnkey recipe for it is published (bl-a661). The general `oauth2` mechanism stays
# available to an operator who may use it — that is the README's generic block.
[[]]
= "openai-chatgpt"
= "https://chatgpt.com/backend-api/codex"
= "openai_responses"
= "oauth2"
= ["max_tokens", "temperature", "top_p"] # the Codex backend 400s on each; stripped pre-encode (config §4.1.1)
= { = "codex", = "~/.codex/auth.json" } # borrow the Codex CLI's own ChatGPT sign-in on a store miss, read-only (auth §5.5)
[]
= "https://auth.openai.com/oauth/authorize"
= "https://auth.openai.com/oauth/token"
= "app_EMoamEEZ73f0CkXaXp7hrann" # Codex's published public client (auth §10.5)
= "openid profile email offline_access api.connectors.read api.connectors.invoke"
= { = "localhost", = 1455, = "/auth/callback" } # the registered loopback redirect, byte-exact (auth §10.1)
= { = "https://auth.openai.com", = "codex" } # the headless sign-in: the AUTH BASE, whose /deviceauth/* + /codex/device the codex variant derives (auth §10.8)
= [["id_token_add_organizations", "true"], ["codex_cli_simplified_flow", "true"], ["originator", "codex_cli_rs"]] # auth §10.2
= "ChatGPT-Account-ID" # name is row data, value is the cred's account_id (auth §10.4)
= [["originator", "codex_cli_rs"]] # static data-plane header (auth §4)
[]
= false # the Codex backend 400s unless store:false; rides the request's passthrough valve (config §4.1)
[]
= "/models"
= [["client_version", "0.0.0"]] # /models 400s without it; the sub-release sentinel returns the FULL catalog (model-discovery §3.2)
= "models" # Codex returns {"models":[…]}, not the protocol-default {"data":[…]}
= "slug" # each entry's id is `slug`, not `id`