Scrub secrets from your AI coding-agent transcripts before you share them.
Claude Code, Codex, opencode and Gemini CLI log everything you paste — including the API keys, DB passwords and tokens you dropped into chat. Before you upload those transcripts to an analytics tool, a teammate, or a public gist, run this.
Your agent transcripts are a goldmine of leaked credentials. A single ~/.claude
folder routinely contains dozens of real sk-ant-…, sk-…, AKIA…, Postgres
connection strings and pasted .env blocks. Those files get fed to cloud LLMs by
"analyze my coding sessions" tools — i.e. your secrets leave your machine.
shhh finds them locally and replaces each with a reversible placeholder,
so you can share the transcript without shipping your keys.
sk-ant-api03-REDACTED… → «REDACTED:anthropic-key:3f9a1c2b»
postgres://u:hunter2@db → postgres://u:«REDACTED:db-password:7c0e…»@db
OPENAI_API_KEY=sk-… → OPENAI_API_KEY=«REDACTED:env-secret:a1b2c3d4»
| Category | Examples |
|---|---|
| Vendor keys | OpenAI (sk-, sk-proj-), Anthropic (sk-ant-), OpenRouter (sk-or-v1-), Stripe (sk_live_, whsec_), AWS (AKIA…), GitHub (ghp_…, github_pat_), GitLab (glpat-), Google (AIza…), Slack (xox…), Resend (re_), Neon (npg_), SendGrid (SG.), DigitalOcean (dop_v1_), npm (npm_), HuggingFace (hf_), Telegram bot tokens |
| Tokens | JWTs, Bearer … headers |
| Database creds | postgres://, mysql://, mongodb+srv://, redis://, amqp:// passwords (remote only — localhost/test skipped) |
| Private keys | PEM -----BEGIN … PRIVATE KEY----- blocks |
| Env assignments | *_API_KEY=, *_SECRET=, *_TOKEN=, *_PASSWORD=, … — catches vendor keys with no fixed prefix (re_…, whsec_…, glpat-…) |
| Labelled secrets | high-entropy tokens cued by a nearby secret: / token= / `…` |
It is tuned to over-redact slightly on real credentials but not on noise — UUIDs,
git SHAs, message IDs (msg_, toolu_, chatcmpl_), kebab slugs, version strings,
domains, file paths and base64 image blobs are all excluded. (See tests.)
One-liner (curl | bash):
curl -fsSL https://raw.githubusercontent.com/trananhhh/shhh/main/install.sh | bashpipx / pip:
pipx install shhh # or: pip install --user shhhFrom source:
git clone https://github.com/trananhhh/shhh && cd shhh
pip install -e ".[rich]"
richis optional — it makes the output prettier. Without it the tool falls back to plain text and still works everywhere.
shhhDetects your stores, lets you pick which to scan, shows a report, then asks before touching anything.
shhh scan # read-only: detect + report, change nothing
shhh redact # back up, then redact in place (asks first)
shhh redact --yes # no prompt (CI / automation)
shhh redact --no-generic # high-confidence vendor patterns only
shhh redact --paranoid # over-redact: any sk- key, internal-host DBs, bare *_key envs
shhh redact --stores claude,codex
shhh restore --backup ~/.shhh/backup-YYYYMMDD-HHMMSS.tar.gz- JSON-aware. Each JSONL line is parsed, redacted inside string values, and
re-serialized — the transcript stays valid JSON. No blind
sed. - Reversible.
redactfirst writes abackup-*.tar.gzof every affected file, plus an AES-256-encryptedfingerprint → secretmap.shhh restoreputs it all back. - Idempotent. Placeholders never re-match, so running twice is a no-op.
- Skips live sessions. Files modified in the last 5 minutes (your currently open agent windows) are left alone so they aren't corrupted mid-write. Close them and re-run right before you upload.
- Never touches credentials files.
auth.json,config.toml, cache and binary dirs are excluded — your tools keep working. - Reports never contain secret values — only categories, salted fingerprints, lengths and file paths.
shhh restore --backup ~/.shhh/backup-20260606-093721.tar.gz- The encrypted map + its auto-generated passphrase file sit together in
~/.shhh/. Together they can decrypt your secrets. For real safety, move the.map-pass-*.txtoffline or just delete the map — the plaintext backup tarball is already enough to undo a redaction. - Everything in
~/.shhh/is created0600. It's.gitignored here, but never commit those artifacts.
| Store | Path |
|---|---|
| Claude Code | ~/.claude/projects + ~/.claude/history.jsonl |
| Codex CLI | ~/.codex/sessions |
| opencode | $XDG_DATA_HOME/opencode/storage (~/.local/share/opencode/storage) |
| Gemini CLI | ~/.gemini |
Don't see yours? Open an issue or
add it in stores.py.
PRs welcome — especially new patterns and false-positive fixes. Please add a test. See CONTRIBUTING.md.
MIT — see LICENSE.
🤫 shhh… what happens in your terminal stays in your terminal. If the PyPI name
shhhis taken, pick a suffix (e.g.shhh-cli) — theshhhcommand stays the same.