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

ProviderAuthenticationModel
anthropicANTHROPIC_API_KEYclaude-opus-5 by default
openaiOPENAI_API_KEYnone shipped — you must set one
claude-cliYour logged-in claude sessionrequired in config
codex-cliYour logged-in codex sessionoptional

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_url may 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 (or openai with a model set).
  • You already pay for a Claude or ChatGPT subscription and would rather not add API billing → claude-cli or codex-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.