Committed, encrypted credentials for the BigConfig package. Secrets live in git as
age-encrypted files and are decrypted into your shell
automatically on direnv load — using a private identity file you keep locally and never
commit. No plaintext ever touches disk.
Two shared team keypairs gate access:
| File | Encrypted to | Holds |
|---|---|---|
.credentials/read-only.age |
team-ro and team-rw |
limited-scope credentials |
.credentials/read-write.age |
team-rw only |
full-scope credentials |
Both files export the same variable names (Cloudflare / R2 / Resend). .envrc sources the
read-only file first and the read-write file second, so:
- A read-only developer (holds the
team-roidentity) decrypts onlyread-only.age. - A read-write developer (holds the
team-rwidentity) decrypts both, and the read-write values win.
Everything lives under .credentials/; only .envrc and .gitignore sit at the project root.
age—brew install agedirenv—brew install direnv, then hook it into your shell
-
Obtain your team identity file from whoever provisions keys (RO devs get
team-ro, RW devs getteam-rw). It is a private key — never commit or share it. -
Place it at
.credentials/team-rw-identity.txt(the default the loader looks for), or put it anywhere and pointAGE_IDENTITYat it. -
Allow direnv in this directory:
direnv allow
Your secrets are now exported whenever you cd into this directory.
Create a gitignored .envrc.private that exports the override:
# .envrc.private (never committed)
export AGE_IDENTITY="$HOME/.config/bigconfig/age-identity.txt"Never edit .age files directly — decrypt, edit the plaintext, re-seal, and delete the scratch:
# decrypt to a gitignored *.plain scratch file
age -d -i .credentials/team-rw-identity.txt .credentials/read-write.age > .credentials/read-write.plain
# edit .credentials/read-write.plain ...
# re-seal (rw -> team-rw only; ro -> team-ro + team-rw)
.credentials/seal .credentials/read-write.plain rw
# remove the plaintext
rm .credentials/read-write.plainseal reads the public recipient keys from .credentials/recipients.txt. After re-sealing, run
direnv reload (or re-enter the directory) to pick up the new values.
| Committed | Local only (gitignored) |
|---|---|
.envrc, .credentials/{read-only,read-write}.age, .credentials/recipients.txt, .credentials/seal |
.envrc.private, *identity* (private keys), *.plain (scratch) |
recipients.txt holds public keys only and is safe to commit. Identity files and *.plain
scratch files are secrets — the .gitignore keeps them out, but treat them as sensitive regardless.
age-keygen -o .credentials/team-ro-identity.txt # record its public key as `team-ro` in recipients.txt
age-keygen -o .credentials/team-rw-identity.txt # record its public key as `team-rw`Distribute identity files out of band: RO devs get team-ro; RW devs get team-rw (which already
opens the RO file too).
The keypairs and
.agepayloads currently in the repo are dev/test placeholders — regenerate them and re-seal with real secrets before any real use.
See plan.md for the full design rationale.