ChatModel protocol. You rarely construct
adapters by hand — you name a model and metalworks resolves it.
Model refs
A model ref isprovider:model-id or provider/model (the slash form matches
the convention used by OpenRouter, LiteLLM, and most agent runtimes):
| Ref | Routes to | Needs |
|---|---|---|
anthropic/<id> | native Anthropic SDK | ANTHROPIC_API_KEY |
openai/<id> | native OpenAI SDK | OPENAI_API_KEY |
google/<id> (or gemini/<id>) | native Google SDK | GOOGLE_API_KEY / GEMINI_API_KEY |
openrouter/<vendor/model> | OpenRouter | OPENROUTER_API_KEY |
openai-compatible/<id> | your OPENAI_BASE_URL endpoint | OPENAI_API_KEY + OPENAI_BASE_URL |
meta-llama/llama-3-70b (any unknown vendor) | OpenRouter (the whole ref is the id) | OPENROUTER_API_KEY |
anthropic/claude-opus always routes to the
native SDK — it never silently lands on OpenRouter.
No ref? Inferred from your keys
With nomodel, the provider is taken from the first key present, in order:
Anthropic, OpenAI, Google. So Metalworks() with only OPENAI_API_KEY set uses
OpenAI. You can also pin a default in ~/.config/metalworks/metalworks.toml:
model= ref > config file > first present key.
Any OpenAI-compatible endpoint
This is the “bring your own model” path. Any server that speaks the OpenAI chat-completions API — OpenRouter, vLLM, LM Studio, Together, Groq, a local runtime — works with no new adapter:native_structured=False routes structured calls straight to the schema-in-prompt
ladder tier, which is the safe default for endpoints whose JSON-schema support
varies. Leave it True if your endpoint enforces response_format reliably.
Fast vs main model
The research and discovery pipelines use a cheap “fast” model for triage and filtering and a capable model for synthesis and generation. Set both:model, the fast slot falls back to it. Resolve a pair directly
with metalworks.config.resolve_models(model, fast_model).