# 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`, `-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:////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 and ) # 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).