Add guard rails for several agents working on the repo at once

Deploys from unpushed branches were being reverted by the next deploy
from main, and in-place vault edits could overwrite each other.

- deploy-guard.yml (imported by site.yml and dns.yml) refuses real runs
  unless the checkout is clean and exactly origin/main; --check is fine.
- bin/deploy holds a lock so only one deploy runs at a time.
- bin/vault-run edits the vault under a lock with an atomic swap.
- bin/worktree starts a task in a fresh worktree from origin/main.
- CLAUDE.md explains the workflow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Phil
2026-10-31 09:29:41 -06:00
co-authored by Claude Opus 5.5
parent 9363bc24d5
commit 0875389d02
8 changed files with 149 additions and 0 deletions
+31
View File
@@ -8,6 +8,37 @@ This is a personal infrastructure Ansible playbook that automates deployment and
**Important**: Always review `DEPLOYMENT_LEARNINGS.md` when working on this repository for lessons learned and troubleshooting guidance.
## Working alongside other agents (read first)
Several agents change this repo and deploy to the same server at once. Two
things went wrong before these rules: a deploy from an unpushed branch was
silently reverted by the next deploy from main, and vault edits overwrote each
other. Follow these steps:
1. **Never edit the main checkout.** Start each task in its own worktree:
`bin/worktree <branch-name>` (based on the latest origin/main, with the
vault files linked in).
2. **Land on main before deploying.** Commit, `git fetch && git rebase
origin/main`, `git push origin HEAD:main`, then deploy that exact commit.
`deploy-guard.yml` (imported by site.yml and dns.yml) refuses real runs from
a checkout that is dirty or isn't origin/main. `--check` runs are always
allowed; `-e allow_unpushed=true` is for emergencies only, and the fix must
be pushed straight after.
3. **Deploy with `bin/deploy`**, not ansible-playbook directly. It holds a lock
so only one deploy runs at a time (`bin/deploy --tags <service>`;
`PLAYBOOK=dns.yml bin/deploy` for DNS). Use the narrowest tag that covers
your change.
4. **Edit the vault only with `bin/vault-run <command>`.** It locks, backs up,
decrypts to a private temp file passed as `$VAULT_PLAIN`, checks the YAML,
re-encrypts and swaps it in at once. Never `ansible-vault edit`, and don't
decrypt vault.yml in place.
5. **Check the live result after deploying** (e.g. `docker inspect`, a login
test). If someone else's deploy undid yours, rebase, push, and redeploy
rather than deploying an older checkout.
6. **Shared files** (Caddyfile.j2, domains.yml, dns.yml, main.yml task lists)
are touched by everyone: keep edits small, rebase just before pushing, and
resolve conflicts by keeping both sides.
## Common Commands
### Initial Setup