Models & providers
Every provider below uses one of three wire protocols: Anthropic Messages, OpenAI
chat completions, or Ollama's native API. Pick a provider during setup or re-run
bwn init. Environment variables override stored keys. With no saved setup and no
terminal, as in CI, bwn uses the first provider whose key is set, or the one
named with --provider.
| Provider | Kind | Key |
|---|---|---|
| Anthropic (Claude) | remote | ANTHROPIC_API_KEY |
| OpenAI | remote | OPENAI_API_KEY |
| OpenRouter | remote | OPENROUTER_API_KEY |
| Groq | remote | GROQ_API_KEY |
| Hugging Face | remote | HF_TOKEN |
| Ollama | local | — |
| llama.cpp server | local | — |
| LM Studio | local | — |
| OpenAI-compatible endpoint | remote or local | CUSTOM_API_KEY (optional) |
Switching models with /model
/model switches the model and the provider mid-session. Before it saves
anything or reports success, it sends a one-token probe through the real request path to check
the key, the model name, and the server. For Ollama, it checks the list of installed models
instead, because a probe could spend minutes loading a large model. If the API key is missing,
/model prompts you for it. If Ollama is not running, it shows the steps to install
Ollama, start the server, and pull the model. If the probe fails, you keep your current
model.
/model gpt-4o # provider inferred and validated
/model ollama/qwen2.5-coder # checked against `ollama list` first
/model meta-llama/llama-3.3-70b # any OpenRouter model, by org/model name
/model http://localhost:8000/v1 my-model # any OpenAI-compatible server (vLLM, TGI, LiteLLM)
Custom endpoints work without a key, which is how vLLM runs by default. If you set
CUSTOM_API_KEY, bwn refuses to send it over plain HTTP to anything but a loopback
address. bwn saves a custom endpoint's key for that endpoint only, so /model to a
new address asks for that address's key. CUSTOM_API_KEY from the environment goes
to one custom endpoint per run, the first one bwn looks up a key for. When the run starts on a
custom endpoint, that is the one.
Local models
To run with no API key and keep your code on your machine:
- Install Ollama from ollama.com
and start it. The desktop app starts the server. If you don't use the desktop app,
run
ollama serve. - Pull a coding model:
ollama pull qwen2.5-coder. - Run
bwnand pick Ollama at setup, or switch an existing setup with/model ollama/qwen2.5-coder.
On the native Ollama path, bwn reads each model's context window from Ollama and sets
num_ctx to match, up to 32k. This stops Ollama from truncating long prompts without
warning. A num_ctx set in the model's Modelfile wins, even above 32k, up to the
model's own maximum. When Ollama does not report the window, bwn uses 8,192 tokens. To use a
different value, set context_tokens.
A model with a context window under 32k tokens gets a compact set of 10 tools instead of the
full set, because small models make more mistakes with a long tool list. On Ollama, llama.cpp,
LM Studio and any OpenAI-compatible endpoint, even a remote gateway, bwn assumes 8,192 tokens
when the server does not report the window. Such a model gets the compact set. If the real
window is 32k or more, set context_tokens to it to get the full set. MCP tools you
add stay in the compact set.
Some small models write tool calls as text instead of native tool calls. Qwen2.5-Coder wraps
them in tags such as <tool_call>, and Gemma writes a Python-style call in a
tool_code fence. bwn parses those calls, so a model as small as 1.5B parameters can
write files. bwn runs such a call only when it opens the reply, or ends the reply after one short
lead-in line. A call inside an explanation stays text.
Timeouts and redirects
Connecting times out after 15 seconds. A streamed reply may pause for up to 300 seconds
between chunks. On slower local hardware, set BWN_READ_TIMEOUT_SECS to a higher
value. bwn retries a request only when it could not connect, or when the server replied with
HTTP 429, 500, 502, 503, 504 or 529. It retries 3 times by default. A server that answers 503
while it loads a model gets 14 retries, about two minutes. BWN_MAX_RETRIES replaces
both counts with one value from 0 to 20. bwn retries a refused connection once, whatever the
setting. bwn does not retry an out-of-memory error. If a request times out or its connection
drops after bwn sent it, bwn reports
the error. It does not send the request again, because the server may still be working on
it.
bwn does not follow redirects, so your API key goes only to the base_url you set.
A 3xx reply becomes an error that names the redirect target.
Vision
bwn sends image and video attachments only to models that accept images. Every current
Claude model accepts images. For a model on Ollama, LM Studio or llama.cpp, bwn asks the server
first, unless context_tokens is set. Ollama lists the model's capabilities, LM
Studio reports the model type, and llama.cpp reports its modalities. When bwn does not ask, or
the server says nothing, bwn decides from the model name, for example gpt-4o, o3, gemini,
llava, qwen-vl, gemma3, llama3.2-vision or moondream. Set "vision": true or
"vision": false in settings.json to decide for yourself. For a text-only model, bwn
prints a notice instead of dropping the attachment without telling you.
See Multimodal input.
Some local vision models, such as gemma3 on Ollama, have no native tool
calling. When the server replies "does not support tools", bwn lists the tools in the system
prompt instead and reads the calls from the model's text. The same model can then look at a
screenshot and edit files. bwn prints this once per session:
⟳ gemma3:4b has no native tool calling — describing tools in the prompt instead.
bwn stores keys in ~/.buildwithnexus/.env.keys. On Linux and macOS the file has
mode 0600. On Windows, bwn restricts it to your user account.
Data & privacy lists what each request carries and what stays on
your machine.
If your API key was rejected
An HTTP 401 or 403 from a remote provider means the key is wrong, revoked, or belongs to
another account or project. Run bwn init and enter the new key for the same
provider. Or set the provider's environment variable, such as ANTHROPIC_API_KEY,
which overrides the stored key. A local server needs no key. A gateway behind the
custom provider reads CUSTOM_API_KEY.
New in 0.15. Run /login in a session, or
buildwithnexus login, to replace the stored key. bwn checks the new key with the
provider before saving it. In a session, the error for a rejected key points to
/login. In a headless run such as bwn run, it names
buildwithnexus login or the provider's key variable. The /model picker
labels that provider key rejected. See
What's new in 0.15.
Reasoning depth
/effort off|low|medium|high sets the reasoning depth. You can also set it with
--effort or with "reasoning_effort" in settings. The default is
off. bwn maps the level to each API's own control. Claude 4.6 and later get adaptive
thinking with an effort level, and earlier Claude models get a thinking budget. OpenAI reasoning
models, meaning the o-series and GPT-5, get reasoning_effort. Native Ollama gets
think. When an Ollama model answers that it does not support thinking, bwn sends
the request again without think and leaves it off for that model for the rest of
the session. bwn never sends reasoning parameters to non-reasoning or local
OpenAI-compatible models.
Tokens and cost
bwn records the token usage the server reports for every reply: input, output, cache read,
and cache write. /cost shows the session totals and an estimated price for known
models. Local servers show $0.00 (local). Unknown models show tokens only, and bwn
never makes up a price for them. /context uses the measured size of the last request
when one is available, and then labels the total "measured from the last request".
--max-budget-usd 2 or
"max_budget_usd": 2 stops the agent before the next request once the estimated cost
passes the limit. To give a price to a model the built-in table does not know, add it under
"prices" in settings.json, in USD per million tokens. With a cap set, bwn sends no
request to a model with no known price, because it could not count the cost. At startup it
exits with code 2 and asks for a prices entry. A model on Ollama's native API, even
on another machine, and any server on a loopback address are exempt, because bwn counts them as
free. Anthropic requests carry prompt-cache breakpoints on the system prompt and the last
message.
Native tools on local servers
With llama.cpp, LM Studio, vLLM and any OpenAI-compatible server on a loopback address, bwn sends native tool schemas on the first try. It retries once without native tools when an HTTP 400 error names tools, or when the error rejects the message roles or says the model "does not support" something, such as images. A retry after an error that names images also leaves the images out. When the 400 behind the retry names tools, the chat template or message roles, bwn sends every later request to that endpoint without native tools for the rest of the session. After any other rejection, the next request tries native tools again. If a model still answers with tool calls in tagged text, the recovery parser reads them.