Cloud APIs
Cloud APIs
Three built-in backends call a hosted API, and a recipe can define more.
| Backend | API | Host | Default model |
|---|---|---|---|
openai |
Responses | https://api.openai.com/v1 |
gpt-5.5 |
openai-chat |
chat completions | https://api.openai.com/v1 |
gpt-4o |
deepseek |
chat completions | https://api.deepseek.com/v1 |
deepseek-chat |
Set a model explicitly rather than relying on the default. The step's model
wins, then --model on the command line, then the recipe's model. See
Credentials for what each backend needs.
A step against OpenAI
{
"name": "openai-smoke",
"backend": "openai",
"model": "gpt-5.5",
"steps": [
{
"label": "ping",
"prompt": "Reply with exactly: OK",
"completion_keyword": "OK",
"reasoning": "medium",
"max_output_tokens": 32,
"timeout": 120
}
]
}completion_keyword matters more here than on a shell step. Without it, a
provider step completes on the provider's completion event, which says the
response finished, not that it did what you asked. With it, the step completes
only when the keyword appears in the output.
The Responses backend sends reasoning as the request's reasoning effort, with
max mapped to xhigh. The chat-completions backends ignore reasoning. All
three send max_output_tokens when set. System context, when a step has one,
goes in the instructions field for Responses and as a system message for
chat completions.
The Responses backend accepts a few model aliases: codex-5-5 and gpt-5-5
resolve to gpt-5.5, gpt-5-4-mini to gpt-5.4-mini, and codex-5-3 to
gpt-5.3-codex. Other names are sent as written.
Custom providers
Use providers for any host with an OpenAI-compatible API.
{
"name": "custom-chat",
"providers": {
"acme": {
"api": "chat_completions",
"base_url": "https://api.acme.example/v1",
"api_key_env": "ACME_API_KEY",
"api_key_vault": "acme-api-key",
"model": "acme-large"
}
},
"steps": [
{
"label": "ask",
"backend": "acme",
"prompt": "Reply with exactly: ACME_OK",
"completion_keyword": "ACME_OK",
"timeout": 120
}
]
}api accepts responses, chat_completions, cli, and shell. Every field
is optional, and the defaults are the OpenAI ones: api defaults to
chat_completions, base_url to https://api.openai.com/v1, api_key_env to
OPENAI_API_KEY, and model to gpt-4o for chat completions or gpt-5.5 for
Responses. cli maps to the Claude CLI adapter, or to the Codex CLI adapter
when the provider is named codex. shell maps to the shell adapter.
A custom HTTP provider always requires a credential, even when the server does
not check one. If api_key_env is unset in the environment and no vault key
resolves, the step fails before any request is made.
base_url is a trust boundary. The built-in OpenAI and DeepSeek credential
names are pinned to their official hosts, so pointing a custom base_url at a
third-party service cannot quietly forward one of those keys to it. Give the
provider its own key name. doctor refuses the alternative:
| Severity | Code | Location | Recommendation |
| --- | --- | --- | --- |
| error | generic_provider_credential | providers.acme | Use a provider-specific `api_key_env` or `api_key_vault`. |The lint is not the only guard. If the recipe runs anyway, the step fails before the request is built:
Provider acme cannot send OpenAI credentials to api.acme.example; use a provider-specific api_key_env or api_key_vaultTimeouts and retries
Provider steps inherit the 1800 second default timeout, which doctor reports
as default_timeout. Set timeout per step. For flaky endpoints, max_retries
and retry_backoff_ms retry the step before the run fails. A non-2xx response
fails the attempt with the status code and the first part of the body.
What leaves the machine
The prompt, any system context, and the model settings go to the provider you
selected, and nothing else. Run records stay on disk under .mentu/runs/ in the
workspace.
The --cloud flag on mentu-recipes run, and "cloud": { "enabled": true } in
a recipe, turn on a separate set of run hooks that post to
https://api.mentu.ai. They are off by default and they need a Mentu API key,
read from MENTU_API_KEY in the environment or from the vault keys
mentu-api-key or mentu-api-token. There is no public way to obtain such a
key today, so for the public runner this flag has no effect: without a key the
run proceeds locally and the run record says local-only.
Every run record carries a cloud_mode field: local-only when no key is
present, enabled when the hooks ran, unavailable when the first call failed
and the run continued locally.