# AGENTS.md — agent-led setup instructions > **For Claude Code, Codex, Aider, or any other coding agent dropped into this repo.** > Follow this file top-to-bottom. It walks the user through replacing every placeholder with real values. Treat each numbered section as one Q&A round: ask the listed questions, wait for answers, fill in the files, then move on. ## Operating rules for this setup session 1. **One question at a time.** Don't fire all questions in a giant wall of text. Ask one, wait for the answer, ask the next. 2. **Confirm before destructive actions.** Generating a new SSH keypair, generating a new age keypair, force-pushing — always confirm. Show what you're about to do; let the user say yes/no. 3. **Never paste secrets back to the user in plaintext.** When the user gives you an API token, treat it like radioactive material: write it to the right file, then forget it. Don't echo it in a status message, don't put it in a commit, don't show it in a `cat` of the file. 4. **Fail loud on missing prerequisites.** If `chezmoi`, `age`, or `duckdb` isn't installed, stop and tell the user the brew command. Don't try to proceed. 5. **Verify before claiming.** When a step is "done", run a check that proves it: a `chezmoi diff`, a file existence test, a token round-trip. Tell the user what you verified. 6. **Don't commit secrets.** Verify with `git status` before any commit that no `.env`, no unencrypted secret, no SSH private key is staged. If chezmoi's autoCommit fires, double-check the diff. ## Section 0 — Prerequisites check Run silently, only surface findings to the user: ```bash command -v chezmoi >/dev/null && chezmoi --version command -v age >/dev/null && age --version command -v age-keygen >/dev/null command -v duckdb >/dev/null && duckdb --version command -v git >/dev/null && git --version ``` If any are missing, tell the user the install command (`brew install chezmoi age duckdb`) and stop until they confirm. ## Section 1 — Identify the user Ask: > **Q1:** What name and email should I use for git commits on this fleet? > (e.g., `Alice Smith `) Take their answer and write to `dot_gitconfig` (replacing the `examples/gitconfig.example` placeholders). Don't render the file yet — just stage the chezmoi source. ## Section 2 — Generate or reuse the age keypair Ask: > **Q2:** Do you already have an age keypair you want to use for this fleet? (yes / no) > > If **yes**: where is the private key file? (default: `~/.config/chezmoi/key.txt`) > If **no**: I'll generate a new one. Confirm before I create the file. If generating new: ```bash mkdir -p ~/.config/chezmoi age-keygen -o ~/.config/chezmoi/key.txt chmod 600 ~/.config/chezmoi/key.txt ``` Then extract the public key (it's printed to stderr by `age-keygen`, and on the first commented line of the file). Show ONLY the public key to the user. Edit `.chezmoi.toml.tmpl`: replace `REPLACE_ME_WITH_YOUR_AGE_PUBLIC_KEY` with the public key. > **Verify:** `chezmoi execute-template '{{ (index .age "recipient") }}'` should print the new public key. ## Section 3 — Identify this machine and the fleet Ask: > **Q3:** What's the hostname of this machine? (run `hostname -s` if you need a default) > > **Q4:** What's the username on this machine? (run `whoami` for the default) > > **Q5:** How many other machines will be in this fleet, and what are their hostnames + usernames? Generate this machine's identity SSH key if missing: ```bash [ -f ~/.ssh/id_ed25519 ] || ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" ``` Read the public key from `~/.ssh/id_ed25519.pub` and capture it. Build `.chezmoidata/fleet.yaml` from `.chezmoidata/fleet.yaml.example`, replacing the placeholder entries with the machines the user named. For now, leave the OTHER machines' pubkeys as placeholders — they'll get filled in when those machines run their own onboarding (Section 9 covers this). ## Section 4 — SSH config for the fleet Use `examples/ssh-config.tmpl.example` as a starting point. Render it for this fleet by: - Replacing `laptop1` / `laptop2` / `desktop` placeholders with the real hostnames from Q5. - Replacing `` with the real usernames from Q5. Save to `private_dot_ssh/config.tmpl` in the chezmoi source. > **Verify:** `chezmoi execute-template < private_dot_ssh/config.tmpl` renders cleanly with no `{{` literals leaking through. ## Section 5 — Decide on a forge Ask: > **Q6:** Where will this fleet's git remote live? (gitea, github, forgejo, gitlab, self-hosted bare repo) > If on a service that requires auth, how do you authenticate? (SSH key in agent, HTTPS PAT in keychain, gh CLI, etc.) Verify the user can `git push` to that forge from this machine. If they're on a private gitea (like `gitea.tojo.team`), confirm they have a PAT in their environment or a credential helper configured. ## Section 6 — Secrets Ask: > **Q7:** Which API tokens do you want to manage via the fleet's encrypted secrets file? > The default list (in `examples/secrets.env.example`) covers Cloudflare, Porkbun, Tailscale, HuggingFace, OpenAI/Anthropic/Gemini, and the forge token. You can add or remove freely. For each token the user wants: - Ask for it ONE AT A TIME. - Append it to a temp file at `~/.config/fleet-dotfiles/secrets.env` (create the dir + chmod 600 the file FIRST). - Don't echo the value. When all tokens are entered: ```bash chmod 600 ~/.config/fleet-dotfiles/secrets.env chezmoi add --encrypt ~/.config/fleet-dotfiles/secrets.env ``` > **Verify:** `ls $(chezmoi source-path)/dot_config/private_fleet-dotfiles/` should now show `encrypted_private_secrets.env.age` (the encrypted source file). The original `~/.config/fleet-dotfiles/secrets.env` stays unencrypted on disk for runtime use; never commit it directly. > **Sanity check:** `git status` in the chezmoi source dir must NOT show any unencrypted secret file staged. ## Section 7 — CLAUDE.md Ask: > **Q8:** I've copied a generic CLAUDE.md skeleton from `examples/CLAUDE.md.example` to `dot_claude/CLAUDE.md`. Do you want me to add machine-specific or project-specific sections on top? (e.g., your servers, your common commands, your workflow rules) If yes, ask what sections, write them. If no, leave the skeleton — they can add later. > **Verify:** `chezmoi diff dot_claude/CLAUDE.md` shows the file ready to apply. ## Section 8 — First apply Show the user `chezmoi diff --no-pager` summary (file count + paths, NOT contents — the diff might leak secret-shaped strings). Confirm: > **Q9:** Ready to materialize all of this to the live filesystem? (yes / no) On yes: ```bash chezmoi apply ``` Then verify the launchd jobs registered: ```bash launchctl list | grep -E "chezmoi|taskdurations" ``` You should see three labels: - `com.chezmoi.claude-watcher` - `com.chezmoi.claude-puller` - `com.taskdurations.pull-fleet` If any are missing, tell the user to run `chezmoi apply --force ~/Library/LaunchAgents/` and reload manually: ```bash for plist in ~/Library/LaunchAgents/com.{chezmoi,taskdurations}.*.plist; do launchctl unload "$plist" 2>/dev/null launchctl load "$plist" done ``` ## Section 9 — Push to the forge Initial commit + push: ```bash cd $(chezmoi source-path) git remote -v # confirm it points at the user's forge 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 ``` > **Final verify:** Open the forge URL in a browser. Confirm `examples/`, `dot_local/bin/...`, `private_Library/LaunchAgents/...` are all present. Confirm `dot_config/private_fleet-dotfiles/encrypted_private_secrets.env.age` is the encrypted form (`.age` extension), not a plaintext `.env`. ## Section 10 — Onboarding additional machines Tell the user: > Each additional fleet machine repeats Sections 0, 2 (reuse the SAME age private key — copy it via secure channel; do NOT push it to git), 3 (generate that machine's identity SSH key), and then runs `chezmoi init https:////.git` and `chezmoi apply`. > > The age public key in `.chezmoi.toml.tmpl` doesn't need changing — it's the same recipient for the whole fleet. > > After the new machine applies, edit `.chezmoidata/fleet.yaml` to add its real pubkey. The watcher commits the change; within 7 min, every other fleet machine has it in `authorized_keys`. Walk them through the first additional machine if they're available. ## Done — what to leave the user with - A running fleet sync on this machine. - A `~/.local/bin/chezmoi-auto-sync.sh` that the watcher will call on every change to a managed path. - A `~/.config/fleet-dotfiles/secrets.env` (cleartext on disk, encrypted in source) sourced by `.zshrc` on shell start. - The full Claude Code agentic team available at `~/.claude/agents/agentic-team/`, plus `/lite` and `/lite-sub` slash commands. - A pointer to the task-durations repo (separate) if they want fleet-wide time estimates. - A note that any subsequent machine they want to add: see [`docs/add-machine.md`](docs/add-machine.md). ## What to NEVER do during this setup - Never echo a secret back to the user in plaintext (not in chat, not in a log, not in a commit message). - Never run `git push --force` without explicit user confirmation. - Never delete the user's existing `~/.ssh/id_ed25519` if they already have one — work with what's there. - Never commit `~/.config/chezmoi/key.txt` (it's the age private key — losing it locks them out of every encrypted file in the repo). - Never overwrite `~/.zshrc` without showing a diff first; users often have hand-tuned aliases there. - Never assume the user wants every example file — confirm each section before applying.