Model providers
Anymo uses OpenAI-compatible chat endpoints: local model servers like Ollama and LM Studio, routers, proxies, or hosted APIs. The model is a configuration choice, not an architectural one.
Setting a provider key
How you supply the key depends on how you run Anymo.
Headless CLI: environment variables
The CLI reads its provider settings from the environment and never writes a key to disk. Export them for the session that runs anymo:
export ANYMO_PROVIDER_BASE_URL=http://localhost:11434/v1 # e.g. Ollama; LM Studio uses :1234
export ANYMO_PROVIDER_MODEL=llama3.1
export ANYMO_PROVIDER_API_KEY=<your-api-key> # only hosted endpoints need a key
$env:ANYMO_PROVIDER_BASE_URL = "http://localhost:11434/v1"
$env:ANYMO_PROVIDER_MODEL = "llama3.1"
$env:ANYMO_PROVIDER_API_KEY = "<your-api-key>" # hosted endpoints only
Then run with anymo run --provider http. The key lives only in that process environment; local model servers usually need no key at all.
The workspace .anymo/config.toml holds a commented endpoint template. Keys belong in ANYMO_PROVIDER_API_KEY, never in that file.
Desktop app: sealed at rest
Open Settings → Model provider, enter the base URL, model, and an API key for hosted endpoints, then save. The desktop app seals saved keys at rest: the key is encrypted on disk with a master secret held in the OS keychain, with an encrypted-file fallback. Saved profiles persist across restarts, and a per-profile health check confirms the endpoint is reachable.
In both cases, keys never appear in events, logs, artifacts, or the UI.
How sealed storage works
Provider profile metadata is safe to serialize, but API keys are never written to profile JSON. Keys are stored through the native secret store:
- An OS keychain master key when the host keychain is available.
- An encrypted local fallback store when the caller supplies a passphrase or host-managed secret. The fallback file contains only nonces and ciphertext.
Do not commit local provider files, fallback passphrases, or real API keys.
Presets
The kernel exposes these presets:
| Preset | Base URL | Notes |
|---|---|---|
| Generic OpenAI-compatible | https://api.openai.com/v1 | Works for compatible hosted APIs and proxies; custom HTTPS URLs are also valid |
| OpenRouter-style | https://openrouter.ai/api/v1 | Adds sanitized example HTTP-Referer and X-Title headers; callers may replace them |
| Ollama | http://localhost:11434/v1 | Local endpoint only; non-local hosts are rejected for this preset |
| LM Studio | http://localhost:1234/v1 | Local endpoint only; non-local hosts are rejected for this preset |
| Custom base URL | caller-supplied | Remote URLs must use HTTPS; localhost, 127.0.0.1, and ::1 may use HTTP |
Embedding the provider store
The Rust API that backs the desktop store is available to embedders. A generic hosted provider:
use hive_kernel::{ProviderPreset, ProviderProfile, Secret};
let profile = ProviderProfile::from_preset(
ProviderPreset::GenericOpenAiCompatible,
"default",
"Default provider",
"gpt-example",
Secret::new("EXAMPLE_PROVIDER_KEY_DO_NOT_USE"),
Some("https://provider.example.com/v1".into()),
)?;
Local Ollama:
let profile = ProviderProfile::from_preset(
ProviderPreset::Ollama,
"ollama",
"Ollama",
"llama3.1",
Secret::default(),
None,
)?;
An encrypted fallback store for tests or non-keychain hosts:
use anymo_native::{EncryptedFileSecretStore, SecretStoreKey};
use hive_kernel::ProviderProfileStore;
let key = SecretStoreKey::from_passphrase(
"example passphrase supplied outside the repo",
b"anymo-example-salt-0000",
)?;
let secrets = EncryptedFileSecretStore::new("provider-secrets.json", key);
let store = ProviderProfileStore::new("profiles.json", secrets);
store.save_profile(&profile)?;
Compatibility checks
ProviderHealthSuite runs a provider-neutral compatibility report covering:
- Chat completion
- Streaming, when the capability registry advertises it
- JSON-object response behavior
- Tool and action JSON fallback for providers without native tool calls
- Context-window and max-output-token metadata
- Latency per networked check and safe error rendering
HttpProvider normalizes provider failures into authentication, invalid request, rate limit, timeout, network, server, parse, unsupported, or unknown errors. Retry and backoff apply only to transient network, timeout, rate-limit, and server responses. Rendered errors redact bearer keys and custom header values before entering logs or events.
Failover
Give a run an ordered fallback chain with --fallback <base_url>,<model> (repeatable), or via ANYMO_PROVIDER_FALLBACK_BASE_URL, ANYMO_PROVIDER_FALLBACK_MODEL, and ANYMO_PROVIDER_FALLBACK_API_KEY. Each fallback takes over when the previous endpoint exhausts retries on a retryable failure, and every switch is recorded as a durable provider.fallback event. In the desktop app, the fallback chain spans your saved profiles.
Routing defaults
When a run does not explicitly set reasoning effort, Anymo applies stable defaults per agent role:
| Role | Default reasoning |
|---|---|
| Supervisor / planner | xhigh |
| Reviewer / verifier | high |
| Researcher / coder / tester / synthesizer | xhigh |
| Utility / tool worker* | medium |
*These are defaults; the orchestrator still chooses the best reasoning level for each request.
If a provider supports native reasoning effort, Anymo maps xhigh to the strongest provider-native setting available and keeps the xhigh evaluator and budget intent locally. Providers without native reasoning effort receive no provider-specific field; Anymo still expands local high and xhigh budgets before making requests.