Open-source project
biox/pa avatar
biox/pa

pa: a password manager in about two hundred lines of POSIX shell

a simple password manager. encryption via age, written in portable posix shell

575 stars25 forksShellNOASSERTION

At a glance

What is it?
pa stores encrypted password entries with age, generates keys on first run, and optionally tracks every change in a git repository. There is no daemon, no configuration file and no database, just one shell script you can read end to end, which is the point of the project.
Who is it for?
pa fits someone who wants a password store they can read, back up and version like code, and who is comfortable with age and with shell. It does not fit a team that needs a shared vault with roles, a browser extension, or a GUI, and it does not fit someone who wants passwords synchronised across devices without git.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 54 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Everything is one script, and that is the feature

The feature list is unusually short, and each item is a decision. Encryption is implemented using age, which is a project by Filippo Valsorda. Key generation is automatic. Git tracking is automatic, though it can be turned off. There is support for multiple identities and recipients. It is written in portable POSIX shell. It is simple to extend. It is only about two hundred lines of code. And it is pronounced pah, as in papa. The repository layout matches that claim. The top-level entries are a LICENSE, a README, a contrib directory, the pa script itself and a test file, so the whole implementation is a single readable file. For a security-sensitive tool, that is unusual, and the README's own framing in the FAQ is that pa is smaller, simpler, cleaner and plainer than the alternatives such as pass and passage. Whether that trade is right depends on how much you want to read before you trust it.

The command set, and the environment variables that tune it

Running pa with no arguments prints the usage. The commands are add with a name, which adds a password entry, del which deletes one, edit which opens an entry in vi, git which runs a git command in the password directory, list with an optional category, show which prints a password, and move which renames an entry. Four environment variables configure the behaviour. The data directory is set with PA_DIR and defaults to a path under the local share directory, the generated password length comes from PA_LENGTH and defaults to 50, the password character pattern comes from PA_PATTERN and defaults to letters, digits, low line and dash, and setting PA_NOGIT disables the git tracking.

bash
    $ pa add test
    generate a password? [y/N]: y
    saved 'test' to the store.

    $ pa list
    test

    $ pa show test
    vJwKuEBtxBVvdR-xppTdfofIei0oLlkoSK4OCSP2bMEBsP6ahM

So the entry name is a key, the secret is generated rather than typed, and the output of show is the decrypted value. The edit command opens the entry in your editor, and the move command renames one.

bash
    $ pa mv test example

    $ pa del example
    delete password 'example'? [y/N]: y

Git as the history layer, and why that changes the threat model

The automatic git tracking is the design choice that most affects how you should think about the tool. The README shows the resulting history after the example commands, with a commit for each operation.

bash
    $ pa git log --oneline
    bbe85dc (HEAD -> main) delete 'example'
    c7f76d7 move 'test' to 'example'
    b597c04 edit 'test'
    cba20cc add 'test'
    ef76f7e initial commit

Every add, edit, move and delete becomes a commit in a repository inside the password directory, and the git subcommand exists so you can inspect that history with the usual tools. The upside is real. You get an audit trail of every change to your vault, and you can back the store up with ordinary git mechanics, and the state is diffable. The downside is equally real. A git history of encrypted entries is only as safe as the keys, and if the store is ever committed or pushed somewhere, the earlier versions are in the history rather than gone, and a delete does not remove the file from the repository's past. Setting PA_NOGIT exists for people who do not want that, and it is the first decision to make when installing.

Where the keys live, and where the passwords live

The FAQ answers the practical question directly. The keys are probably in the default locations, the identities directory and the recipients directory, both under the local share directory in a pa subdirectory. The passwords are probably in the default location too, the passwords directory under the same root. The existence of a recipients directory is the hint about how the multi-recipient support works, since a recipient is a public key that you can encrypt to, and the identities directory holds the private key that decrypts. That arrangement is what age is designed for, with one identity encrypting to any number of recipients and the master key never leaving the machine it was generated on. The FAQ on security does not claim a design in the readme. It says that if you want to understand the security characteristics of pa, you should read the author's blog post on storing passwords with age and the explanation in a linked issue comment, and the question of why the project exists points at the same blog post. That is an unusually honest arrangement, since the reasoning lives outside the repository.

A fork of pash, with a test file and a contrib directory

The credits section records the lineage. pa was originally forked from pash by dylanaraps, and age is credited as a project by Filippo Valsorda. The repository root has the LICENSE, the README, a contrib directory, the pa script and a test file. The test file is worth noticing, because a two hundred line shell script with a test file is a better proposition than one without, and the tests can be run on any machine that has the dependencies. The contrib directory is where the extendability claim lives, and the project is explicit that it is simple to extend. The licence is one GitHub cannot classify, so the LICENSE file in the repository root is the authority, and it is worth reading before you decide the project is MIT. The repository is not archived and the last push was on 2026-08-30, with no GitHub releases, so the script in the default branch is the thing you would install.

Editorial conclusion

pa fits someone who wants a password store they can read, back up and version like code, and who is comfortable with age and with shell. It does not fit a team that needs a shared vault with roles, a browser extension, or a GUI, and it does not fit someone who wants passwords synchronised across devices without git. Verify first that you have age and age-keygen available, decide whether the git tracking is something you want, since every change becomes a commit, and read the author's own explanation of the security characteristics before you rely on it, because the FAQ points at a blog post rather than claiming a design in the readme.

Frequently asked questions

How do I add and show a password with pa?

Run pa add with a name, answer yes to the prompt to generate a password, and the entry is saved to the store. Then pa list shows the entry names and pa show with the name prints the decrypted password. Entries can also be edited in your editor with pa edit and renamed with pa move.

What does pa need installed?

age and age-keygen, with git optional. The script itself is written in portable POSIX shell, and the whole implementation is only about two hundred lines of code.

Does pa keep a history of my passwords?

Yes, through git. Every add, edit, move and delete becomes a commit in a repository in the password directory, so pa git log shows the history. You can turn the tracking off by setting the PA_NOGIT environment variable.

Where are my keys and my passwords stored?

Probably the default locations. The keys are in the identities and recipients directories under the local share directory for pa, and the passwords are in the passwords directory there. The data directory can be changed with the PA_DIR environment variable.

Official sources

  1. biox/pa on GitHub
  2. Issues
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/biox-pa.svg)](https://hysenlabs.com/projects/biox-pa)

Was this useful?