8.3 KiB
fleet-dotfiles-template
A chezmoi-based dotfiles template for syncing Claude Code, shell, git, SSH, and per-machine secrets across a fleet of macOS workstations. Auto-commits any change you make on one machine, propagates it to the others within ~7 minutes, and keeps a unioned view of Claude Code task-duration stats across the whole fleet.
The repo is a template — fork it, replace the example files in examples/ with your own real config, and you have a working fleet sync without writing the plumbing yourself.
What you get
Two-way sync of ~/.claude/, shell, git, SSH config |
A launchd watcher commits + pushes changes the moment you save; a 5-minute puller applies incoming updates from peers. |
| Encrypted secrets | One file (secrets.env) holds every API token; age-encrypted at rest, decrypted on apply. |
| Mesh SSH | A modify_ script appends every fleet pubkey to each machine's authorized_keys automatically — any machine can SSH any other. |
| Cross-fleet time estimates | Bundled Claude Code Stop hook + pull-fleet.sh produce a Hive-partitioned parquet tree. estimate.sh --fleet queries the union for grounded p50/p90/p99 task durations. |
| Pre-built Claude Code agents | The full 11-agent agentic team (Architect, Builder, Critic, Designer, Explorer, Integrator, Requirements Analyst, Research Scout, Reviewer, Scope Negotiator, Tester) and two slash commands (/lite, /lite-sub). |
| Verify-before-claiming hook | Catches hedging language ("likely", "could be", "might") missing an [unverified] tag and prompts a revision before turn end. |
Requirements
- macOS (the launchd plists are macOS-specific; everything else is portable)
chezmoi(brew install chezmoi)agefor secret encryption (brew install age)duckdbfor task-durations queries (brew install duckdb)- Git with SSH key access to your forge (GitHub, Gitea, etc.)
Quickstart
The full walkthrough is in docs/setup-new-fleet.md. The short version:
# 1. Fork this repo on your forge of choice (gitea / github / forgejo)
# 2. On your first machine:
brew install chezmoi age duckdb
# 3. Generate an age keypair (one for the whole fleet — copy to each machine via secure channel):
mkdir -p ~/.config/chezmoi
age-keygen -o ~/.config/chezmoi/key.txt
chmod 600 ~/.config/chezmoi/key.txt
# Copy the public key (printed by age-keygen) — you'll paste it into .chezmoi.toml.tmpl
# 4. Initialize chezmoi from your fork:
chezmoi init https://<your-forge>/<you>/fleet-dotfiles.git
# 5. Edit the rendered .chezmoi.toml to insert your age public key:
chezmoi edit-config
# 6. Replace the placeholder example files with your real config:
chezmoi cd
# ...edit examples/*.example, then move them into the right chezmoi paths...
# 7. Apply:
chezmoi apply
For each subsequent fleet machine, see docs/add-machine.md.
Repo layout
fleet-dotfiles-template/
├── README.md ← this file
├── LICENSE ← MIT
├── docs/
│ ├── architecture.md ← how the watcher / puller / pull-fleet pipeline works
│ ├── security.md ← age encryption boundaries, what gets encrypted vs cleartext
│ ├── setup-new-fleet.md ← bootstrap walkthrough
│ └── add-machine.md ← onboarding subsequent machines
│
├── examples/ ← replace these with your real config
│ ├── fleet.yaml.example → .chezmoidata/fleet.yaml
│ ├── secrets.env.example → ~/.config/fleet-dotfiles/secrets.env (then `chezmoi add --encrypt`)
│ ├── ssh-config.tmpl.example → private_dot_ssh/config.tmpl
│ ├── CLAUDE.md.example → dot_claude/CLAUDE.md
│ ├── zshrc.tmpl.example → dot_zshrc.tmpl
│ └── gitconfig.example → dot_gitconfig
│
├── .chezmoi.toml.tmpl ← stub asking for your age public key
├── .chezmoiexternal.toml ← public skill repos cloned by chezmoi
├── .chezmoiignore
├── .chezmoiversion
│
├── dot_local/bin/executable_chezmoi-auto-sync.sh ← the watcher script
│
├── private_Library/LaunchAgents/ ← chezmoi-templated launchd jobs
│ ├── com.chezmoi.claude-watcher.plist.tmpl ← fires on file change
│ ├── com.chezmoi.claude-puller.plist.tmpl ← runs every 5 min, pulls updates
│ └── com.taskdurations.pull-fleet.plist.tmpl ← runs every 5 min, mesh-rsyncs task-durations parquets
│
├── run_onchange_after_reload-launchd-agents.sh.tmpl ← reloads launchd whenever a plist changes
│
├── private_dot_ssh/
│ └── modify_private_authorized_keys.tmpl ← appends every fleet pubkey to authorized_keys
│
└── dot_claude/ ← Claude Code config
├── agents/agentic-team/ ← 11 specialized agents + shared principles + team.md
├── commands/
│ ├── lite.md ← /lite — Agent Teams parallel scout/explorer/critic/tester
│ └── lite-sub.md ← /lite-sub — same roles via plain subagents pinned to Opus
├── hooks/
│ ├── executable_verify-before-claiming.py ← Stop hook flagging unverified hedges
│ └── executable_validate-path.js ← PreToolUse hook enforcing project boundary (uses $PROJECT_PATH)
└── executable_statusline-command.sh ← user@host /path | Model | ctx:N% | rate-limit pacer
Fleet aggregation for time estimates
The bundled task-durations system gives you cross-machine p50/p90/p99 task durations grounded in your real Claude Code transcripts. It's referenced by the ~/.claude/scripts/task-durations/ paths in the watcher script and the launchd plists, but the scripts themselves live in a separate public repo (so they can evolve independently of this template):
Upstream: https://gitea.tojo.team/cardinale/task-durations
To install on a fleet machine:
mkdir -p ~/.claude/scripts
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 # initial corpus build
Architecture writeup is in task-durations' own docs/.
References
The plumbing this template builds on:
- chezmoi — dotfile manager. Source: twpayne/chezmoi. Reference docs: reference, quick start, user guide.
- age — file encryption used for the secrets file and SSH keys in the chezmoi source.
- DuckDB — analytics engine for the optional task-durations feature (Hive partitioning docs).
- launchd — macOS service manager that runs the watcher + puller + pull-fleet jobs. Apple's reference: launchd.plist(5).
- Companion repo: task-durations — the cross-fleet time estimator referenced from the launchd plist and Stop hook.
License
MIT — see LICENSE.