Skip to content

GPG Agent

dotsecenv does not configure gpg-agent. This page is a quick reference for users who need their existing agent to play well with dotsecenv: health checks, the recommended gpg-agent.conf, pinentry compatibility, cache warming, and the five problems people actually hit. For setup beyond this scope, see the GnuPG manual.

Before debugging anything specific, confirm the agent is reachable and the rest of the dotsecenv environment is healthy:

Terminal window
dotsecenv vault doctor

doctor verifies that gpg-agent is available, the vault format is current, and the vault is not fragmented. If gpg-agent is not running, doctor reports it and exits non-zero.

To talk to the agent directly:

Terminal window
gpg-connect-agent /bye
# OK ← agent is running

To list the agent’s current settings:

Terminal window
gpgconf --list-options gpg-agent

The same configuration used elsewhere in the documentation. Tuned for usability while still requiring re-entry on a regular cadence:

~/.gnupg/gpg-agent.conf
# Use a GUI pinentry appropriate for your platform:
# macOS: pinentry-program /opt/homebrew/opt/pinentry-mac/bin/pinentry-mac
# Linux: pinentry-program /usr/bin/pinentry-gnome3
# Passphrase expires after 1 hour of inactivity
default-cache-ttl 3600
# Hard cap: passphrase must be re-entered after 4 hours regardless of activity
max-cache-ttl 14400
# Prevent pinentry from storing passphrases in the OS keychain
no-allow-external-cache

Reload the agent after editing:

Terminal window
gpgconf --reload gpg-agent

For the security rationale behind each option — why no-allow-external-cache matters, when to set both TTLs to 0 for maximum security, and how the OS keychain interacts with these settings — see Threat Model: Recommended GPG Agent Configuration.

Pinentry is the program gpg-agent invokes to ask for your passphrase. The choice matters because different invocation contexts (terminal, GUI, AI agent subprocess) require different pinentry programs.

PinentryWorks in interactive terminalWorks in non-TTY context (CI, AI agent, cron)
pinentry-macYesYes, when passphrase is cached
pinentry-gnome3YesYes, when passphrase is cached and a display server is reachable
pinentry-qtYesYes, when passphrase is cached and a display server is reachable
pinentry-ttyYesNo — requires a controlling terminal
pinentry-cursesYesNo — requires a controlling terminal

If you use dotsecenv only at an interactive shell, any pinentry works. If you use it from CI, AI coding agents, scripts, or cron, choose a GUI pinentry and pre-cache your passphrase (see below). For details on why terminal pinentries fail in non-TTY contexts, see Threat Model: AI Coding Agents and GPG.

In any context without a controlling terminal, GPG cannot pop a pinentry dialog if the passphrase is not already cached. Warm the cache from your interactive shell before running the non-interactive job:

Terminal window
gpg --sign --local-user YOUR_FINGERPRINT </dev/null

This forces a passphrase prompt now, which a GUI pinentry can satisfy. The agent caches the passphrase for default-cache-ttl seconds, after which dotsecenv (and any other GPG operation) can run cleanly without a prompt.

GPG needs to know which terminal to attach pinentry to. Most shells set this automatically; if not, add it to your shell init:

Terminal window
# ~/.bashrc or ~/.zshrc
export GPG_TTY=$(tty)

Without GPG_TTY, you may see Inappropriate ioctl for device when the agent tries to prompt.

SymptomLikely causeFirst thing to try
gpg: agent_genkey failed: No agent runningAgent not started, or wrong GNUPGHOMEgpg-connect-agent /bye; if it errors, run gpgconf --launch gpg-agent
Inappropriate ioctl for device from secret get or secret storeTerminal pinentry without GPG_TTYexport GPG_TTY=$(tty) and try again
Passphrase prompt every time you run secret getdefault-cache-ttl 0 or no-allow-mark-trusted overriding cacheSet default-cache-ttl 3600 and reload: gpgconf --reload gpg-agent
secret get hangs in CI/AI-agent contexts then times outTerminal pinentry trying to prompt with no controlling terminalSwitch to a GUI pinentry, then warm the cache before running the job
gpg: signing failed: Card error or smartcard not detectedYubiKey/smartcard not inserted, or scdaemon cannot reach the readergpg --card-status; reinsert the card if missing

For broader threat-model context — what dotsecenv does and does not protect against, why caching is a security trade-off, and how the OS keychain factors in — see Threat Model.