Initial public release
A chezmoi-based fleet-dotfiles template for macOS workstations: - Two-way auto-sync via launchd watcher + 5-min puller - Mesh SSH via modify_authorized_keys driven by .chezmoidata/fleet.yaml - age-encrypted secrets file - Bundled Claude Code agentic team (11 agents) + /lite + /lite-sub commands - Verify-before-claiming Stop hook - Generic statusline + project-boundary validate-path hook - Reference launchd plist for cross-fleet task-durations aggregation (companion repo: gitea.tojo.team/cardinale/task-durations) - AGENTS.md walks an agent through the entire setup Q&A interactively - docs/ covers architecture, security model, fleet onboarding
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# Onboarding an additional fleet machine
|
||||
|
||||
Once your first machine is set up (see [`setup-new-fleet.md`](setup-new-fleet.md)), each subsequent machine joins via this much shorter flow.
|
||||
|
||||
## On the existing fleet (any one machine)
|
||||
|
||||
Add the new machine's eventual hostname + user to `.chezmoidata/fleet.yaml`. The pubkey can be a placeholder for now — you'll fill in the real one after the new machine generates its identity key.
|
||||
|
||||
```yaml
|
||||
fleet:
|
||||
# ... existing entries ...
|
||||
newmachine:
|
||||
user: alice
|
||||
pubkey: "PLACEHOLDER_WILL_FILL_IN_AFTER_NEW_MACHINE_RUNS_KEYGEN"
|
||||
```
|
||||
|
||||
Save. The watcher commits + pushes within ~10 seconds.
|
||||
|
||||
## On the new machine
|
||||
|
||||
### 1. Prerequisites
|
||||
|
||||
```bash
|
||||
brew install chezmoi age duckdb
|
||||
```
|
||||
|
||||
### 2. Get the age private key
|
||||
|
||||
The new machine needs the SAME age private key as every other fleet machine. Copy it from an existing machine via:
|
||||
|
||||
- Encrypted USB drive
|
||||
- Password manager attachment
|
||||
- 1Password Secure Notes
|
||||
- Encrypted message (Signal, iMessage, etc.)
|
||||
|
||||
Place at `~/.config/chezmoi/key.txt` and `chmod 600` it.
|
||||
|
||||
**Do NOT** use plain email, Slack, or any cloud sync that decrypts at rest.
|
||||
|
||||
### 3. Initialize chezmoi from the fleet's forge
|
||||
|
||||
```bash
|
||||
chezmoi init https://<forge>/<you>/fleet-dotfiles.git
|
||||
chezmoi apply
|
||||
```
|
||||
|
||||
`chezmoi apply` will:
|
||||
|
||||
- Decrypt `secrets.env` and write it to `~/.config/fleet-dotfiles/`.
|
||||
- Render the launchd plists with this machine's `$HOME`, write them to `~/Library/LaunchAgents/`.
|
||||
- Run the `run_onchange` script which loads the watcher, puller, and pull-fleet daemons.
|
||||
- Run the `modify_authorized_keys` script which appends every existing fleet machine's pubkey to `~/.ssh/authorized_keys`.
|
||||
|
||||
### 4. Generate this machine's identity SSH key
|
||||
|
||||
```bash
|
||||
[ -f ~/.ssh/id_ed25519 ] || ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
|
||||
cat ~/.ssh/id_ed25519.pub
|
||||
```
|
||||
|
||||
Copy that pubkey.
|
||||
|
||||
### 5. Update fleet.yaml with the real pubkey
|
||||
|
||||
```bash
|
||||
chezmoi edit .chezmoidata/fleet.yaml
|
||||
```
|
||||
|
||||
Replace the placeholder you set in step 0 with the real pubkey.
|
||||
|
||||
```bash
|
||||
chezmoi apply
|
||||
```
|
||||
|
||||
The watcher fires, commits the change, pushes it. Within ~7 minutes, every existing fleet machine pulls the update and adds the new pubkey to its `authorized_keys`.
|
||||
|
||||
### 6. Verify mesh SSH
|
||||
|
||||
From the new machine, try SSHing into one of the existing peers:
|
||||
|
||||
```bash
|
||||
ssh <existing-peer-hostname> 'echo OK from $(hostname -s)'
|
||||
```
|
||||
|
||||
If it returns `OK from <peer>`, mesh is working. If it prompts for a password or rejects, wait a few minutes (the puller hasn't fanned out the new pubkey yet) or run `chezmoi update --force` on the peer manually.
|
||||
|
||||
### 7. Install task-durations (optional)
|
||||
|
||||
```bash
|
||||
git clone https://gitea.tojo.team/cardinale/task-durations.git ~/.claude/scripts/task-durations
|
||||
chmod +x ~/.claude/scripts/task-durations/*.{py,sh}
|
||||
python3 ~/.claude/scripts/task-durations/extract.py
|
||||
```
|
||||
|
||||
The pull-fleet launchd job (already registered by step 3) will start mesh-rsyncing peers' parquets on the next 5-minute tick.
|
||||
|
||||
### 8. Confirm
|
||||
|
||||
```bash
|
||||
launchctl list | grep -E "chezmoi|taskdurations"
|
||||
chezmoi diff # should be empty (everything in sync)
|
||||
```
|
||||
|
||||
You're done.
|
||||
|
||||
## Removing a machine
|
||||
|
||||
If a machine is decommissioned or lost:
|
||||
|
||||
1. On any remaining machine, edit `.chezmoidata/fleet.yaml` to delete the entry.
|
||||
2. `chezmoi apply` (or just save — watcher will fire).
|
||||
3. Every remaining peer will, on next apply, NOT re-add that pubkey to its `authorized_keys`. **Note:** existing entries are NOT removed by the `modify_` script — you'll need to manually `ssh-keygen -R` or hand-edit `~/.ssh/authorized_keys` to remove the line.
|
||||
4. Rotate any secrets the lost machine had access to (since it could have copied the unencrypted `~/.config/fleet-dotfiles/secrets.env` to disk).
|
||||
Reference in New Issue
Block a user