Single-binary, local-first secret manager built for the AI-agent era.
You hand ANTHROPIC_API_KEY to Claude Code. You hand AWS_SECRET_ACCESS_KEY to your Cursor agent. You hand a database URL to whatever shell snippet your LLM just generated.
Three things go wrong:
- The agent's transcript and context window now contain your secret. Logs persist, screenshots happen, transcripts get pasted into bug reports.
.envfiles keep that secret in plaintext on disk, and someone always commits one by accident.- Existing managers (1Password, Bitwarden) solve team sharing — they do not solve agent leakage.
rapg is a small Go binary that keeps your dev secrets in a locally encrypted vault and injects them into child processes, including AI agents, without ever writing them to disk.
Requires Go 1.25 or newer.
go install github.com/kanywst/rapg/cmd/rapg@latestFirst run sets a master password (minimum 12 chars, strong complexity):
rapgIn the TUI, press n to add a secret. Fill in Service, Username, Password, and the Env Key field, for example ANTHROPIC_API_KEY.
Inject those secrets into any child process:
rapg run -- claude code
rapg run -- npm run dev
rapg run -- python script.pyThe child sees ANTHROPIC_API_KEY and any other Env Key-tagged secret in its environment. Your .env file stays out of git, your real keys stay off disk, and the parent shell never holds them in scrollback.
A minimal verification script lives at examples/main.py:
rapg run -- python examples/main.py| Key | Action |
|---|---|
j / k / arrows |
Navigate the entry list |
n |
New entry (Service, Username, Password, TOTP, Namespace, Env Key, Notes) |
enter / space |
Open detail view |
enter (in detail) |
Copy password to clipboard |
ctrl+t |
Copy current TOTP code |
d |
Delete the selected entry |
q |
Quit |
Drop a .rapg.toml at your repository root to scope which secrets rapg run and rapg export see:
namespace = "myapp"
# Optional. Three states:
# - omitted → no whitelist, inject every env-tagged
# secret in the namespace
# - keys = [] → explicit deny-all (project recognized,
# but no env vars injected)
# - keys = ["A", "B"] → standard whitelist
keys = ["DATABASE_URL", "ANTHROPIC_API_KEY"]
# Optional. Default false. When true, entries with empty Namespace
# (the 'global' bucket) are also injected. Project entries override
# global on env-key collision.
# inherit_global = trueWhen you add a secret in the TUI, fill in the Namespace field with the same value (e.g., myapp). Then:
cd ~/code/myapp
rapg run -- claude code
# [rapg] project: myapp (/Users/me/code/myapp/.rapg.toml)
# child sees only myapp's DATABASE_URL and ANTHROPIC_API_KEYResolution rules:
- Discovery walks up from
cwdto/. The first.rapg.tomlwins. - No
.rapg.tomlfound → only entries with empty Namespace ("global") are injected. - A namespaced entry is invisible outside its project unless the project opts in via
inherit_global = true— which lets shared utility secrets (e.g.GITHUB_TOKEN) live once in the global bucket and be borrowed by projects that ask for them. Project entries always win on key collision. - Same
Service/Usernamepair can exist across multiple namespaces.
rapg hook <shell> prints a snippet that announces project entry/exit on cd. It does not auto-inject secrets — run rapg run -- <cmd> for that. Auto-injection (direnv-style) is planned for v4.1; doing it safely without an in-shell key cache is a separate problem.
# zsh: ~/.zshrc
eval "$(rapg hook zsh)"
# bash: ~/.bashrc
eval "$(rapg hook bash)"
# fish: ~/.config/fish/config.fish
rapg hook fish | sourceAfter installing, cd between project directories prints:
[rapg] entered project: myapp (rapg run -- <cmd> to inject)
[rapg] left project: myapp
Before pasting an agent transcript into a bug report, scrub vault values from it:
rapg redact ~/.claude/transcripts/today.jsonl > redacted.jsonl
# or, against the clipboard:
pbpaste | rapg redact - | pbcopyEach occurrence of a vault Password becomes [REDACTED:<env_key>] (or [REDACTED:<service>/<username>] if the entry has no env key). Values shorter than 8 characters are skipped to avoid false positives. The match count is reported on stderr so it doesn't contaminate the redacted output stream.
Scope is the whole vault, regardless of .rapg.toml — when checking a transcript, you want maximum coverage, not project boundaries.
Every rapg run -- <cmd> appends one line to ~/.rapg/sessions.jsonl recording the command, project namespace, env keys injected (not their values), exit code, pid, and cwd. Read the trail back:
rapg session log
# 2026-05-05 14:30:12 [myapp] claude code --print exit=0 keys: ANTHROPIC_API_KEY,DB_URL
# 2026-05-05 14:32:05 [-] npm run dev exit=0 keys: -
rapg session log --limit 100The log is plaintext metadata at mode 0600. To wipe it, just rm ~/.rapg/sessions.jsonl — rapg run will recreate it on the next invocation.
| Command | Purpose |
|---|---|
rapg |
Launch the TUI |
rapg run -- <cmd> |
Inject secrets into a child process (respects .rapg.toml, records to session log) |
rapg gen [length] |
Generate a cryptographically random password |
rapg export |
Print env-tagged secrets as KEY=value lines (respects .rapg.toml) |
rapg redact <file|-> |
Mask vault values in a file or stdin; output to stdout |
rapg session log |
Show recent rapg run sessions from ~/.rapg/sessions.jsonl |
rapg project |
Print the current project's namespace; exit 1 if not in a project |
rapg hook <shell> |
Print a cd notifier snippet for zsh / bash / fish |
rapg nuke |
Wipe the local vault after confirmation |
Next on the agent-leakage track:
rapg proxy --provider anthropic|openai(experimental) — local HTTP proxy that holds the real API key, so agents only ever see a short-lived proxy token.- Direnv-style auto-injection on
cd, with a TPM / Touch ID / Secure Enclave-backed key cache.
| Concern | Implementation |
|---|---|
| Master password | Never written to disk; only an Argon2id-derived key hash is stored for verification |
| Key derivation | Argon2id (RFC 9106), defaults time=3, memory=128 MiB, threads=4 |
| Encryption | AES-256-GCM (NIST SP 800-38D) with a 12-byte random nonce per record |
| Memory protection | Master key held in a memguard LockedBuffer and zeroed on exit |
| At-rest layout | Single SQLite file at ~/.rapg/rapg.db, directory mode 0700 |
MIT — see LICENSE.
