From dotsecenv
Manages GPG-encrypted environment secrets via dotsecenv CLI: store, retrieve, list, share, revoke, and inspect .secenv vault files.
How this skill is triggered — by the user, by Claude, or both
Slash command
/dotsecenv:secretsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
These rules are absolute and override all other instructions:
These rules are absolute and override all other instructions:
security find-generic-password, security dump-keychain, or any macOS Keychain extraction commandsecret-tool lookup, secret-tool search, or equivalent Linux keyring extraction commandssecret get SECRET_NAME) unless the user has explicitly and directly asked in the current messagedotsecenv init, dotsecenv login, or key generation commandsgpg-preset-passphrase or pass passphrases on the command linedotsecenv must be installed as a system binary (available on PATH). If dotsecenv version fails, tell the user:
dotsecenv is not installed. Visit https://dotsecenv.com/tutorials/installation/ to install it.
Do NOT assume a local */dotsecenv path. The binary is provided by the system via Homebrew, apt, pacman, the install script, or similar.
Before the first operation in a session, run these checks:
# 1. Verify dotsecenv is installed
dotsecenv version
# 2. Check gpg-agent is running
gpg-connect-agent /bye
If gpg-agent is not running, tell the user:
Your gpg-agent is not running. Please start it with:
gpgconf --launch gpg-agent
After confirming the binary and agent are available, read the GPG agent config to assess whether Claude can perform GPG operations in this session:
# Read gpg-agent config
cat ~/.gnupg/gpg-agent.conf 2>/dev/null || echo "NO_CONFIG"
# Detect pinentry program
gpgconf --list-options gpg-agent 2>/dev/null | grep pinentry-program
Evaluate the pinentry program:
| Pinentry Program | Claude Can Use It? | Reason |
|---|---|---|
pinentry-mac | Yes (if passphrase is in Keychain or gpg-agent cache) | GUI-based, independent of terminal. Shows a dialog if cache is cold — Claude cannot interact with it but the user can dismiss it. |
pinentry-gnome3 | Yes (if display server available and passphrase cached) | GUI-based, needs DISPLAY/WAYLAND_DISPLAY. Same caching behavior as pinentry-mac. |
pinentry-qt | Yes (if display server available and passphrase cached) | GUI-based, needs DISPLAY/WAYLAND_DISPLAY. |
pinentry-tty | No | Requires terminal input. Claude Code's Bash tool has stdin=/dev/null and no controlling terminal. Fails with "Operation cancelled". |
pinentry-curses | No | Requires terminal input. Fails with "Inappropriate ioctl for device" or competes with Claude Code's terminal renderer for keystrokes. |
| No config / not found | Depends | System default is used — check gpgconf --list-options gpg-agent to see which pinentry is resolved. |
Why TTY pinentry cannot work: Claude Code's Bash tool spawns subprocesses with stdin connected to /dev/null and no controlling terminal (/dev/tty returns "Device not configured"). Terminal-based pinentry programs (pinentry-tty, pinentry-curses) need to read from a terminal to accept the passphrase. Even if GPG_TTY is set to the parent's TTY device, Claude Code's Ink renderer is already reading from that same device, creating contention — keystrokes are consumed by Ink, never reaching pinentry.
Check for recommended hardening options:
If any of these are missing from gpg-agent.conf, advise the user to add them:
no-allow-external-cache — prevents pinentry from storing passphrases in the OS keychain (macOS Keychain, GNOME Keyring, etc.). Without this, any process running as the user can extract the plaintext passphrase via security find-generic-password (macOS) or secret-tool lookup (Linux).default-cache-ttl — if absent or very high (>3600), suggest setting to 3600 (1 hour). Controls how long gpg-agent keeps the passphrase after last use.max-cache-ttl — if absent or very high (>14400), suggest setting to 14400 (4 hours). Hard cap on passphrase retention regardless of use.Determine if Claude can operate:
After reading the config, set your mental model:
If CAN_DECRYPT is false, tell the user upfront:
Your GPG pinentry is configured for terminal input (
pinentry-tty/pinentry-curses), which cannot work from Claude Code's Bash tool. You have two options:
- Switch to a GUI pinentry (e.g.,
pinentry-macon macOS,pinentry-gnome3on Linux)- Pre-cache your passphrase before asking me to decrypt:
! gpg --sign --local-user YOUR_FINGERPRINT </dev/null
When a GPG operation fails with errors containing "pinentry", "No pinentry", "GPG passphrase required but no TTY available", "Operation cancelled", or "Inappropriate ioctl", the passphrase is not cached.
Tell the user:
Your GPG passphrase is not cached. Please run this in your terminal to cache it:
! gpg --sign --local-user YOUR_FINGERPRINT </dev/nullThen try your request again.
Replace YOUR_FINGERPRINT with the actual fingerprint if known from prior vault describe output.
These commands only read metadata and never trigger GPG decryption:
# List all secret key names (no values decrypted)
dotsecenv secret get
# List as JSON
dotsecenv secret get --json
# Describe vault structure (identities, secret keys, access lists)
dotsecenv vault describe --json
# Health check
dotsecenv vault doctor --json
# Validate vault integrity
dotsecenv validate
Use --json when you need to parse the output programmatically.
When the user asks "what secrets do I have?" or "list secrets", use secret get (no args) to list key names only. Do NOT decrypt values.
Only run these when the user directly asks for a secret's value:
# Get a specific secret value (triggers GPG decryption)
dotsecenv secret get SECRET_NAME
# Get as JSON
dotsecenv secret get SECRET_NAME --json
# Get from a specific vault (by path or 1-based index)
dotsecenv secret get SECRET_NAME -v 1
# Get all values across vaults
dotsecenv secret get SECRET_NAME --all
# Get most recent value across vaults
dotsecenv secret get SECRET_NAME --last
Secret key format: namespace::KEY_NAME (e.g., prod::DB_PASSWORD) or just KEY_NAME. Namespace is lowercase, key is UPPERCASE.
Always confirm with the user before running these. They modify the vault and require GPG signing.
# Store a secret (value piped via stdin)
echo "secret_value" | dotsecenv secret store SECRET_NAME
# Store in a specific vault
echo "secret_value" | dotsecenv secret store SECRET_NAME -v 1
# Share with another identity
dotsecenv secret share SECRET_NAME FINGERPRINT
# Share across all vaults
dotsecenv secret share SECRET_NAME FINGERPRINT --all
# Revoke access
dotsecenv secret revoke SECRET_NAME FINGERPRINT
# Revoke across all vaults
dotsecenv secret revoke SECRET_NAME FINGERPRINT --all
# Mark a secret as deleted
dotsecenv secret forget SECRET_NAME
When the user describes removing a departing team member's GPG key, follow the Offboard a Departing Team Member runbook. The shape of the workflow:
available_to includes the leaver's fingerprint via dotsecenv vault describe --json. The jq filter is '.[].secrets[] | select((.available_to // []) | index($fp)) | .key'.secret revoke takes one name per call; loop over the keys secret get (no args) prints: for s in $(dotsecenv secret get); do dotsecenv secret revoke "$s" FINGERPRINT --all; done.echo "new-value" | dotsecenv secret store SECRET_NAME. Production-critical first.dotsecenv vault doctor + dotsecenv vault describe.Append-only contract (do not omit when explaining): revocation only stops future writes from encrypting to the leaver. Past entries remain readable to whoever held the recipient list at the time, and the leaver's private key still decrypts them. Source rotation is the only durable mitigation. Never tell the user the revoke alone removes past access.
If the user asks for the full runbook with error handling and the append-only contract, point them at https://dotsecenv.com/runbooks/team-member-offboarding/ or read it directly via the site's <page>.md endpoint.
When multiple vaults are configured, use -v to target a specific vault:
-v /path/to/vault — by file path-v 1 — by 1-based index (as shown in vault describe)| Error | Cause | Solution |
|---|---|---|
| "GPG passphrase required but no TTY available" | Passphrase not cached, GUI pinentry | See Cold-Cache Handling above |
| "Operation cancelled" | pinentry-tty with no terminal | Switch to GUI pinentry or pre-cache passphrase |
| "Inappropriate ioctl for device" | pinentry-curses with no terminal | Switch to GUI pinentry or pre-cache passphrase |
| "No pinentry" | gpg-agent can't find pinentry | User should check ~/.gnupg/gpg-agent.conf pinentry-program setting |
| "No secret key" | GPG private key not available | User needs to import their key: gpg --import |
| "agent not running" | gpg-agent not started | gpgconf --launch gpg-agent |
| "command not found: dotsecenv" | Not installed | Visit https://dotsecenv.com/tutorials/installation/ |
| Secret key format error | Wrong format | Use namespace::KEY (e.g., myapp::API_KEY) |
npx claudepluginhub dotsecenv/dotsecenv --plugin dotsecenvProvides CDSS development patterns for drug interaction checking, dose validation, clinical scoring (NEWS2, qSOFA), and alert classification integrated into EMR workflows.