Start
Safely manage the secrets your agent uses without .env files, shell history, or chat leaks. Stored in your macOS Keychain.
Migrate every key=value pair from a .env file straight into Keychain.
~/projects/myapp
mxkey migrate --delete .env.local myapp
Found 4 key(s):
STRIPE_SECRET_KEY (33 chars)
DATABASE_URL (46 chars)
OPENAI_API_KEY (41 chars)
RESEND_API_KEY (25 chars)
Migrate all of these under project.myapp.* ? [y/N] y
set project.myapp.stripe_secret_key (STRIPE_SECRET_KEY)
set project.myapp.database_url (DATABASE_URL)
set project.myapp.openai_api_key (OPENAI_API_KEY)
set project.myapp.resend_api_key (RESEND_API_KEY)
migrated 4 / 4 secrets. skipped: 0
project.myapp now contains 4 secret(s). wrote .env.mxkey. deleted .env.local.
Agent
Drop the SKILL.md into Claude Code, Cursor, or Codex and the agent learns every secret-handling behavior on this page.
~/projects/myapp
ln -sfn ~/GitHub/mxkey ~/.claude/skills/mxkey
# Skill loaded. Claude now triggers mxkey for any
# .env, hardcoded key, or pasted secret it sees.
When the agent spots a .env in your project, it offers to migrate the contents into Keychain — without you asking.
Claude
I see
.env.local with 4 keys (Stripe, OpenAI, Resend, Postgres). Want me to migrate them into Keychain under project.myapp.* and delete the file?You
yes
Claude
Migrated 4 secrets. Wrote
.env.mxkey. Deleted .env.local. Your dev command now uses mxkey run-here -- pnpm dev.If you paste a secret into chat, the agent refuses to act on it and tells you to rotate first — never stores or echoes the value.
You
save this openai key for me: sk-proj-abc123def456ghi789...
Claude
That looks like a live API key. Because it's now in this conversation, rotate it at OpenAI first. Then run
mxkey set api.openai OPENAI_API_KEYand type the new value at the hidden prompt — it won't enter the chat.When the agent sees a hardcoded API key in source code, it warns before any commit and suggests the safe pattern.
Claude
I noticed
src/api.ts has a hardcoded Stripe key on line 12. Don't commit this — store it with mxkey set api.stripe STRIPE_SECRET_KEY and read it via process.env.STRIPE_SECRET_KEY instead. Want me to rewrite the file?The agent rewrites your dev commands so they load secrets from Keychain via mxkey run, not from .env files on disk.
~/projects/myapp
# Before:
pnpm dev # reads from .env.local
# After (agent suggested):
mxkey run-here -- pnpm dev
> Server listening on :3000
# Same env vars, no .env file needed.
Save & run
Save a secret to Keychain at a hidden prompt — never echoed, never logged, never written to disk.
~/projects/myapp
mxkey set api.openai OPENAI_API_KEY
Value for mxkey.api.openai (input hidden):
set mxkey.api.openai (OPENAI_API_KEY)
Run any command with named secrets injected as environment variables — values never appear in argv or shell history.
~/projects/myapp
mxkey run api.openai -- curl https://api.openai.com/v1/models
{"object":"list","data":[...]}
List every stored secret name, optionally filtered by group prefix — values stay in Keychain and are never printed.
~/projects/myapp
mxkey list project.myapp
NAME ENV_VAR
---------------------------------------- ------------------------------
project.myapp.database_url DATABASE_URL
project.myapp.openai_api_key OPENAI_API_KEY
project.myapp.resend_api_key RESEND_API_KEY
project.myapp.stripe_secret_key STRIPE_SECRET_KEY
Project groups
Write a .env.mxkey manifest listing every secret a project needs — names only, no values, safe to commit.
~/projects/myapp
mxkey init project.myapp
wrote .env.mxkey with 4 name(s):
project.myapp.stripe_secret_key
project.myapp.database_url
project.myapp.openai_api_key
project.myapp.resend_api_key
Walk up to the nearest .env.mxkey and run a command with every listed secret loaded — works from any subfolder.
~/projects/myapp/services/api
mxkey run-here -- pnpm dev
> myapp@1.0.0 dev
> next dev
▲ Next.js 16.2.4
- Local: http://localhost:3000
- Ready in 372ms
Safety
Save a secret with macOS authentication required on every read — Touch ID for prod DBs, billing keys, and anything where silent theft would hurt.
~/projects/myapp
mxkey set --require-auth db.prod-postgres DATABASE_URL
Value for mxkey.db.prod-postgres (input hidden):
set mxkey.db.prod-postgres (DATABASE_URL) — requires authentication on every read
Store 2FA recovery codes one per line, then atomically print-and-delete the next available code on demand so a code can never be re-used.
~/projects/myapp
mxkey backup use github
abc1-2def-3ghi
consumed backup.github.1; 7 code(s) remaining