piggy

PIV-based encryption for daily use.

piggy is a combo of pass, pivy, and age:

  • pass ergonomics — the passwordstore.org command surface (init, show, insert, edit, generate, rm, mv, cp, find, grep, git), with the same filesystem layout and same git integration.
  • pivy key material — passwords are encrypted to a YubiKey PIV slot (default 9D, Key Management / ECDH) via pivy-box, so unlocking requires a physical touch rather than a passphrase. Decryption works transparently over SSH agent forwarding, or directly against a locally-attached card when no agent is reachable.
  • age spirit — the ebox template format plays the role age's recipient syntax does: a small, explicit list of public keys that can unseal the payload, built on modern ECDH rather than legacy RSA/PGP. Encrypted files live alongside the plaintext command flow, not behind a separate keystore.

Install

piggy ships as a Nix flake. With flakes enabled:

nix run github:amarbel-llc/piggy -- --help
nix profile install github:amarbel-llc/piggy

For development:

git clone https://code.linenisgreat.com/piggy
cd piggy
nix develop
just build

Dependencies (pinned by the devshell): pivy (vendored at vendor/pivy/), git, a clipboard helper (xclip / wl-clipboard / pbcopy), tree, qrencode.

Note on the vendored pivy. The standalone amarbel-llc/pivy fork (forked from arekinath/pivy) is archived. All ongoing pivy work — bug fixes, new features, vendored patches — happens in this repository under vendor/pivy/. Do not open issues or send PRs against the archived fork; file them here against vendor/pivy/... instead. The vendored tree is the canonical source.

Usage

The user-facing CLI is piggy <subcommand>. piggy --help prints the full subcommand list. There are three groups:

  • Pass-style (init, show, insert, edit, generate, rm, mv, cp, find, grep, git) — same surface as passwordstore.org.
  • First-party Rust (box) — a pivy-box reimplementation whose decrypt carries a direct-PCSC ECDH oracle, so it unseals against a local card with no agent (#57); box subcommands it doesn't handle fall back to C. (agent currently execs the C pivy-agent.)
  • Store-keyed volumes (luks format|open|add-key|close) — a store entry's first line is the passphrase handed to cryptsetup; see piggy(1).
  • C pivy-* shortcut (tool) and the generic piggy pivy <tool> escape hatch — forwarded to the corresponding pivy-* C binary (piggy pivy box reaches C pivy-box even though piggy box runs the Rust impl).

See the manpages in doc/ for the full command reference and the PIGGY_* environment-variable knobs.

The pass-style handlers and piggy box (stream encrypt/decrypt, tpl create/show) are implemented natively in Rust under crates/piggy/src/; box decrypt carries a direct-PCSC ECDH oracle, so it unseals against a local card with no agent (#57). The C pivy-* family is shelled to for the tool passthrough and any box subcommand the Rust impl doesn't handle (e.g. tpl edit); both are transitional (see docs/plans/2026-09-14-retire-c-pivy-rust-nix-migration.md).

A more complete walkthrough is tracked at #25.

History

piggy started as a fork of passwordstore.org and replaced the GPG encryption path with pivy-box. See COPYING for the original GPL-2.0+ license retained from pass.