Eleven providers ship in @husk-ai/models. Three have their own wire format and their own
file; the rest speak OpenAI's /v1/chat/completions dialect and are configuration
rather than code.
| Provider | Priority | Environment variable | Free tier |
|---|---|---|---|
anthropic | 95 | ANTHROPIC_API_KEY | no |
openai | 85 | OPENAI_API_KEY | no |
google | 80 | GOOGLE_API_KEY or GEMINI_API_KEY | yes |
groq | 60 | GROQ_API_KEY | yes |
deepseek | 58 | DEEPSEEK_API_KEY | no |
cerebras | 56 | CEREBRAS_API_KEY | yes |
openrouter | 55 | OPENROUTER_API_KEY | yes, on :free models |
mistral | 52 | MISTRAL_API_KEY | no |
together | 50 | TOGETHER_API_KEY | no |
lmstudio | 42 | none — LMSTUDIO_HOST moves the endpoint | local, so free |
ollama | 40 | none — OLLAMA_HOST moves the endpoint | local, so free |
Priority is the quality ordering auto walks, highest first. It is not a statement about
which provider is better at your task.
A provider with no key set is not an error. It is reported, with the fix:
Setting a key
Husk reads keys from the process environment. Nothing is stored in ~/.husk, and no
command writes a key to disk.
export ANTHROPIC_API_KEY=sk-ant-...
husk doctor # confirms it tookFor a persistent, non-shell-history setup, ~/.husk/.env is the file Husk reserves for
local overrides. On Windows, setx ANTHROPIC_API_KEY "sk-ant-..." and open a new
terminal.
The three first-party providers
anthropic
export ANTHROPIC_API_KEY=sk-ant-... # console.anthropic.com
export ANTHROPIC_BASE_URL=... # optional, for a proxyCatalogued models: claude-opus-5, claude-sonnet-5, claude-haiku-4-5-20251001. All
three support tools, vision, streaming and extended thinking, with a 200k context
window.
Three things here are not shared with the OpenAI dialect, and they are why this provider
has its own file: tool results ride inside a user message rather than a tool role,
extended thinking is a content block whose signature must be echoed back verbatim, and
prompt caching is opt-in per block.
Caching is placed on exactly two blocks — the system prompt, and the last stable user
turn. Every cache_control marker costs a cache write, and marking the newest turn
caches a prefix that will never be seen again.
Anthropic is also the one provider here that charges to write a cache entry. The
catalog carries cacheWritePerMTok as an explicit price rather than a multiplier,
because the write price is not a fixed fraction of input anywhere else.
When you enable thinking, Husk raises max_tokens to at least the thinking budget plus
1024 and drops temperature and top_p, because the API rejects a sampling override
while thinking is on.
openai
export OPENAI_API_KEY=sk-... # platform.openai.com
export OPENAI_BASE_URL=... # optional, for a compatible gatewayCatalogued: gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-5, gpt-5-mini, gpt-4o,
gpt-4o-mini, o3, o4-mini.
This is the base dialect plus the quirks OpenAI's own models have. Anything matching
o1–o9 or gpt-5 is treated as a reasoning model: max_tokens becomes
max_completion_tokens, temperature and top_p are deleted, and a thinking budget is
mapped onto reasoning_effort.
| Thinking budget | reasoning_effort |
|---|---|
| unset | medium |
| ≤ 2048 | low |
| 2049–16383 | medium |
| ≥ 16384 | high |
Sending the wrong parameter name to a reasoning model is a 400, and a 400 is the one error class the router will not retry — so getting this right here is the difference between a working request and a dead one.
export GOOGLE_API_KEY=AIza... # aistudio.google.com; GEMINI_API_KEY also read
export GOOGLE_BASE_URL=... # optionalCatalogued: gemini-2.5-pro, gemini-2.5-flash, gemini-2.5-flash-lite. Flash and
Flash-Lite are marked free — reachable at zero cost on the Gemini API free tier, at a
low rate limit. Pro is not.
Gemini is genuinely a different wire format, not a dialect: contents instead of
messages, model instead of assistant, function results keyed by name rather
than by call id, and a JSON Schema subset that rejects half of draft-07. Each of those
is a translation @husk-ai/models owns.
The OpenAI-compatible providers
Each of these is a base URL, an environment variable and at most one quirk. If you find yourself needing a method for one, the quirk belongs behind a config flag instead.
groq — free tier
export GROQ_API_KEY=gsk_... # console.groq.com/keysCatalogued: llama-3.3-70b-versatile, llama-3.1-8b-instant. Both are marked free and
both support tools. Groq's selling point is latency; the 70B is the most capable
genuinely-free hosted model in the catalog.
cerebras — free tier
export CEREBRAS_API_KEY=... # cloud.cerebras.aiCatalogued: llama-3.3-70b, llama3.1-8b, both marked free. Cerebras rejects
stream_options.include_usage, so Husk does not send it — which means token counts on a
streamed Cerebras call come from Husk's own estimate rather than from the provider.
openrouter — free on :free models
export OPENROUTER_API_KEY=sk-or-... # openrouter.aiOpenRouter is one of three providers Husk asks for a live catalogue instead of trusting
the static one. The :free suffix is the whole pricing signal:
deepseek/deepseek-chat bills and deepseek/deepseek-chat:free does not, so a
discovered model ending in :free is priced at zero and is eligible for --model free.
Husk sends OpenRouter's two attribution headers, http-referer: https://github.com/Hotragn/husk and
x-title: Husk. Without them your calls are filed as anonymous on OpenRouter's activity
page.
deepseek
export DEEPSEEK_API_KEY=... # platform.deepseek.comCatalogued: deepseek-chat, deepseek-reasoner. Both prices are conservative estimates,
not published figures — see Cost.
mistral
export MISTRAL_API_KEY=... # console.mistral.aiCatalogued: mistral-large-latest, mistral-small-latest. Mistral's endpoint rejects
unknown top-level stream options, so stream_options is not sent.
together
export TOGETHER_API_KEY=... # api.together.ai/settings/api-keysCatalogued: meta-llama/Llama-3.3-70B-Instruct-Turbo, Qwen/Qwen2.5-Coder-32B-Instruct.
Together is asked for a live catalogue. Note that a Together model id contains a slash
of its own; Husk splits provider/model at the first slash only, so
together/meta-llama/Llama-3.3-70B-Instruct-Turbo resolves correctly.
lmstudio — local
No key. Husk probes http://127.0.0.1:1234/v1/models with a 2-second timeout and treats
everything LM Studio serves as free.
export LMSTUDIO_HOST=http://192.168.1.20:1234/v1 # optional, to point elsewhereUnavailable reads as http://127.0.0.1:1234/v1 is not listening, with the fix
Start the LM Studio local server (Developer tab) and load a model.
ollama — local
No key. Husk lists what is actually pulled on the machine — never a catalogue of models
you would have to download first — and reads the real context window and tool support
from /api/show.
export OLLAMA_HOST=http://127.0.0.1:11434 # the defaultLocal models is the end-to-end setup for both of these.
Self-hosting a compatible endpoint
Anything that speaks /v1/chat/completions can be pointed at through the base-URL
override of a provider you are not otherwise using:
export OPENAI_BASE_URL=http://10.0.0.5:8000/v1
export OPENAI_API_KEY=whatever-your-gateway-wants
husk modelsHusk will apply OpenAI's reasoning-model quirks to any model id matching o1–o9 or
gpt-5, so avoid those names on a gateway that does not want them.
What Husk sends where
Model requests go to the provider you configure. Other tasks may contact public sources, search providers, remote computers, and image registries. The installed runtime has no product telemetry or crash reporter; the hosted website and docs use Vercel Web Analytics.