guide

Key Management

API keys are never written into configuration files. There are exactly two sources:

Source How it works When to use
Environment variable Read at runtime from an env var. On by default (auto_detect_env: true). Local dev, CI/CD — just export the variable
System keyring Stored encrypted in the OS credential store (macOS Keychain / Windows Credential Manager / Linux Secret Service) via zlogic key add. Persistent keys on your machine

Resolution priority per provider: environment variable first, then the keyring. Keys that cannot be resolved simply make that provider unavailable — nothing is ever sent unauthenticated.

Environment variables (default)

Just export the variable — no key add step needed:

export DEEPSEEK_API_KEY=sk-...
  • Built-in providers recognize their official variable names (OPENAI_API_KEY, ANTHROPIC_API_KEY, DEEPSEEK_API_KEY, GEMINI_API_KEY, GOOGLE_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, DASHSCOPE_API_KEY, ZHIPUAI_API_KEY, GLM_API_KEY, OPENROUTER_API_KEY).
  • The generic pattern is <PROVIDER>_API_KEY (provider id uppercased).
  • To turn environment keys off entirely, set auto_detect_env: false in models.yaml — after that only the keyring is consulted.

System keyring (persistent)

# Add a key for a provider (prompts for the secret)
zlogic key add openai

# List which providers have keyring entries (masked, never the plaintext)
zlogic key list

# Verify a credential actually works against the provider
zlogic key verify openai
zlogic key verify openai gpt-4o

# Remove a keyring entry
zlogic key remove openai --yes

Keyring entries are referenced by provider id (keyring:openai). The desktop Settings UI adds keys the same way — choose the provider and pick a credential source.

Keys for web search (the web_search tool)

The search tool needs no key by default: Exa and Parallel both have a free tier, with a low quota. When that runs out, store a key for the backend — same two sources as a provider, with a prefixed entry name:

Backend Get a key Environment variable Keyring entry
exa https://dashboard.exa.ai/api-keys EXA_API_KEY (or ZLOGIC_EXA_API_KEY) web_search:exa
parallel https://platform.parallel.ai PARALLEL_API_KEY (or ZLOGIC_PARALLEL_API_KEY) web_search:parallel
zlogic key set exa          # prompts, writes web_search:exa
zlogic key set parallel

In the desktop app, fill it in place under Settings → Tools → Web search; the link at the right of each row is the page from the table above. Provider cards (Settings → Models) carry the same link, taken from the provider's guide_url. The key is read on every search, so the next one uses it — no restart. The prefix matters: exa / parallel are retrieval services rather than model providers, and they cannot share a keyring entry with a same-named provider.

env.yaml — keys in a single file

If you would rather not export every time and do not want to use the keyring, drop an env.yaml into the config root (~/.config/zlogic/env.yaml). The system loads it as environment variables at startup (a real environment variable always wins; env.yaml only fills in what is missing):

# ~/.config/zlogic/env.yaml
DEEPSEEK_API_KEY: sk-...
OPENAI_API_KEY: sk-...
  • Plain KEY: value pairs (uppercase key names; the values are plaintext secrets — keep the file private).
  • Values never override an existing process environment variable of the same name.
  • Exactly equivalent to export: the auto_detect_env switch applies the same way.
  • Do not commit it; add env.yaml to .gitignore.

Security recommendations

  • Personal machines: zlogic key add <provider> once — the OS keyring decrypts transparently afterwards.
  • CI/CD and shared environments: use environment variables injected by your secrets manager.
  • Never write API keys as plaintext in any configuration file or repository.