11 KiB
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.
Background reading you may need mid-flow
If you hit a chezmoi-specific question you can't answer from this file alone, consult the live docs:
- chezmoi homepage — overview, install, quick start.
- chezmoi command reference — every subcommand (
init,add,apply,diff,update,re-add,edit-config,cd,source-path,execute-template). - chezmoi templates — the
{{ .chezmoi.homeDir }}and{{ .chezmoi.hostname }}syntax used throughout this template. - chezmoi encryption — how
chezmoi add --encryptworks with age. - age homepage — keypair format,
age-keygen,ageandage -dcommands. - Apple launchd guide — if a plist fails to load, this is the reference for
launchctl load/unload/list.
If the user asks about cross-fleet time estimates, the companion repo is task-durations (separate; install instructions in this template's README).
Operating rules for this setup session
- 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.
- 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.
- 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
catof the file. - Fail loud on missing prerequisites. If
chezmoi,age, orduckdbisn't installed, stop and tell the user the brew command. Don't try to proceed. - 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. - Don't commit secrets. Verify with
git statusbefore 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:
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 <alice@example.com>)
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:
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 -sif you need a default)Q4: What's the username on this machine? (run
whoamifor 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:
[ -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/desktopplaceholders with the real hostnames from Q5. - Replacing
<USERNAME_FOR_*>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.tmplrenders 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:
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 showencrypted_private_secrets.env.age(the encrypted source file). The original~/.config/fleet-dotfiles/secrets.envstays unencrypted on disk for runtime use; never commit it directly.
Sanity check:
git statusin 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.exampletodot_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.mdshows 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:
chezmoi apply
Then verify the launchd jobs registered:
launchctl list | grep -E "chezmoi|taskdurations"
You should see three labels:
com.chezmoi.claude-watchercom.chezmoi.claude-pullercom.taskdurations.pull-fleet
If any are missing, tell the user to run chezmoi apply --force ~/Library/LaunchAgents/ and reload manually:
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:
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. Confirmdot_config/private_fleet-dotfiles/encrypted_private_secrets.env.ageis the encrypted form (.ageextension), 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://<forge>/<user>/<repo>.gitandchezmoi apply.The age public key in
.chezmoi.toml.tmpldoesn't need changing — it's the same recipient for the whole fleet.After the new machine applies, edit
.chezmoidata/fleet.yamlto add its real pubkey. The watcher commits the change; within 7 min, every other fleet machine has it inauthorized_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.shthat 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.zshrcon shell start. - The full Claude Code agentic team available at
~/.claude/agents/agentic-team/, plus/liteand/lite-subslash 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.
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 --forcewithout explicit user confirmation. - Never delete the user's existing
~/.ssh/id_ed25519if 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
~/.zshrcwithout showing a diff first; users often have hand-tuned aliases there. - Never assume the user wants every example file — confirm each section before applying.