Developers
One CLI call. Every secret.
No env vars. No config files. No secrets in logs. Every secret your infrastructure needs, resolved at runtime.
The pattern
Store it once. Retrieve it anywhere.
Each agent is initialized once with its own token, scopes, and rate limits. After that, the agent can fetch secrets at runtime. The key is stored encrypted in the vault, never in env vars or source code. If the key rotates, update it in the vault UI — every agent picks it up automatically.
Three ways to use it
Field
One value. Pipe it into any command or script.
Render
Whole config file. Resolve all clavitor:// references at startup. Template is safe to commit.
Proxy
HTTPS proxy. Credentials resolved from headers transparently — never in logs or agent output.
Which one should I use?
| Field | Render | Proxy | |
|---|---|---|---|
| Secrets out of logs | |||
| Works with any language | |||
| Works with any tool (curl, SDK, browser) | |||
| Per-agent scoping & audit | |||
| Multiple secrets at once | |||
| No code changes needed | |||
| Config files safe to commit | |||
| SSH / non-HTTP use cases |
Quick pick: Building a script or CLI tool? Use Field. Deploying a service with a config file? Use Render. Running AI agents that make API calls? Use Proxy.
Field — single value
API_KEY=$(clavitor-cli get "OpenRouter" --field key) SSH_KEY=$(clavitor-cli get "Deploy Key" --field private_key)
Render — whole config
Write your config with clavitor://entry/field references:
{
"db": "clavitor://Production DB/password",
"stripe": "clavitor://Stripe API/key",
"openrouter": "clavitor://OpenRouter/key"
}clavitor-cli render app.config.json | myapp --config -
Proxy — transparent credential injection
See the zero-knowledge proxy section below.
Zero-knowledge proxy
Your credentials never leave your machine.
One line to enable. No routing tables. No configuration. The agent writes clavitor:// where the secret should go — the proxy resolves it locally before the request leaves your machine.
export HTTPS_PROXY=http://localhost:1983 curl -H "Authorization: Bearer clavitor://OpenRouter/key" \ https://openrouter.ai/api/v1/chat/completions
Why this beats every other credential proxy.
Nothing to steal. Cloud-hosted proxies are high-value targets — breach one and you get every customer’s credentials. Local proxies store credentials in their own config, readable by any agent on the machine. Clavitor’s proxy holds only an encrypted config file. No plaintext secrets on disk, no credential store to raid. Compromised agents find nothing.
Agents can’t pry it open. A compromised agent can’t extract credentials from the proxy — the proxy doesn’t expose an API, serve a dashboard, or accept commands. It reads one header, resolves one reference, and injects the result into the outbound request. No attack surface.
Nothing in logs. The agent writes clavitor://Entry/field. That’s what appears in stdout, in logs, in conversation history. The real credential exists only inside the proxy process for the duration of one HTTP call. Log aggregators, crash dumps, CI artifacts — clean.
Zero config. No routing tables, no API mappings, no credential files to manage. The clavitor:// reference in the header is the only instruction. One init, one env var, done.
Languages
Works in every language. No SDK required.
Bash
# Single value, consumed inline — never written to disk curl -H "Authorization: Bearer $(clavitor-cli get 'OpenRouter API' --field key)" \ https://openrouter.ai/api/v1/models
Go
key, _ := exec.Command("clavitor-cli", "get", "OpenRouter API", "--field", "key").Output()
client := openai.NewClient(option.WithAPIKey(strings.TrimSpace(string(key))))Python
import subprocess
api_key = subprocess.check_output(
["clavitor-cli", "get", "Stripe API", "--field", "key"]
).decode().strip()
stripe.api_key = api_keyRust
let key = std::process::Command::new("clavitor-cli")
.args(["get", "AWS Credentials", "--field", "secret_key"])
.output()?.stdout;
let secret = String::from_utf8(key)?.trim().to_string();TypeScript / Node
import { execSync } from 'child_process';
const apiKey = execSync('clavitor-cli get "Anthropic API" --field key').toString().trim();
const client = new Anthropic({ apiKey });Infrastructure
Zero secrets in config. Zero secrets in logs.
Docker Compose
Use render to resolve secrets before starting the stack:
# docker-compose.template.yml (committed to git)
services:
app:
environment:
- DB_PASSWORD=clavitor://Production DB/password
- API_KEY=clavitor://Stripe API/key
# Start with resolved secrets (never written to disk)
clavitor-cli render docker-compose.template.yml | docker compose -f - upTerraform
data "external" "vault" {
program = ["clavitor-cli", "get", "AWS Root", "--json"]
}
provider "aws" {
secret_key = data.external.vault.result.password
}Kubernetes
kubectl create secret generic app-secrets \ --from-literal=db-pass="$(clavitor-cli get 'Production DB' --field password)" \ --from-literal=api-key="$(clavitor-cli get 'Stripe API' --field key)"
Ansible
- name: Get database password
command: clavitor-cli get "Production DB" --field password
register: db_pass
no_log: true
- name: Configure app
template:
src: app.conf.j2
vars:
db_password: "{{ db_pass.stdout }}"GitHub Actions
- name: Deploy
run: |
clavitor-cli init ${{ secrets.CLAVITOR_TOKEN }}
kubectl set image deployment/app \
app=myapp:${{ github.sha }}
kubectl create secret generic app-secrets \
--from-literal=api-key="$(clavitor-cli get 'Deploy Token' --field key)" \
--dry-run=client -o yaml | kubectl apply -f -SSH with vault-stored keys
clavitor-cli get "Deploy Key" --field private_key | ssh-add - ssh deploy@production
AI agents
Every agent. Scoped access. Full audit trail.
Each agent gets its own token, its own scopes, its own rate limits. The vault logs every credential access. Agents that access too many distinct credentials are automatically locked.
Claude Code
# Skill auto-installed on init clavitor-cli init <token> # Claude Code can now: # "get me the AWS credentials" # "what's the GitHub deploy token?" # "store this API key as 'Stripe Prod'"
The installed skill enforces guardrails: one credential at a time, no bulk enumeration, secrets never echoed to conversation output.
OpenClaw
Replace hardcoded API keys in openclaw.json with vault references:
{
"providers": {
"openrouter": {
"apiKey": "clavitor://OpenRouter API/key"
},
"fireworks": {
"apiKey": "clavitor://Fireworks.ai/key"
}
},
"channels": {
"discord": {
"accounts": {
"main": { "token": "clavitor://Discord Bot/token" }
}
}
}
}# Start with resolved config clavitor-cli render openclaw.json | openclaw start --config -
Codex (OpenAI)
CODEX_ENV_API_KEY=$(clavitor-cli get "OpenAI API" --field key) codex
Cursor / Windsurf / Aider
Any agent that runs shell commands. Add to project instructions:
# "Use clavitor-cli to retrieve secrets. Never ask the user for passwords."
CrewAI / LangChain / AutoGen
import subprocess
def get_secret(name, field="password"):
return subprocess.check_output(
["clavitor-cli", "get", name, "--field", field]
).decode().strip()
# Use inline — don't store in a variable longer than needed
client = OpenAI(api_key=get_secret("OpenRouter API", "key"))n8n / Make / Zapier
HTTP-based integration with the vault API directly:
curl -H "Authorization: Bearer $CVT_TOKEN" \ https://vault.example.com/api/entries/search?q=Stripe
Config rendering
Commit your configs. Not your secrets.
clavitor-cli render scans any file for clavitor://entry/field references, resolves each against the vault, and outputs the result. The template lives in git. The resolved config lives in a pipe. Secrets never touch disk.
Works with JSON, YAML, TOML, .env, or any text file. If it contains clavitor://, it gets resolved.
The pattern is always the same.
One CLI call, any context. The agent's scope determines what it can see. The tier determines what it can decrypt. The audit log records every access.