key-amnesia
Health Pass
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Community trust — 16 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Let your AI agent use your passwords and API keys - without ever letting it see them
key-amnesia
Let your AI agent use your passwords and API keys — without ever letting it see them.

The problem is .env
.env was designed for a threat model whose adversary was git. One line in .gitignore and you were done. That model is obsolete: the adversary is now the agent sitting in your project. Anything the agent can read — .env, shell history, MCP configs, a credentials JSON left in the tree — is a LEAK (Locally Exposed Agent Key). Pasting a key into chat is worse; it lives in the conversation forever.
Your choices used to be ugly: paste the key, leave it in plaintext where the agent can read it, or do that part yourself.
key-amnesia is the fourth option. Secrets live in an encrypted vault. The agent triggers commands that use them — values are injected into the child process environment, out of the agent's sight. If a command prints a secret, key-amnesia censors it before the agent sees the output. The master password can only ever be typed by you, at a real keyboard: when an agent needs approval, a separate console window pops up — one the agent cannot read or type into. Auth routing requires both stdin and stdout to look like a TTY before prompting inline; set KEY_AMNESIA_NONINTERACTIVE=1 in agent harnesses to always force that window.
The agent gets amnesia. That's the whole point.
Docs: github.com/fujitoid/key-amnesia/wiki — or run ka docs (prints the URL; opens a browser unless you pass --print).
How it works, in 30 seconds
pip install key-amnesia
ka setup # skills + secret-guard hook for Claude Code / Cursor / Codex
ka init --project # or: ka init for a global vault
ka import .env # move plaintext into the vault (TTY-only; never prints values)
ka scan # find remaining LEAKs (names/paths only)
ka run --secret API_KEY -- python my_script.py
ka init asks for the master password twice; if the entries do not match, nothing is created. There is no recovery if you forget that password — Argon2id + SecretBox leave none by design.
When the agent triggers ka run and your approval is needed, a new console window appears with a clear message — only your password, typed there, lets it proceed. Close the window to deny.
Install
pip install key-amnesia
Or from source: pip install git+https://github.com/fujitoid/key-amnesia, or from a local clone: pip install . — every path gets you both the full key-amnesia command and the short ka alias.
Windows and Linux supported. macOS isolated-console spawn is experimental (PID-file wrapper around Terminal.app / osascript) until a real Mac user confirms the visible window path — see wiki — macOS.
Agent bootstrap
Paste this into your coding agent when you want it to install and teach itself key-amnesia:
Install key-amnesia and set yourself up to use it correctly for secrets in
this project:
1. pip install key-amnesia
2. Verify `ka --version` works in a fresh terminal (if not found, fix PATH
as instructed).
3. Run `ka setup` (installs its skills + safety hook globally).
4. Tell me to restart this session so the skill loads, then tell me exactly
what to do in my OWN terminal to finish setup (master password etc.) —
you cannot do that step yourself.
ka setup copies the bundled skills to ~/.claude/skills/, ~/.cursor/skills/,~/.agents/skills/ (Codex), and ~/.codex/skills/ (legacy Codex /$CODEX_HOME), and merges a PreToolUse / preToolUse hook that blocks tool
calls containing inline credential-shaped tokens. Codex also needs you to
review and trust the new hook via /hooks before it will run.
Two modes: ask every time, or unlock a session
| Mode | What it feels like |
|---|---|
per-call (default) |
Every use of a secret asks for your password. Maximum safety, maximum prompts. |
cached |
You run ka unlock once; a background guard keeps the vault open for 30 minutes (configurable). Agent commands run without prompts until it expires or you ka lock. |
ka config set session-mode cached
ka unlock # see flags below
ka lock
Unlock admission flags (both opt-in; never the default):
| Flag | What it does |
|---|---|
| (default) | First unrecognized client gets a y/N prompt on the guard TTY. Approval admits that connecting process only. Real OS descendants of it are silent later; siblings under a shared parent (typical next ka from the same shell/IDE) are not — they re-prompt. |
--pre-admit |
Auto-admits the very next connecting process for a bounded window (no prompt). Arrival-time grant — whoever connects first. Optional --pre-admit-secret NAME scopes it. |
--admit-tree |
At the first unrecognized-peer prompt, pick a kernel-verified ancestor as the admission root. Admits that ancestor and its OS descendants for the rest of the session. Use this when the connecting client is a short-lived ka and you want later sibling invocations under the same parent to stay silent. Does not admit processes outside that root's subtree (including siblings of the root). Distinct from --pre-admit (lineage vs who arrives next). |
ka unlock --admit-tree # choose parent/IDE as root when prompted
ka unlock --pre-admit # next client only, no ancestry picker
Full command reference, project vaults, manifests, roles/export, and admission details: the wiki (ka docs).
Security limits — read this part honestly
No tool in this class can promise absolute secrecy, and we'd rather tell you exactly where the edges are:
- A command you run can still leak its own secret. Censoring catches exact copies of the value in output — a command that base64-encodes or otherwise obfuscates the secret before printing slips through. This limit is shared by every tool of this kind (
op run,teller run). - Output is not live. Command output is collected fully, censored, then released — the agent sees it only after the command finishes.
- Secret names are stored in plain text (so
ka listcan work without a password). Values never are. Treat names as non-sensitive labels. - The pop-up window assumes the agent can't control your screen. If you've given an agent screen-reading and keyboard/mouse-injection powers, the window's isolation weakens — your typed password stays hidden, but a yes/no confirmation could theoretically be clicked by such an agent. The same caveat applies to the guard's admission prompt.
- Headless machines fail closed. No display → no way to approve → the operation is denied. By design.
- Same-user processes share your privileges. Any program running under your OS account can talk to a live guard session (this is equally true of
ssh-agent). That's why the guard is designed to never return raw values — the worst a rogue same-user process gets is the same bounded "run a command" capability the legitimate path has, and even that requires one admission prompt to be approved on your own screen first. - Windows peer identity is weaker than Linux. Linux binds admission to
SO_PEERCRED(kernel-verified at accept) and rejects a peer whose kernel uid differs from the guard'sgeteuid(). Windows usesGetNamedPipeClientProcessIdthen an immediateOpenProcesswhose handle is held for the admission lifetime so that PID cannot be recycled while admitted — but the residual race between those two calls is not eliminated, and process-tree ancestry is a consent UX (real OS descendants of an admitted root), not an airtight boundary against in-tree malware that already shares your account. - The master password never crosses any inter-process channel, in any form — it's consumed only inside the process that prompted you for it.
- Avoid
ka set NAME VALUEwith the value inline. It's supported for scripting, but an inline value briefly appears on the calling process's command line — visible to same-user process inspection and Windows command-line auditing. Prefer plainka set NAMEand type the value at the hidden prompt. (If an agent tries the inline form, the approval window shows you the incoming value before asking for your password — so you can still deny it.) --pre-admitis an explicit, opt-in trust-widening you ask for. It auto-admits whichever process happens to connect first within the window — not necessarily the one you meant — so only use it right before the command you're expecting, for a short window, and treat the loud confirmation line + audit log entry as the evidence of what it actually admitted.--admit-treeis a separate opt-in trust-widening (also never the default, no config/env). At the first unrecognized-peer prompt it lets you pick a kernel-verified ancestor as the admission root, so every real OS descendant of that root (including later sibling CLI invocations under the same parent) is silently in-tree for the rest of the session. That is wider than admitting the short-lived connectingkaprocess alone — use it only when you intend lineage trust, and read the loudvia=interactive-treeannounce + audit line for the root you actually chose. It does not change--pre-admit(arrival-time grant vs lineage root).- A live guard session reloads on change, not on a fixed schedule. The guard checks a cheap content fingerprint of the vault file on every
run/list/status; when another terminal changes it, the guard re-opens with the SecretBox key it already derived at unlock — no new password prompt. The tradeoff: the guard keeps that derived key in memory for the session. Detail: DESIGN.md and the threat-model wiki page. - Runner role is not a cryptographic ACL against you. If your local identity is enrolled as
runner,karefusesreveal/copy— effective against an agent. Anyone who knows the master password can still decrypt the vault offline. Per-memberka exportciphertext is cryptographic (only that member's key opens it).
Longer honesty notes and policy-vs-crypto labels: wiki — Threat model (draft; maintainer judgement flagged).
Community
Questions, bugs, and ideas: Discord, GitHub Discussions, or GitHub issues.
Support
key-amnesia is free and open source. If it's useful to you, you can support its development here:
Development
pip install -e ".[dev]"
pytest
Design rationale, file formats, invariants: DESIGN.md. Wiki drafts suitable for publishing live in wiki/.
License
Apache License 2.0 — see LICENSE.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found
