kvendra unlock runs in your own terminal — never
inside an MCP client like Claude Code or Cursor. It derives
the master key with Argon2id and writes a session blob to
~/.kvendra/sessions/active.blob encrypted with a
machine-bound wrap key (hostname + uid +
canonical home path). Every subsequent
kvendra mcp serve subprocess reads the blob to
install the derived key —
the password never enters the MCP client's transcript
or the LLM's context.
TTL configuration
The [session] block of ~/.kvendra/config.toml controls session length:
[session]
default_ttl_seconds = 14400 # 4h (default)
max_ttl_seconds = 86400 # 24h (default; hard cap accepted by --ttl)
renew_on_activity = false # absolute TTL by default
Hard ceiling: 7 days
(MAX_CONFIGURABLE_TTL_SECONDS). Anything larger
is rejected.
Anti-captured-env defence
kvendra unlock refuses to run inside an MCP client subprocess.
Three layers, evaluated in order (PAT-KVD-CLI-008):
/dev/tty (POSIX) / CONIN$ (Windows). Direct open. A captured subprocess has no controlling terminal, so this fails with ENXIO and the command stops before the password prompt. - Triple
isatty + foreground process group match. Defence in depth — confirms stdin/stdout/stderr are real TTYs and the process is in the foreground. - Parent ancestry walk. Flags known MCP client binaries in the error message so you know exactly why the command refused.
If you ever see
kvendra unlock: no controlling terminal detected.
inside an IDE, that's the guard doing its job. Open a real
terminal and run kvendra unlock there instead.