kz CLI
How the kz CLI works -- config format, secret resolution, blind mode, and shell hooks
kz is the keyzero CLI. It reads .keyzero.toml, resolves secrets from configured providers, and injects them as environment variables into a subprocess.
How It Works
kz run -- npm start
- Load config -- finds and reads
.keyzero.toml(walks up from the current directory) - Select environment -- checks
KEYZERO_ENV(orNODE_ENV,RAILS_ENV, etc.) to activate environment-specific sections - Resolve secrets -- calls each configured provider (keychain, 1Password, AWS, Vault, etc.) to fetch secret values
- Inject env vars -- sets the resolved values as environment variables on the subprocess
- Spawn subprocess -- runs the command with secrets available in its environment
.keyzero.toml Config
The config maps environment variable names to secret providers:
[secrets]
DATABASE_URL = { provider = "keychain", ref = "myapp-db-url" }
API_KEY = { provider = "1password", ref = "op://Vault/myapp/api-key" }
AWS_SECRET = { provider = "aws", ref = "sm://prod/aws-secret" }
[production.secrets]
DATABASE_URL = { provider = "aws", ref = "sm://prod/db-url" }
API_KEY = { provider = "aws", ref = "sm://prod/api-key" }
Set KEYZERO_ENV=production to activate the [production.secrets] section, which overrides the default [secrets].
Local overrides
.keyzero.local.toml overrides .keyzero.toml for personal settings. Add it to .gitignore.
Global config
Provider defaults go in ~/.config/keyzero/config.toml.
Blind Mode
kz run --blind -- node agent.js
In blind mode, secrets are masked with tokens before being injected into the subprocess. A local MITM proxy intercepts outgoing HTTP/HTTPS requests and swaps the masked tokens for real values at the network boundary.
What the subprocess sees:
API_KEY=kz_masked_7f3a9b...
What hits the upstream API:
API_KEY=sk-proj-abc123...
The subprocess never sees raw secrets. This is designed for AI agents and other untrusted workloads.
Connection control
In .keyzero.toml, control which hosts the subprocess can reach:
[blind]
[[blind.connections]]
allow = true
host = "api.openai.com"
[[blind.connections]]
allow = false
host = "*"
Environment Variables Set by kz
In blind mode, the subprocess inherits these environment variables in addition to the secrets:
| Variable | Value | Purpose |
|---|---|---|
HTTP_PROXY | http://127.0.0.1:<port> | Route HTTP traffic through the proxy |
HTTPS_PROXY | http://127.0.0.1:<port> | Route HTTPS traffic through the proxy |
http_proxy | http://127.0.0.1:<port> | Lowercase variant for compatibility |
https_proxy | http://127.0.0.1:<port> | Lowercase variant for compatibility |
SSL_CERT_FILE | Path to ephemeral CA cert | Trust the MITM CA (OpenSSL) |
NODE_EXTRA_CA_CERTS | Path to ephemeral CA cert | Trust the MITM CA (Node.js) |
REQUESTS_CA_BUNDLE | Path to ephemeral CA cert | Trust the MITM CA (Python requests) |
CLI Flags
kz run [OPTIONS] -- <COMMAND>...
| Flag | Description | Default |
|---|---|---|
--only <KEYS> | Resolve only the listed secret keys | All secrets |
--clean-env | Start with a clean environment (only injected secrets) | false |
--keep-env <KEYS> | When using --clean-env, also keep these host env vars | None |
--blind | Mask secrets with tokens; run MITM proxy | false |
--no-force-proxy | In blind mode, don't force-set proxy env vars | false |
Shell Hook
Auto-load secrets when you cd into a project directory:
# zsh
eval "$(kz hook --shell zsh)"
# bash
eval "$(kz hook --shell bash)"
# fish
kz hook --shell fish | source