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,161 @@
|
||||
# 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).
|
||||
Reference in New Issue
Block a user