# Your .env file - AI can read this STRIPE_SECRET_KEY=sk_live_abc123... DATABASE_URL=postgres://user:pass@host OPENAI_API_KEY=sk-proj-xyz789... # AI assistant asks: "I see your STRIPE_SECRET_KEY, want me to set up the payment webhook?" # Your key is now in the conversation, # potentially in logs, training data...
# Your .secrets.json - AI sees this { "project": "my-app", "secrets": [ "STRIPE_SECRET_KEY", "DATABASE_URL", "OPENAI_API_KEY" ] } # AI assistant suggests: "Run: secret-lover run -- npm run dev" # Values stay in Keychain, injected only # at runtime with your Touch ID approval
No server. No account. No magic. Just a shell script wrapping macOS security tools you already have.
Nothing leaves your machine. No servers, no accounts, no telemetry. Works offline.
Secrets stored in macOS Keychain - the same place Safari stores your passwords. Encrypted by Apple.
~200 lines of bash. No dependencies. Read the whole thing in 5 minutes. Uses standard `security` CLI.
Every secret access requires your fingerprint. See exactly what's being accessed. Deny anytime.
AI reads your manifest, suggests the right command. You approve with Touch ID.
# In your project, create .secrets.json: ~/myproject/.secrets.json { "project": "myproject", "secrets": ["DATABASE_URL", "API_KEY"] } # Claude Code sees the manifest, suggests: "I see you need DATABASE_URL and API_KEY. Run: secret-lover run -- npm run dev" # You run it, Touch ID pops up: $ secret-lover run -- npm run dev [Touch ID prompt: "secret-lover" wants to access "DATABASE_URL"] # You approve, secrets injected for that command only: Ready on http://localhost:3000
Different projects, different credentials. Same workflow.
# Project A - Production Supabase ~/project-a/.secrets.json { "project": "project-a", "secrets": ["SUPABASE_URL", "SUPABASE_KEY"] } $ cd ~/project-a $ secret-lover add SUPABASE_URL "https://abc.supabase.co" Stored: SUPABASE_URL (project: project-a) # Project B - Staging Supabase (completely separate) ~/project-b/.secrets.json { "project": "project-b", "secrets": ["SUPABASE_URL", "SUPABASE_KEY"] } $ cd ~/project-b $ secret-lover add SUPABASE_URL "https://xyz.supabase.co" Stored: SUPABASE_URL (project: project-b) # Shared secrets work everywhere $ secret-lover add OPENAI_KEY "sk-..." --global Stored: OPENAI_KEY (global) # Each project gets its own SUPABASE_URL, shares OPENAI_KEY
Project name comes from .secrets.json or folder name. No config needed.
If a secret isn't project-specific, it checks global. Shared keys just work.
secret-lover list --all shows secrets organized by project.
Paste this into your CLAUDE.md. Claude Code will manage secrets via macOS Keychain directly — no tool needed.
## Secrets Management
Never store secrets in .env files. Use macOS Keychain instead.
Projects declare what secrets they need in `.secrets.json`:
```json
{
"secrets": ["API_KEY", "DATABASE_URL"],
"env": { "NODE_ENV": "production" }
}
```
**Reading secrets from Keychain:**
```bash
security find-generic-password -a "SECRET_NAME" -s "my-project" -w
```
**Storing a new secret:**
```bash
security add-generic-password -a "SECRET_NAME" -s "my-project" -w "value"
```
**Running a command with secrets injected:**
Read each name from the `secrets` array in `.secrets.json`, fetch from
Keychain using the command above, and export as environment variables
before running the command. Use the project directory name as the
service name (-s flag).
For static values in the `env` object, export them directly.
**Rules:**
- Never create .env files or suggest `export VAR=value` in shell
- Never hardcode secret values in code
- If `.secrets.json` exists, check it to know what secrets are needed
- If a secret is missing from Keychain, tell me to add it
That's it. Claude Code will use Keychain commands instead of .env files — same idea as secret-lover, zero install.
Common commands at a glance:
# Store a secret (Touch ID protected): secret-lover add MY_API_KEY "your-secret-value" # Retrieve a secret (prompts Touch ID): secret-lover get MY_API_KEY # Run a command with secrets injected: secret-lover run -- npm run dev # List all your secrets: secret-lover list --all # Migrate existing secrets to Touch ID: secret-lover migrate
Uses a Swift helper for Touch ID integration. Falls back to password if Touch ID unavailable.
Different tools for different problems.
| secret-lover | cross-keychain | |
|---|---|---|
| Platform | macOS only | Windows, macOS, Linux |
| Touch ID | Yes (native Swift) | No |
| Dependencies | None (bash + Swift) | Node.js + native modules |
| Use case | CLI for dev workflows | Programmatic API for apps |
| Project namespacing | Built-in | No |
| AI-focused | Yes (.secrets.json manifest) | No |
Building a Node.js app that needs to store user credentials programmatically across platforms.
You're a developer using AI assistants and want Touch ID-protected secrets that stay out of AI context.
If you want the nicer workflow with .secrets.json manifests: