Providers
The named provider registry β model-plane connections that judge and fleet consume by name.
A provider is a named entry in the providers section of
bro.config.json β { type, β¦connection }. Consumers pick by name; the name carries no
semantics. The type fixes the connection shape and which surfaces the
entry can serve. There is no bro providers command β providers are
configured, and bro doctor reports the resolved set (a misnamed
apiKeyEnv, an unset env var, a bad model).
{
"providers": {
// One API host, many models β each model declares its wire.
"orcarouter": { "type": "api", "baseUrl": "https://api.orcarouter.ai",
"apiKeyCommand": "secret-tool lookup service typesafe.ai",
"models": {
"typesafe/jev-1.13": "systemone",
"acme/cheap-chat": "openai-compat",
"acme/auto-x": null // inferred
} },
"kilo-cli": { "type": "acp", "command": "kilo --acp",
"model": "typesafe/jev-1.13" },
"local": { "type": "cli", "command": "devin -p --prompt-file {promptFile}",
"model": "devin-1" }
}
}Kinds and surfaces
| kind | call (judge) | spawn (fleet) |
|---|---|---|
api | by model wire β systemone typed, openai-compat prose | β |
acp | typed on a jev-family model, else prose | yes |
cli | prose β stdout parsed | yes β the loop.agent template contract |
- An
apientry is a host + auth + amodelsallowlist β{ "<model-id>": "systemone" | "openai-compat" | { "wire": β¦ } | null }.null/absent infers the wire:jev-family ids βsystemone, everything else βopenai-compat.modelpins the default; ajudge.modelor per-call override must name an allowed id β anything else is a config error listing the allowlist. Auth isapiKeyEnv(the env var name) orapiKeyCommand(a secret-store lookup β the key never sits in the config file). cli.commandis a shell template:{promptFile}expands to the quoted prompt-file path (appended as the last arg when absent),{model}to the resolved effective model. stdout is the answer. A model override the template can't consume is a loud error, not a relabel β provenance never claims a model the worker didn't run.- An
acpentry's call grade is decided by the served model βtypesafe/jev-*(or barejev-*) is typed transport; anything else is prose and stampsprovider:<name>:proseindecidedBy.
Consumer wiring
- Judge β
judge.provider: '<name>'+judge.model: '<allowed-id>'(+judge.fallback: '<name>'). The resolved model's wire picks the adapter. A prose-grade answer is never counted as a calibrated typed judgment βdecidedBysays which. - Fleet β
agents.<backend>.provider: '<name>'orfleet.profiles.<p>.providerβ the provider supplies what runs inside the backend's spawn; provenance ridesBRO_AGENT_PROVIDER/BRO_AGENT_MODELinto the registry entry andbro fleetoutput.
No defaults, no hardcoding: absent providers means provider behavior
is off β a consumer naming a missing entry errors rather than silently
vendoring a fallback.