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, not 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.
brew install kanywst/tap/rapgDownload a tarball for your OS and architecture from the latest release, then put rapg on your PATH.
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.pyAn MCP server is another child process that needs a token, and a tempting single point of credential aggregation. Wrap one with rapg run so its token comes from the vault, not a .env on disk:
# any MCP server that reads its token from the environment
rapg run -- npx -y @modelcontextprotocol/server-githubThe server picks up its token (a GitHub PAT, say) from the variable you set as the entry's Env Key. It never hits disk or shell history, and stays scoped to this project.
| 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 |
Static dev credentials don't rotate themselves, so rapg surfaces staleness. The detail view shows when each secret was last set (Rotated: 12d ago) and flags anything past 90 days with a consider rotating nudge.
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 on the roadmap; 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 recreates it on the next invocation.
rapg run puts the real key in the child's environment. rapg proxy doesn't: it holds the key in memory and gives the agent a short-lived, loopback-only token. If a prompt-injected agent dumps its env, all that leaks is a token that works only on 127.0.0.1 and dies with the process.
rapg proxy --provider anthropic -- claude code
rapg proxy --provider openai -- python agent.pyThe key is a normal vault entry, located by its Env Key (ANTHROPIC_API_KEY / OPENAI_API_KEY by default, or --env-key) and scoped by .rapg.toml like rapg run. The port is ephemeral (--port to pin it), and the proxy lives as long as the child.
| Provider | Upstream | Child env injected |
|---|---|---|
anthropic |
https://api.anthropic.com |
ANTHROPIC_BASE_URL, ANTHROPIC_AUTH_TOKEN, ANTHROPIC_API_KEY |
openai |
https://api.openai.com |
OPENAI_BASE_URL (+ legacy OPENAI_API_BASE), OPENAI_API_KEY |
Any agent that honors a custom base URL (Claude Code, the OpenAI Agents SDK, most tools) works unchanged.
| Command | Purpose |
|---|---|
rapg |
Launch the TUI |
rapg run -- <cmd> |
Inject secrets into a child process (respects .rapg.toml, records to session log) |
rapg proxy --provider <provider> -- <cmd> |
Run a command behind a localhost gateway that holds the real API key (anthropic, openai) |
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:
- 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 |
| Prompt-injection blast radius | Secrets go into the child's environment, never the prompt or context window; rapg redact scrubs vault values from transcripts before you share them |
rapg covers the secret boundary on your dev machine: real keys off disk, out of agent transcripts. It isn't a production identity platform. Per-agent identities, workload federation, and server-side rotation live in your cloud IAM or a Vault / Secrets Manager. rapg is the local complement to those.
MIT. See LICENSE.
