ebccdda936
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
162 lines
5.1 KiB
Markdown
162 lines
5.1 KiB
Markdown
# Setup — first machine of a new fleet
|
|
|
|
If you'd rather have an agent (Claude Code, Codex, etc.) walk you through this interactively, point the agent at this repo and tell it to follow [`AGENTS.md`](../AGENTS.md). The instructions below are the same flow, written for a human to follow directly.
|
|
|
|
## Prerequisites
|
|
|
|
```bash
|
|
brew install chezmoi age duckdb
|
|
```
|
|
|
|
You need git access to whichever forge you'll host the fleet repo on (gitea, GitHub, forgejo, gitlab — anything chezmoi can clone over HTTPS or SSH).
|
|
|
|
## 1. Fork this template
|
|
|
|
Fork `fleet-dotfiles-template` to your forge:
|
|
|
|
- **Gitea:** `https://gitea.tojo.team/cardinale/fleet-dotfiles-template` → click Fork.
|
|
- **GitHub:** if mirrored there, fork it.
|
|
- **Other forges:** clone, push to a new repo on your forge.
|
|
|
|
Name the fork however you want (`my-fleet-dotfiles`, `<your-handle>-dotfiles`, etc.). The rest of this doc assumes you've named it `fleet-dotfiles` on your forge.
|
|
|
|
## 2. Generate an age keypair (one for the whole fleet)
|
|
|
|
This keypair encrypts the secrets file. The private key never touches the forge. Every machine in the fleet gets a copy of it via secure side-channel.
|
|
|
|
```bash
|
|
mkdir -p ~/.config/chezmoi
|
|
age-keygen -o ~/.config/chezmoi/key.txt
|
|
chmod 600 ~/.config/chezmoi/key.txt
|
|
```
|
|
|
|
`age-keygen` prints the public key to stderr and writes it as the first commented line of `key.txt` prefixed with `# public key: `. Capture it — you'll paste it into the chezmoi config in the next step.
|
|
|
|
## 3. Initialize chezmoi from your fork
|
|
|
|
```bash
|
|
chezmoi init https://<forge>/<you>/fleet-dotfiles.git
|
|
```
|
|
|
|
This clones the fork to `~/.local/share/chezmoi/` and runs the template prompts. When it asks for the age recipient, paste the public key you captured.
|
|
|
|
If you missed the prompt, run `chezmoi edit-config` and replace `REPLACE_ME_WITH_YOUR_AGE_PUBLIC_KEY` in the rendered config.
|
|
|
|
## 4. Replace placeholders with your real config
|
|
|
|
The example files live in `examples/`. Move and edit them into the chezmoi source layout:
|
|
|
|
```bash
|
|
chezmoi cd
|
|
|
|
# Fleet roster
|
|
mv examples/fleet.yaml.example .chezmoidata/fleet.yaml
|
|
$EDITOR .chezmoidata/fleet.yaml
|
|
# (replace placeholder hostnames, users, pubkeys; for now you only need this machine's pubkey)
|
|
|
|
# Git identity
|
|
mv examples/gitconfig.example dot_gitconfig
|
|
$EDITOR dot_gitconfig
|
|
# (replace <YOUR_EMAIL> and <YOUR_NAME>)
|
|
|
|
# SSH config (templated)
|
|
mv examples/ssh-config.tmpl.example private_dot_ssh/config.tmpl
|
|
$EDITOR private_dot_ssh/config.tmpl
|
|
# (replace placeholder hostnames + usernames with your real fleet)
|
|
|
|
# Shell config (templated)
|
|
mv examples/zshrc.tmpl.example dot_zshrc.tmpl
|
|
$EDITOR dot_zshrc.tmpl
|
|
# (add your own PATH, aliases, completions; keep the secrets.env source line)
|
|
|
|
# Claude Code top-level instructions
|
|
mv examples/CLAUDE.md.example dot_claude/CLAUDE.md
|
|
$EDITOR dot_claude/CLAUDE.md
|
|
# (add personal sections if you want; the template only carries fleet-relevant ones)
|
|
```
|
|
|
|
## 5. Generate this machine's identity SSH key
|
|
|
|
If `~/.ssh/id_ed25519` doesn't exist:
|
|
|
|
```bash
|
|
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
|
|
```
|
|
|
|
Then add this machine's pubkey to `.chezmoidata/fleet.yaml`:
|
|
|
|
```bash
|
|
PUBKEY=$(cat ~/.ssh/id_ed25519.pub)
|
|
echo "Add this to .chezmoidata/fleet.yaml under your machine's entry:"
|
|
echo " pubkey: \"$PUBKEY\""
|
|
```
|
|
|
|
## 6. Set up encrypted secrets
|
|
|
|
```bash
|
|
mkdir -p ~/.config/fleet-dotfiles
|
|
cp $(chezmoi source-path)/examples/secrets.env.example ~/.config/fleet-dotfiles/secrets.env
|
|
chmod 600 ~/.config/fleet-dotfiles/secrets.env
|
|
$EDITOR ~/.config/fleet-dotfiles/secrets.env
|
|
# (fill in real values for tokens you actually use; delete the rest)
|
|
|
|
# Encrypt + add to chezmoi source:
|
|
chezmoi add --encrypt ~/.config/fleet-dotfiles/secrets.env
|
|
```
|
|
|
|
Verify:
|
|
|
|
```bash
|
|
ls $(chezmoi source-path)/dot_config/private_fleet-dotfiles/
|
|
# Expect: encrypted_private_secrets.env.age
|
|
```
|
|
|
|
## 7. Apply
|
|
|
|
```bash
|
|
chezmoi diff # review changes
|
|
chezmoi apply # materialize them
|
|
```
|
|
|
|
Verify the launchd jobs registered:
|
|
|
|
```bash
|
|
launchctl list | grep -E "chezmoi|taskdurations"
|
|
# Expect 3 lines: claude-watcher, claude-puller, taskdurations.pull-fleet
|
|
```
|
|
|
|
If any are missing, run:
|
|
|
|
```bash
|
|
for plist in ~/Library/LaunchAgents/com.{chezmoi,taskdurations}.*.plist; do
|
|
launchctl unload "$plist" 2>/dev/null
|
|
launchctl load "$plist"
|
|
done
|
|
```
|
|
|
|
## 8. Install task-durations (optional)
|
|
|
|
If you want fleet-wide time estimates:
|
|
|
|
```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 Stop hook in your `~/.claude/settings.json` will keep the local corpus fresh; the `com.taskdurations.pull-fleet` launchd job will mesh-rsync peer parquets every 5 minutes.
|
|
|
|
## 9. Push to your forge
|
|
|
|
```bash
|
|
chezmoi cd
|
|
git status # confirm no unencrypted secrets are staged
|
|
git add -A
|
|
git commit -m "Initial fleet dotfiles for $(hostname -s)"
|
|
git push -u origin main
|
|
```
|
|
|
|
You're done. Open the forge URL and confirm the encrypted secrets file is present (`encrypted_private_secrets.env.age`, NOT `secrets.env`).
|
|
|
|
To onboard the next machine, see [`add-machine.md`](add-machine.md).
|