psst π€« Because Your Agent Doesn't Need to Know Your Secrets
I have a confession.
I keep pasting API keys into Claude Code. Or just letting it cat .env. Every time I tell myself Iβll fix it later. I never do.
# "just read the .env"
cat .env
# "here, use this key"
sk-live-4wB7xK9mN2pL8qR3...
# "I'll delete it from the chat after..."
my database password is hunter2, can you check why queries are slow?
Weβve all done it. The secret is now in the modelβs context, in our terminal history, possibly in logs, maybe in training data. We tell ourselves itβs fine. Itβs not fine.
The Problem
When you give an agent shell access, it needs secrets to do real work. Call APIs. Deploy code. Access databases. The standard approaches all leak:
Environment variables? The agent can run env and see everything. Or it runs export STRIPE_KEY=... and now the secret is in its context.
.env files? The agent can cat .env. Easy.
Paste it in chat? Now itβs in the conversation history. Possibly forever.
The agent doesnβt need to know your Stripe key. It just needs to use it.
The Insight
What if secrets could be injected at the last possible moment - into the subprocess environment - without ever touching the agentβs context?
# Agent writes this:
psst STRIPE_KEY -- curl -H "Authorization: Bearer $STRIPE_KEY" https://api.stripe.com
# What the agent sees:
# β
Command executed successfully
# What actually ran:
# curl -H "Authorization: Bearer sk_live_abc123..." https://api.stripe.com
The agent orchestrates. It knows which secret to use. But it never sees the value.
How It Works
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Agent Context β
β β
β "I need to call Stripe API" β
β > psst STRIPE_KEY -- curl https://api.stripe.com β
β β
β [Command executed, exit code 0] β
β β
β (Agent never sees sk_live_...) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β psst β
β β
β 1. Retrieve encryption key from OS Keychain β
β 2. Decrypt STRIPE_KEY from local vault β
β 3. Inject into subprocess environment β
β 4. Execute command β
β 5. Return exit code (not the secret) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Secrets are encrypted at rest with AES-256-GCM. The encryption key lives in your OS keychain (macOS Keychain, libsecret on Linux). Zero friction - no passwords to type.
The Interface
Setup once:
npm install -g @pssst/cli
psst init
psst set STRIPE_KEY # interactive prompt, value hidden
psst set OPENAI_API_KEY
Then agents just use it:
psst STRIPE_KEY -- curl https://api.stripe.com
psst AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY -- aws s3 ls
psst DATABASE_URL -- prisma migrate deploy
Thatβs the whole API. One pattern: psst SECRET -- command.
Agent Onboarding
Run psst onboard in your project and it adds instructions to your CLAUDE.md or AGENTS.md:
## Secrets Management (psst)
Use `psst SECRET -- command` to run commands with secrets.
Never ask the user to paste secrets in chat.
If a secret is missing, ask them to run `psst set SECRET_NAME`.
It also teaches agents to shame you if you try to paste a secret in plain text. Because we all need accountability.
Local-First, Agent-First
No cloud. No sync. No account. Your secrets stay on your machine, encrypted, accessible only through the keychain.
The first customer is the agent. The interface is designed for non-human use. Humans just set things up and let the agent work.
Try It
npm install -g @pssst/cli
psst init
psst set MY_SECRET
psst MY_SECRET -- echo "The secret is $MY_SECRET"
Code: github.com/Michaelliv/psst
psst π€« β because your agent doesnβt need to know your secrets.