Bring your own keys (BYOK)
Hydrate is zero-config by default - if claude is on
your $PATH, everything works. Adding your own provider
API keys is optional; it upgrades retrieval quality and gives you
a faster extraction path than the Claude Code subprocess.
This page explains what those keys do, how to store them
(industry-standard OS keychain, not .zshrc), and
the precedence rules.
Should you add keys?
The honest tier ladder from /docs/install:
- Just installed, didn't do anything else?
You're on Tier 1 - Hydrate uses
claude --printas a subprocess for extraction, FTS5 keyword search for retrieval. Works. Most users stop here. - Want semantic retrieval (fuzzy fact-matches,
not just keyword)? Run Ollama locally + set
HYDRATE_EMBED_ENDPOINT. Still no cloud keys. Tier 2. - Want the benchmark-quality setup?
Add
OPENAI_API_KEY- gpt-4o-mini for extraction, text-embedding-3-small for embeddings. Tier 3. - Want to route extraction through Anthropic
directly (bypass the
claude --printsubprocess for a faster path)? AddANTHROPIC_API_KEY. - Want code-specialised embeddings?
Add
VOYAGE_API_KEY- usesvoyage-3-lite, better recall on API-surface / architectural vocabulary than OpenAI's general embedding.
How to add a key - the right way
Hydrate ships OS-native secret storage - macOS
Keychain on Mac (via Apple's security tool, no CGO
dependencies), a 0600-permission file under
~/.hydrate/ on Linux / Windows (v1). This is the
same pattern gh auth login, stripe login,
and 1password signin use.
# Interactive - prompts for the key, input hidden:
hydrate login openai
hydrate login anthropic
hydrate login voyage
# Non-interactive (CI, scripts):
echo "$OPENAI_API_KEY" | hydrate login openai --stdin
# See what's configured (values masked):
hydrate providers
# Remove a stored key:
hydrate logout openai macOS users: the key goes in the login keychain
under service com.gethydrate.cli. Inspect or revoke
any time from Keychain Access.app → search "gethydrate".
macOS will prompt for your user password the first time Hydrate
reads the entry after a reboot - same behaviour as every other
Keychain-using CLI.
Linux / Windows users: keys live in
~/.hydrate/secrets.yaml with mode 0600.
Not encrypted at rest - the goal is "fewer footguns than
exporting in your shell profile," not "defeat a local attacker
with filesystem access." Secret-Service / Credential-Manager
backends are v2.
What not to do
- Don't paste keys into
~/.zshrc/~/.bashrcunless you actively want them available to every program you run. That's a larger blast radius than strictly needed, and shell history / process-list leaks are real. - Don't commit
~/.hydrate/secrets.yamlto a dotfiles repo. The file is outside any git repo by default; adding it would defeat the point. - Don't put keys in
~/.hydrate/config.yamleither. Hydrate's own config reader reads them but the file isn't designed as a secret store.hydrate loginwrites to the right place.
Precedence - env vars always win
When Hydrate resolves which provider to use, the order is:
- Explicit
HYDRATE_LLM_PROVIDER/HYDRATE_EMBED_PROVIDER - Environment variables (
OPENAI_API_KEYetc.) HYDRATE_LLM_ENDPOINT/HYDRATE_EMBED_ENDPOINT- Keyring lookup (what
hydrate loginwrites to) - Claude Code subprocess (if
claudeis on PATH) - Heuristic fallback (pure Go, no network)
Why env > keyring: CI / Docker / ephemeral shells set env vars on purpose and shouldn't be silently overridden by whatever the user's keychain had. Interactive shells, which rarely export API keys, pick up the keyring automatically.
Disabling / opting out
# Don't use any LLM at all (heuristic extractor, FTS5 only):
export HYDRATE_LLM_PROVIDER=none
# Don't use any embedder (FTS5 keyword retrieval only):
export HYDRATE_EMBED_PROVIDER=none
# Don't spawn hydrate-server if hooks find it down:
export HYDRATE_AUTOSTART=0
# Force the file backend everywhere (CI / test harnesses):
export HYDRATE_SECRETS_BACKEND=file Key-safety posture
- Hydrate reads the secret only in-process, passes it to the configured provider, discards. Nothing persists in memory.
- Obfuscated-at-rest AES-GCM wrap applies to the local fact
store (user facts, captured transcripts). Keys themselves live
in the OS keychain /
0600file, not the wrapped columns. - Hydrate Free never makes an outbound network call except to the provider you configured. Nothing phones home to gethydrate.dev. Add your own firewall rule to verify.
Rotation
hydrate login <provider> overwrites the
existing entry. For rotation on a regular cadence: revoke the
key at the provider, run hydrate login again with
the new one - no restart of
hydrate-server needed; the next request picks up
the fresh value.