EP002 · Get started

Get Started with EnvFolio

Install it, make your store, and put in your first text and secret. Then see them, and use them.

EP001 showed what EnvFolio is for: it keeps your texts and secrets in one store, and hands them to a command only when you ask. This one gets you there, in five steps:

  1. Install it.
  2. Make your store: folio init.
  3. Add a text and a secret: folio insert.
  4. See them: folio ls and folio show.
  5. Use them: folio exec and folio shell.
▶
Rather watch? The same steps are a short video: flip through the slides.

1 · Install

With Homebrew, on macOS or Linux:

brew install nawaman/tap/folio

Or by hand: EnvFolio is one bash script. Download folio and SHA256SUMS from the latest release, check it, make it executable and put it on your PATH:

sha256sum -c SHA256SUMS            # macOS: shasum -a 256 -c SHA256SUMS
chmod +x folio && mv folio ~/.local/bin/
folio version

If folio version is not found, ~/.local/bin is not on your PATH (often the case on macOS): add export PATH="$HOME/.local/bin:$PATH" to your shell's rc file.

It needs bash 3.2 or newer (the one macOS ships is enough), pass, gpg, git, tree, tar and gzip. On Windows, EnvFolio runs in WSL.

brew install pass gnupg tree          # macOS
sudo apt install pass gnupg git tree  # Debian / Ubuntu

For Tab completion of commands, options and item names, add eval "$(folio completion bash)" to ~/.bashrc, or the zsh one to ~/.zshrc. Completing never reads or decrypts an item, so it never asks for a passphrase.

2 · Make your store: folio init

folio init creates your store. It picks or creates the GPG key that protects it, runs pass init with that key, and starts the store's git history. It first says what it needs, then confirms each answer, and only then makes anything.

If you already have GPG keys, it shows them in a menu, with Create a new key at the end. With none, it goes straight to a new one: your name and your email (guessed from git when it can), and, with gpg 2.5.21 or later, the kind of key:

EnvFolio
folio init
✓ Store path: ~/.folio
Your name [e.g. Jane Doe]: Demo User
✓ Name: Demo User
Your email [e.g. jane@example.com]: demo@example.com
✓ Email: demo@example.com
✓ Passphrase: gpg asks for it when it makes the key
Which kind of key?
1) Post-quantum (recommended) — ML-KEM-768 + Brainpool P-256, Brainpool P-384
2) Classical — X25519, Ed25519
Pick a number (Enter for 1, Ctrl-D cancels):
✓ Key type: Post-quantum — ML-KEM-768 + Brainpool P-256, Brainpool P-384
Next, gpg asks you to choose the new key's passphrase (twice).
It protects the key: you need it to read your secrets and to add texts.
It cannot be reset, so keep it safe.
Press Enter to continue (Ctrl-D cancels):

A post-quantum key also protects your secrets from a future quantum computer, but every machine that opens the store, a backup of it, or an export locked to it then needs gpg 2.5.21 or later. Pick Classical if one of them has an older gpg. With an older gpg there is no question: the key is gpg's default.

Then gpg asks for the passphrase, and makes the key. The run ends with a summary:

Your pass store is ready.

Store:   ~/.folio
Key:     C9406AB7E48726D265D45E4AD5DE5723219725DF
         Demo User <demo@example.com>
Type:    post-quantum (ky768_bp256)
Expires: 2029-10-27

To get your passwords back if this machine is lost, you need both:

1. Your passphrase — it can't be reset. Memorise it, and keep a written copy offline.

2. A backup of your key and store — one file, made with:
     folio backup
   Keep it somewhere safe and offline, and run it again after you change passwords.

When the key expires (2029-10-27), pass can't add or change entries until you extend it:
  gpg --quick-set-expire C9406AB7E48726D265D45E4AD5DE5723219725DF 2y

Take the two points in the middle seriously: the passphrase cannot be reset, and without a backup a lost machine is a lost store. EnvFolio does not watch the key's expiry for you yet, so note the date and the command next to it.

Three more ways to run it:

  • folio init --key jane@example.com uses a key you already have, and asks nothing. An existing key needs no passphrase here: the store is only encrypted to it.
  • FOLIO_STORE_DIR=~/work-folio folio init puts the store somewhere else; every later folio command then needs the same FOLIO_STORE_DIR.
  • For a key with special needs (another algorithm, a smart card, another expiry), make it with gpg first, then pick it here.

