Secrets
Secrets
private/ works exactly like autolink/ (same layers, same
linking rules, except it never folds), but git only ever sees
encrypted *.age files.
| File | Committed? | What it is |
|---|---|---|
private/common/netrc |
never | plaintext, linked to ~/.netrc |
private/common/netrc.age |
yes | the same, encrypted with age |
private/recipients.txt |
yes | public key: anything can seal without a passphrase |
private/identity.age |
yes | private key, encrypted with your passphrase; needed only to unlock |
There is no recovery. Keep the passphrase in the password manager.
Commands
homebot keys init # once, ever: make the key pair, pick a passphrase
homebot pack ~/.netrc --private # move a secret in, seal it, link it back
homebot unlock # decrypt everything (passphrase asked once)
homebot lock # seal what changed; --wipe also deletes plaintext
Sealing is automatic: the commit guard and the hourly helper encrypt changed
plaintext on their own, because sealing needs only the public key.
You never encrypt by hand. Edit the plaintext (it is what ~/.netrc links
to); private/.gitignore keeps git from ever seeing it. The next commit,
whether homebot save, the autosave or a plain git commit, seals it into the
.age file next to it and commits that. The guard’s refusal of plaintext
(step 2 below) is only a safety net for a file force-added with git add -f.
Two machines, one secret
Each machine keeps hashes of what it last sealed or unlocked, so homebot knows
where a change came from.
| State | Means | Fix |
|---|---|---|
new / modified |
plaintext changed here | sealed automatically |
locked |
.age exists, no plaintext here yet |
homebot unlock |
upstream |
.age changed on another machine |
homebot unlock |
conflict |
changed here and elsewhere | homebot unlock --theirs or homebot lock --ours |
A pull never silently overwrites a local edit; conflicts land in the inbox as urgent.
The commit guard
homebot setup points core.hooksPath at homebot/hooks. Before every commit it:
- Seals changed secrets and stages the
.agefiles. - Refuses plaintext from
private/, even if force-added (git add -f). - Refuses any file over
limits.maxFileMB(50 MB; GitHub hard-fails at 100). - Refuses anything
gitleaksflags in the staged changes. - Refuses everything if
gitleaksisn’t installed. No scanner, no commit.
The hook prefers bun homebot/src/cli.ts from the repo, so the guard always
matches the checked-out tool. A refused automatic commit becomes an urgent
inbox item with the reason.
git commit --no-verify works, and is exactly how secrets end up on GitHub.
If the guard is wrong, fix the guard.