brazen 0.0.6

A stateless, swiss-army-knife adapter for every LLM provider and protocol.
Documentation
# Embedded provider table (arch §4.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.

# 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.
timeout = 120

[[provider]]
name = "anthropic"
base_url = "https://api.anthropic.com"
protocol = "anthropic_messages"
auth = "api_key"
api_header = { name = "x-api-key", scheme = "raw" }
beta_headers = [["anthropic-version", "2023-06-01"]]
body_defaults = { max_tokens = 4096 }   # Anthropic requires max_tokens; the row's sane default, overridable via config/flag (config §4.1)
model_prefixes = ["claude-"]            # owns the claude- family, so `bz -m claude-… "q"` routes here with no --provider (arch §4.3)
ambient = { format = "api_key_env", path = "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)

[[provider]]
name = "openai"
base_url = "https://api.openai.com/v1"
protocol = "openai_chat"
auth = "bearer"
api_header = { name = "Authorization", scheme = "bearer" }
model_prefixes = ["gpt-", "chatgpt-", "o1", "o3", "o4"]   # the OpenAI families; openai-responses (same models, other protocol) ships none, so it stays explicit (arch §4.3)

# Mistral speaks the OpenAI chat dialect verbatim — the severability proof: one
# row, ZERO Rust (providers §2). Reuses the OpenAiChat protocol + bearer auth.
[[provider]]
name = "mistral"
base_url = "https://api.mistral.ai/v1"
protocol = "openai_chat"
auth = "bearer"
api_header = { name = "Authorization", scheme = "bearer" }
model_prefixes = ["mistral-", "ministral-", "magistral-", "codestral-", "pixtral-"]

[[provider]]
name = "openai-responses"
base_url = "https://api.openai.com/v1"
protocol = "openai_responses"
auth = "bearer"
api_header = { name = "Authorization", scheme = "bearer" }
# 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).

# Google authenticates with a custom header NAME carrying the raw key — pure row
# DATA read by the shared ApiKeyAuth, no new Auth impl (providers §4.1).
[[provider]]
name = "google"
base_url = "https://generativelanguage.googleapis.com"
protocol = "google_generative_ai"
auth = "api_key"
api_header = { name = "x-goog-api-key", scheme = "raw" }
model_prefixes = ["gemini-"]

# 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).
[[provider]]
name = "ollama"
base_url = "http://localhost:11434"
protocol = "ollama_chat"
auth = "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).
[[provider]]
name = "claude-code"
protocol = "claude_code"
auth = "none"
exec = "claude"
unsupported_body_keys = ["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.
[[provider]]
name = "openai-chatgpt"
base_url = "https://chatgpt.com/backend-api/codex"
protocol = "openai_responses"
auth = "oauth2"
api_header = { name = "Authorization", scheme = "bearer" }
unsupported_body_keys = ["max_tokens", "temperature", "top_p"]   # the Codex backend 400s on each; stripped pre-encode (config §4.1.1)

[provider.oauth]
authorize_url = "https://auth.openai.com/oauth/authorize"
token_url = "https://auth.openai.com/oauth/token"
client_id = "app_EMoamEEZ73f0CkXaXp7hrann"                       # Codex's published public client (auth §10.5)
scope = "openid profile email offline_access api.connectors.read api.connectors.invoke"
redirect = { host = "localhost", port = 1455, path = "/auth/callback" }   # the registered loopback redirect, byte-exact (auth §10.1)
authorize_params = [["id_token_add_organizations", "true"], ["codex_cli_simplified_flow", "true"], ["originator", "codex_cli_rs"]]   # auth §10.2
account_header = "ChatGPT-Account-ID"                            # name is row data, value is the cred's account_id (auth §10.4)
beta_headers = [["originator", "codex_cli_rs"]]                  # static data-plane header (auth §4)

[provider.body_defaults]
store = false   # the Codex backend 400s unless store:false; rides the request's passthrough valve (config §4.1)

[provider.models]
path = "/models"
query = [["client_version", "0.0.0"]]   # /models 400s without it; the sub-release sentinel returns the FULL catalog (model-discovery §3.2)
array_key = "models"                    # Codex returns {"models":[…]}, not the protocol-default {"data":[…]}
id_key = "slug"                         # each entry's id is `slug`, not `id`