Mentu

Credentials

Credentials

The shell backend needs no credential, no network access, and no account. If you only run shell recipes, there is nothing on this page to do.

Provider backends need their own key. The runner never prompts for one and never writes one into a run record.

Resolution order

For a given credential the runner checks, in order:

  1. the step env block, then the recipe env block
  2. the process environment
  3. the macOS Keychain, through mentu-recipes vault

The first hit wins. In the Keychain the runner tries the backend's vault key name first, then names derived from the environment variable: OPENAI_API_KEY also matches openai-api-key, and any FOO_API_KEY matches foo-api-key.

What each backend needs

Backend Credential Environment variable Vault key
shell none
openai OpenAI key OPENAI_API_KEY openai-api-key
openai-chat OpenAI key OPENAI_API_KEY openai-api-key
deepseek DeepSeek key DEEPSEEK_API_KEY deepseek-api-key
ollama none for a default local server OLLAMA_API_KEY if your server requires one ollama-api-key
claude whatever the Claude CLI is already signed in with ANTHROPIC_API_KEY if you use one only through an env reference
codex whatever the Codex CLI is already signed in with OPENAI_API_KEY if you use one only through an env reference

The HTTP backends read the Keychain themselves. The two CLI backends do not. They shell out to a CLI you have already authenticated, so they usually need nothing from the runner, and they receive an API key only if it is present in the environment the runner builds: your process environment plus the recipe and step env blocks. To hand a vault key to a CLI, reference it from env as shown below. Their environments are allow-listed per backend: the Claude CLI is passed ANTHROPIC_API_KEY and not OPENAI_API_KEY, and the Codex CLI is passed OPENAI_API_KEY and not ANTHROPIC_API_KEY.

Store a key in the Keychain

Keys are generic password items in your login Keychain under the service name mentu-vault, with the key name as the account. You can inspect or remove them in Keychain Access as well as with the commands below.

Pipe the secret in on stdin so it does not land in your shell history.

printf '%s' "$OPENAI_API_KEY" | mentu-recipes vault set openai-api-key
✓ stored openai-api-key

List the key names the vault holds. Values are never printed by list. On a machine with two keys stored:

mentu-recipes vault list
deepseek-api-key
openai-api-key

Read one back. This prints the secret to stdout.

mentu-recipes vault get openai-api-key

Remove it.

mentu-recipes vault delete openai-api-key
✓ deleted openai-api-key

A get after the delete exits non-zero:

mentu-recipes: Key not found: openai-api-key

Vault keys are read on demand, not scanned. Availability detection stays out of the Keychain deliberately, so a backend whose key lives only in the vault shows as unavailable in mentu-recipes adapters and still runs when a step selects it by name.

Reference a vault key from a recipe

{
  "env": {
    "OPENAI_API_KEY": "${openai-api-key}"
  }
}

A ${name} value is replaced before the step runs: first from a --var of the same name, then from a process environment variable called name, then from the Keychain. If none resolves, the literal text is left in place. This is the only way a Keychain value reaches a CLI agent step.

Do not commit a real key into a recipe file. Recipes are meant to be diffed and reviewed like the rest of your code.

Custom providers

A recipe can define a provider with its own host and its own key name:

{
  "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"
    }
  }
}

api_key_vault is optional. Without it the runner still tries the Keychain under ACME_API_KEY and the derived name acme-api-key. A custom HTTP provider always needs a key to resolve, even for a server that does not check one.

base_url is a trust boundary. The built-in OpenAI and DeepSeek credential names are pinned to api.openai.com and api.deepseek.com, so setting a custom base_url cannot quietly forward one of those keys to a third-party host. Give a custom provider its own env or vault key.

mentu-recipes doctor raises a generic_provider_credential error when a custom provider declares OPENAI_API_KEY, DEEPSEEK_API_KEY, openai-api-key, or deepseek-api-key as its own credential name, whatever its base_url.

© 2026 Mentu.