Configure
Providers
Two providers talk to an API with a key. Two shell out to a CLI you are already logged into. They are not interchangeable.
The four
| Provider | Authentication | Model |
|---|---|---|
anthropic | ANTHROPIC_API_KEY | claude-opus-5 by default |
openai | OPENAI_API_KEY | none shipped — you must set one |
claude-cli | Your logged-in claude session | required in config |
codex-cli | Your logged-in codex session | optional |
Switch with the config file:
provider: openai
providers:
openai:
model: gpt-4.1-mini
…or for one call only:
smartly --provider claude-cli --model haiku --dry-run list the largest files here
API-backed providers
anthropic and openai use the official SDKs and a billed API key. They are
the fast path: one HTTP request, precise typed errors, no extra processes.
anthropic is the default and needs nothing but ANTHROPIC_API_KEY in your
environment. openai ships no default model, so setting
providers.openai.model is mandatory before it will run.
Both accept an optional base_url, for a self-hosted or proxied endpoint.
Any OpenAI-compatible API
The openai provider is not limited to OpenAI. It speaks the Chat Completions
API, which most inference vendors implement, so pointing base_url at one is
enough — Fireworks, Together, Groq, DeepInfra, OpenRouter, Azure OpenAI, or
anything local like vLLM, Ollama or LM Studio.
Three settings, and the second is the one people miss:
provider: openai
providers:
openai:
model: accounts/fireworks/models/llama-v3p1-70b-instruct
api_key_env: FIREWORKS_API_KEY
base_url: https://api.fireworks.ai/inference/v1
model is that vendor’s model id, not an OpenAI name. It is passed through
verbatim, so it needs to be exactly what the provider’s own docs list —
accounts/fireworks/models/... for Fireworks, meta-llama/... for Together,
whatever your local server reports for vLLM.
base_url is the root the API is served from, including the version
segment — for Fireworks that is https://api.fireworks.ai/inference/v1, and
smartly appends /chat/completions itself. A trailing slash makes no
difference either way.
Then set the key and go:
export FIREWORKS_API_KEY="fw-..."
smartly --dry-run show hidden files sorted by size
smartly config show will confirm what resolved, and reports only whether a
key was found — never its value.
What to expect
- Any endpoint that implements Chat Completions works. smartly deliberately uses that endpoint rather than the newer Responses API, precisely because compatible servers implement Chat Completions and frequently do not implement the other one.
- Error messages get vaguer. smartly maps failures into the same
auth/rate-limit/overloaded/network taxonomy, but third-party servers vary in
what they return, so a misconfigured
base_urlmay surface as a generic failure rather than a precise one. - Command quality tracks the model, not smartly. Smaller open-weight models are likelier to emit prose, a code fence, or a multi-line answer — all of which smartly rejects outright rather than trying to salvage. If a model gives you frequent “unclean response” errors, that is the model, and a larger instruct-tuned one will fix it.
CLI-backed providers
If you already pay for Claude Pro/Max or ChatGPT Plus/Pro, claude-cli and
codex-cli let smartly shell out to your own logged-in session instead of a
separately billed API key.
Log in yourself first — smartly does not manage that login state:
claude login # for provider: claude-cli
codex login # for provider: codex-cli
If the binary is missing or the session is not authenticated, smartly hard-fails with an actionable error rather than silently falling back to an API key.
The tradeoffs
These are real and worth knowing before you switch:
- Slower. Every request spawns a full CLI process, not a lightweight API call.
- Heuristic error classification. Without HTTP status codes, failures (authentication versus anything else) are detected from the exit code plus substring-matching on the CLI’s own text output, not a precise typed error like the SDK-based providers use.
claude-cli
Fully tool-disabled and effectively single-shot. It always runs with
--safe-mode — OAuth authentication without loading your CLAUDE.md, hooks,
plugins or MCP servers — and --tools "", meaning no tool access at all. Asked
to run a command anyway, it declines in text.
model is required in config for this reason: omitting it triggers an internal
multi-model routing step that makes it unclear which model actually produced the
result.
provider: claude-cli
providers:
claude-cli:
model: haiku
binary: claude
max_budget_usd: 0.50
codex-cli
Sandboxed but still agentic. There is no flag to disable tool and shell
execution entirely, so it always runs with --sandbox read-only — a real
OS-enforced boundary. The model may still attempt sandboxed read-only shell
commands while composing its answer, and occasionally its response narrates a
failed self-attempted command rather than being a clean answer.
provider: codex-cli
providers:
codex-cli:
model: "" # optional; omitted if unset
binary: codex
Choosing
- You want it fast and you have an API key →
anthropic(oropenaiwith a model set). - You already pay for a Claude or ChatGPT subscription and would rather not add
API billing →
claude-cliorcodex-cli, accepting the extra latency. - You want the strictest generation behaviour of the two CLI options →
claude-cli, which has no tool access at all.