pass, GPG-agent, and alternativesThe Suckless project does not prescribe a password manager or a key-management daemon. Its official position is a design philosophy: simplicity, clarity, frugality, small scope, and Unix composition.
pass is nevertheless a strong fit. Its own author describes it as a simple Unix password manager: encrypted files, ordinary filesystem tools, shell commands, and optional Git synchronization. Its design deliberately uses GPG and the standard gpg-agent.
For this repository, keep pass and GPG. Do not run a separate GPG service under runit. Simplify the integration instead: configure the terminal once in interactive shell startup and let GnuPG start its agent on demand.
age/passage is the credible alternative if GPG’s key model and agent/pinentry machinery are an unacceptable source of complexity. It requires a new store or migration and makes a different security tradeoff; it is not an automatic fix for this existing store.
The official Suckless philosophy says software should focus on “simplicity, clarity and frugality” and describes code reduction and Unix philosophy as virtues:
https://suckless.org/philosophy/
The official tools catalogue contains small utilities such as dmenu, slock, ii, and quark, but no official password manager or GPG-agent policy:
Therefore claims such as “Suckless recommends GPG” or “Suckless rejects daemons” would be invented. The reasonable method is to apply the principles to the actual threat model and workflow.
pass aligned with that philosophy?Very directly. The pass project says:
Source: https://www.passwordstore.org/
This is closer to the Suckless ideal than a cloud account, browser integration stack, database vault, or large desktop application. The use of an agent does not by itself make the design non-suckless: it is a small shared Unix service that avoids making every client implement private-key handling and passphrase caching.
The important distinction is that gpg-agent is not an additional password manager. It is GnuPG’s backend for private-key operations and passphrase caching.
The official GnuPG manual says that gpg-agent is automatically started on demand by gpg, gpgsm, gpgconf, or gpg-connect-agent; there is normally no reason to start it manually.
It also recommends setting this in the shell initialization used by all shell invocations:
GPG_TTY=$(tty)
export GPG_TTY
The same manual documents updatestartuptty, especially for switching the terminal/display used by GPG’s SSH-agent support.
Source: https://www.gnupg.org/documentation/manuals/gnupg/Invoking-GPG_002dAGENT.html
This changes the conclusion about the current workaround:
GPG_TTY=$(tty) is the durable configuration.
gpgconf --launch gpg-agent is normally redundant for pass.
gpg-connect-agent updatestartuptty /bye is a useful repair command, but should not generally be needed before every ordinary pass show.
The current setup/neon-usage-env.sh performs all three commands locally before reading the secret. It works, but it puts session repair logic in an application-specific generator. A simpler design is to set GPG_TTY once in the common interactive shell environment and let pass invoke GPG normally.
A POSIX-safe form that does nothing when there is no terminal is:
if GPG_TTY=$(tty 2>/dev/null); then
export GPG_TTY
fi
This belongs in the shared shell initialization, not in a Neon-specific script. Keep updatestartuptty as a manual recovery command, or use it when changing terminals if SSH-agent support is enabled.
age and passageage is explicitly designed as a simple Unix encryption tool. Its project describes it as having small explicit keys, no configuration options, and Unix-style composability:
passage is a fork of pass that replaces GPG with age:
https://github.com/FiloSottile/passage
This removes the GPG-specific keyring, agent socket, GPG configuration, and GPG_TTY problem. The basic model is easier to explain:
passage -> age -> identity file -> decrypted text
There are two relevant security choices:
So passage is simpler operationally, but “no agent” does not automatically mean “more secure.” It shifts the choice to where the identity is stored and how often it is unlocked.
It is also not a drop-in backend for this repository. Existing pass/neon-usage.gpg entries need migration to .age entries, and scripts, extensions, and recovery documentation need updating.
gopassgopass is a more capable replacement for pass. Its own project describes support for GPG, age, Git, other storage backends, teams, browser integration, and more:
https://github.com/gopasspw/gopass
That may be useful for teams, but it adds features and a larger implementation. It is not the minimal choice for this one-user dotfiles repository.
These can be excellent security products, particularly where multi-device sharing, recovery, auditing, or browser integration matters. They introduce a database/application or hosted-service model, however, so they do not follow the same small-files-plus-Unix-tools approach. Security requirements can justify that complexity, but “Suckless” alone is not a reason to choose one.
ageThis could be the smallest implementation for a few secrets, but it would duplicate indexing, editing, generation, synchronization, permissions, and migration behavior already provided by pass or passage. It is less code only until the missing edge cases matter.
pass and the existing GPG-encrypted Git store;
/usr/bin/pinentry-curses for terminal prompts;
GPG_TTY=$(tty) in the common interactive shell initialization.
gpgconf --launch gpg-agent from the Neon-specific path unless it is retained as a deliberate workaround.
updatestartuptty before every mk neon; use it for a stale-terminal recovery or GPG SSH-agent setup.
pass show pass/neon-usage be the end-to-end health check. It already starts the agent when needed.
passage only whenPeople closest to the Unix/suckless style do not have one mandatory answer. The strongest evidence points in two directions:
pass maintainers: use simple files, GPG encryption, Git, and the normal GPG agent. This is already a Unix-philosophy design.
age/passage users: use explicit age identity and recipient files to avoid GPG’s larger historical interface and agent integration. This is simpler if the different key-storage tradeoff is acceptable.
For the current machine and existing encrypted store, replacing GPG because of one TTY failure would be complexity added for the wrong reason. Keep GPG, configure GPG_TTY once, and remove unnecessary lifecycle management from mk neon.
pass: https://www.passwordstore.org/
age: https://age-encryption.org/
passage: https://github.com/FiloSottile/passage
gopass: https://github.com/gopasspw/gopass