Problem
Local config drifts. Teams pass .env files around in DMs and password managers, someone edits a value, and now three machines disagree about the truth. The obvious fix — commit the file — is a trap: a plaintext secret committed once lives in git history forever. I wanted config to travel with the repository, safely, so that git clone was the entire onboarding step.
What I built
A CLI that encrypts .env to every developer's age/SSH public key and commits the ciphertext. Access is a reviewable recipients.toml — adding or removing a teammate is a normal pull request. Around that core it ships git hooks, semantic diff and merge drivers, a revoke command with a rotation ledger, and integrity checks for CI.
Architecture / system design
Three questions decide everything the tool does, and each is answered by one file: who can decrypt? (the recipient set), what is the secret? (the encrypted bytes), and is it authentic and current? (a detached signature plus a lock). Sealing is idempotent, and every state change is planned before it is written.
Failure modes / what broke
The load-bearing realization: age gives you confidentiality, not authorship. Because the recipients file is public, anyone can craft ciphertext that decrypts for the whole team — so decrypting a file proves nothing about who wrote it. That gap, plus a path-traversal hole in an early build, drove most of the hardening work.
Proof / tests
Every source file has a test sibling, plus a fuzz suite and a differential .env parser suite run against joho/godotenv. A custom coverage gate fails CI below 85% on the crypto-sensitive packages and 80% for the repository. Eight architecture decision records document the trade-offs; cross-platform binaries ship through GoReleaser.
Lessons learned
The cryptography was the easy part — age handles it. The hard part is naming trust boundaries and refusing to blur them: confidentiality is not authorship, revocation is not rotation, and no ownership change is safe until it is atomic and reviewable.