That one command set up a GPG key, a store that names it, and a passphrase that locks the key. You will meet the passphrase in the steps below. gpg asks for it, never folio: a small program, pinentry, asks you in the terminal or in a window, and gpg-agent then remembers it for a while. Adding a secret needs no passphrase; reading one, or adding a text, does. EP003: The Pieces takes each piece in turn.

3 · Add items: folio insert

A text is not a secret, so it may be given on the command line. folio signs it, so gpg may ask for the passphrase:

folio insert text -t "demo@example.com" gh/user

A secret never is. It is asked twice, at a hidden prompt (this is pass insert; its --echo is refused, as it would show the secret):

EnvFolio
folio insert secret gh/token
Enter password for gh/token:
Retype password for gh/token:
[master f696965] Add given password for gh/token to store.
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 gh/token.gpg
ls ~/.folio/gh
token.gpg user.txt user.txt.sig

From a script, pipe it in, twice, one per line: printf '%s\n%s\n' "$value" "$value" | folio insert secret gh/token. Piped in, an existing secret is overwritten without asking (the old one stays in the history). Both kinds take -m for several lines.

4 · See them: folio ls and folio show

folio ls lists both kinds as one tree. Names only, never values; signatures are left out. On a screen that draws emoji a secret is marked 🔑 and a text 📄; in a pipe, or with --plain, they are (S) and (T).

EnvFolio
folio ls
EnvFolio Store
├── aws
│ └── 📄region
├── db
│ ├── 🔑pass
│ └── 📄user
└── gh
├── 🔑token
└── 📄user

folio ls text and folio ls secret list one kind; a folder name lists only that folder; --flat prints one full name per line, ready for grep.

folio show prints one value. You always say which kind you mean, so a secret is never shown by accident: a text and a secret can share a name, and show text never prints the secret. A text is checked against its signature first, with no passphrase; a secret is decrypted, so this may be where pinentry asks.

EnvFolio
folio show text gh/user
demo@example.com
folio show secret gh/token
ghp_DEMO0000fake0000token

-c copies the value to the clipboard instead of printing it, so it never shows on the screen. For a secret, it is the first line, and the clipboard is cleared after 45 seconds; a text is not a secret, so its copy is not cleared. -c needs pbcopy, wl-copy or xclip.

EnvFolio
folio show secret -c gh/token
Copied gh/token to clipboard. Will clear in 45 seconds.

5 · Use them: folio exec and folio shell

folio exec runs a command with items as environment variables, named after their path. Name a folder, and every item under it comes along. Texts load by default; a secret only with -s (--secrets). folio ls gh first shows what the folder gh holds: a secret, token, and a text, user.

EnvFolio
folio ls gh
EnvFolio Store
gh
├── 🔑token
└── 📄user
folio exec -s gh -- sh -c 'env | grep GH_'
GH_TOKEN=ghp_DEMO0000fake0000token
GH_USER=demo@example.com

The env is only there to show the values arrived; a real command just uses them. Reading gh/token is the first time a secret is decrypted, so this is where pinentry asks, once, and gpg-agent remembers. Not sure what a run will load? --names shows which variable gets which item, reads nothing and runs nothing. EP001 has the rest: picking a variable's name, vars files, and taking the items to a machine with no store.

folio shell does the same for a whole session: it starts your shell with the items, prints the names it loaded (never the values), and sets FOLIO_SHELL=1 for your prompt to show. exit leaves it.

EnvFolio
folio shell -s gh
folio shell: loaded GH_TOKEN, GH_USER (texts: 1, secrets: 1). Type 'exit' to leave.
echo $GH_USER
demo@example.com
exit

And the rest

The everyday commands follow pass, and each one names the kind it is for: folio show secret web/github, folio show text web/github. A secret is never shown by accident. The kind can also come first: folio secret show is folio show secret.

editedit it in $EDITOR
generatemake a random one
mv · cp · rmrename or move, copy, remove
find · grepfind by name, or by value
EnvFolio
folio mv text gh/user gh/login
folio find text login
Search Terms: login
└── gh
└── login

folio backup saves the whole store and its key (still under its passphrase) into one file, and folio restore brings it back, here or on a new machine. Make one now, and keep it somewhere safe and offline. folio help lists every command, and folio help <command> explains one.

Bottom line

Five steps get you going: install, folio init, folio insert, folio ls and folio show, and folio exec or folio shell. When gpg asks for your passphrase, it is pinentry asking for gpg-agent, which then remembers it for a while. Keep the passphrase, and a backup, safe. How the pieces under it all fit together is EP003: The Pieces.

Keep your secrets out of plain sight.

Links