136 lines
8.3 KiB
Markdown
136 lines
8.3 KiB
Markdown
# 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`](https://www.chezmoi.io) (`brew install chezmoi`)
|
|
- [`age`](https://github.com/FiloSottile/age) for secret encryption (`brew install age`)
|
|
- [`duckdb`](https://duckdb.org/) for 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`](docs/setup-new-fleet.md). The short version:
|
|
|
|
```bash
|
|
# 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`](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:
|
|
|
|
```bash
|
|
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/](https://gitea.tojo.team/cardinale/task-durations/src/branch/main/docs/fleet-architecture.md).
|
|
|
|
## References
|
|
|
|
The plumbing this template builds on:
|
|
|
|
- **[chezmoi](https://www.chezmoi.io)** — dotfile manager. Source: [twpayne/chezmoi](https://github.com/twpayne/chezmoi). Reference docs: [reference](https://www.chezmoi.io/reference/), [quick start](https://www.chezmoi.io/quick-start/), [user guide](https://www.chezmoi.io/user-guide/command-overview/).
|
|
- **[age](https://github.com/FiloSottile/age)** — file encryption used for the secrets file and SSH keys in the chezmoi source.
|
|
- **[DuckDB](https://duckdb.org/)** — analytics engine for the optional task-durations feature ([Hive partitioning docs](https://duckdb.org/docs/stable/data/partitioning/hive_partitioning)).
|
|
- **[launchd](https://www.launchd.info/)** — macOS service manager that runs the watcher + puller + pull-fleet jobs. Apple's reference: [launchd.plist(5)](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html).
|
|
- **Companion repo:** [task-durations](https://gitea.tojo.team/cardinale/task-durations) — the cross-fleet time estimator referenced from the launchd plist and Stop hook.
|
|
|
|
## License
|
|
|
|
MIT — see [LICENSE](LICENSE).
|