Runtime text-surface protection for AI coding workflows.
Your AI agent's transcripts, your shell history, and your terminal output are leaking secrets right now. keynv keeps them out, in real time, on your machine. No cloud. No re-architecting how you work.
$ keynv doctor
! zsh history 5 likely secrets across 1 file
! Claude Code transcripts 62,306 likely secrets across 73 files
· Cursor logs clean
Total: 62,311 likely secrets across 74 files.
Top patterns:
aws-access-key-id 90
openai-api-key 81
github-pat-classic 59
jwt 59
slack-webhook 45
stripe-live-secret-key 34
postgres-uri 515
...
That's one developer machine on a normal workday. Vendor-prefixed token leaks are common, postgres URIs with credentials are extremely common, and almost every AI agent session has at least one. The same machine would pass any storage-era secret-manager audit clean.
keynv finds the leaks. Then it fixes them — atomically, with backups — and stops new ones happening.
The GIF runs against a seeded sandbox of fake secrets — regenerate it with
vhs demo/keynv-doctor.tape. The 62,311 figure above is a real scan of a real developer machine.
keynv scrub # retroactively clean what doctor found
keynv shell install # prevent new leaks from landing in shell history
keynv watch start # scrub live AI agent sessions in real time
keynv exec -- npm run dev # agents reference aliases; real values stay in a subprocess they can't seeSee docs/00-vision.md for the long form;
docs/02-threat-model.md for what keynv
defends against and what it explicitly doesn't.
These categories already have mature incumbents. keynv does not compete with them:
- ❌ Vault / Doppler / Infisical / 1Password alternative
- ❌ ".env replacement"
- ❌ Secrets manager
- ❌ Enterprise SSO / SCIM / federation
- ❌ Compliance theatre
If your problem is "where do I store the secret," those tools solved that already. keynv plugs in next to them (or to its own local SQLite vault). Storage is an implementation detail. Runtime text-surface protection is the product.
@<project>.<environment>.<key> — kebab-case segments, e.g.
@billing.prod.stripe_key. Detection regex lives in
packages/core/src/reference/types.ts. Aliases survive everywhere a string
can: code, configs, shell commands, dotenv files, CI templates.
Five-row, project-scoped permission matrix. Lives in packages/rbac.
| Role | What they can do |
|---|---|
| Owner | Everything; one per org; can rotate the master key |
| Admin | Manage projects, members, secrets, audit; can't transfer ownership |
| Team Lead | Per-project: add members, rotate secrets, grant production access |
| Developer | Read assigned secrets via alias; no UI access to plaintext values |
| Reader | Read-only on metadata; can't resolve values |
1. Alias-first resolution. Developers and agents reference
@prod.database.url. The runtime resolves the alias to the real
value ephemerally — inside a privileged subprocess your AI agent's
process tree cannot read. Output through the redactor. Audit trail
per resolution event.
2. Text-surface scrubbing. Every text surface where a secret could leak — shell history files, Claude Code session JSONL, Cursor logs, terminal stdout, CI output — is monitored, scrubbed, or pre-empted. Five commands cover the lifecycle:
| Command | What it does |
|---|---|
keynv doctor |
Read-only retro scan; counts likely leaks across all known surfaces |
keynv scrub |
Atomic in-place rewrite with .keynv.bak.<ts> backups |
keynv shell install |
Preventive zsh/bash/fish history hook (pure regex, no per-command subprocess) |
keynv watch start |
Real-time chokidar daemon — scrubs live AI agent sessions on the fly |
keynv exec |
Alias resolution + automatically registers values with the running watcher so even custom-format secrets get caught |
The two layers compose. The alias half catches secrets before they
enter a surface. The scrubbing half catches the ones that slip through
(cat .env, a stack trace with a header, a copied error message).
npm install -g @keynv/cli
keynv doctorScan only — nothing is rewritten, no network calls. Match previews are bounded to 3 characters; raw values never appear in the output.
keynv scrub --dry-run # preview the plan
keynv scrub # interactive confirm; atomic + backupsFiles mtime'd in the last 10 seconds are skipped by default (likely
being actively written by a live AI session); pass --include-active
to override.
keynv shell install # marked block goes in your ~/.zshrc / ~/.bashrc
keynv shell status # show what's installed where
keynv shell uninstall # cleanly removeThe hook scrubs secret-shaped substrings before each command lands in
~/.zsh_history. POSIX-ERE regex (no per-command subprocess unless a
match fires). Pattern bank mirrors @keynv/redactor's vendor-prefixed
tokens (AWS, GCP, GitHub, Stripe, JWT, Slack, OpenAI, Anthropic) plus
credential-bearing URIs.
keynv watch start # foreground; Ctrl-C to stop
keynv watch status # pid, surfaces, scrub counts
keynv watch stop # SIGTERM → SIGKILL escalation after 15sThe watcher subscribes to ~/.claude/projects/**/*.jsonl (Claude Code
transcripts) and ~/Library/Application Support/Cursor/logs/**/*.log
(Cursor) via chokidar, debounces writes at 1 second, and atomically
rewrites matched substrings. Lifecycle and per-event audit lands in
~/.local/share/keynv/watcher.log.
The self-host server + vault gives you alias storage. Initial setup:
- Coolify walkthrough (recommended) — 15 minutes
- Docker Compose guide
Once deployed:
curl https://api.keynv.example.com/v1/health
keynv login # browser flow; session lands in OS keychain
keynv project create demo
keynv secret create @demo.dev.api_key --value 'whatever'Or use the menu — running keynv with no args in an interactive
terminal opens a TUI that walks through the same operations.
Prefer a standalone binary over Node? Each release publishes
keynv-{darwin,linux,windows}-{arm64,x64}archives at GitHub Releases with SHA256SUMS for verification.
Run keynv in your project root and choose Set up this project. It creates a
.keynv.env file for you. It is safe to commit — it carries alias
references, never values.
# .keynv.env (commit this!)
OPENAI_API_KEY=@demo.dev.openai-key
DATABASE_URL=@demo.prod.db-url
NODE_ENV=development # plain literals work tooThen wrap whatever you'd normally run with keynv exec:
keynv exec -- npm run dev
keynv exec -- pytest
keynv exec -- next buildkeynv exec walks up from your cwd to find .keynv.env, resolves every
@alias against the vault, and forks the subprocess with the real values in its
env. Your shell, your editor, and the AI agent driving the terminal never see
the resolved values — only the alias literals.
In package.json it disappears into the script:
{
"scripts": {
"dev": "keynv exec -- next dev",
"test": "keynv exec -- vitest"
}
}Heads up — Next.js 16 + React 19 build worker: the upstream
create-next-app@latesttemplate currently failsnext buildon/_global-errorprerender (Cannot read properties of null (reading 'useContext')). This is a Next.js + React 19 template issue, NOT a keynv issue — the same scaffold fails without keynv in the loop.next devworks fine; for production builds either pinnext@15or wait for the upstream fix.
| Phase | What | State |
|---|---|---|
| 0 | Discovery + spike measurements | done |
| 1 | Core vault: server, CLI, RBAC, audit, encryption | done |
| 2 | Alias resolution: keynv exec, keynv-mcp, redactor, installers |
done |
| 3 | Connection testers: postgres, mysql, redis, ssh, http, AWS, GCP | done |
| 4 | Web UI for team leads (Next.js 15) | in progress (slice 9 of ~11) |
| A | Runtime text-surface protection — primitives (doctor, scrub, shell install, watch, fingerprint registry) |
done |
| B | MCP capability tokens + keynv.run agent-bound subprocess execution |
not started |
| C | First-class agent integrations (Claude Code skill, Cursor extension) | not started |
Versioning is unstable pre-1.0 — schemas, APIs, and config formats may change without backwards-compatibility shims.
A self-hosted Cloud option may exist later as a commercial deliverable. The OSS path is local-first and the only supported deployment for now. See
docs/00-vision.mdfor the positioning.
| Getting started | First run, core commands, headless/CI usage |
| Quickstart | The five-step local workflow end to end |
| AI setup (Claude Code / Cursor / MCP) | Wire keynv into your AI agents so they reference aliases, not values |
| Vision | What keynv is, what it's not, where it goes |
| Threat model | What we defend against, what we explicitly don't |
| Text surfaces | The TextSurface contract, rewrite semantics, race window |
| Architecture | Components, data flow, trust boundaries |
| Encryption design | KEK / DEK split, libsodium primitives |
| Backup/restore runbook | RPO/RTO, restore drills, KEK loss handling |
| API spec | HTTP endpoints |
| API compatibility | CLI/server skew, feature flags, deprecation policy |
| Roadmap | Phase status + active slice tracker |
| Coolify deploy | 15-min self-host walkthrough |
AGENTS.md |
Working rules for humans + AI agents in this repo |
Stack: TypeScript everywhere; Bun for the CLI, Node 20+ for the server, Hono +
SQLite + Drizzle + libsodium. Working rules in AGENTS.md.
Open core ships under MIT — see LICENSE. Decision rationale
in docs/decisions/0001-license-choice.md.
The planned Phase 6 commercial modules (SSO, HSM, SIEM, multi-step approvals) and
the keynv Cloud service are intended to ship under a separate commercial license
in a future packages/ee/* subdirectory, kept isolated from the open-core
packages. (That subdirectory does not exist in this repository yet.)
