Files

227 lines
11 KiB
Markdown

# 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](https://www.chezmoi.io)** — overview, install, quick start.
- **[chezmoi command reference](https://www.chezmoi.io/reference/commands/)** — every subcommand (`init`, `add`, `apply`, `diff`, `update`, `re-add`, `edit-config`, `cd`, `source-path`, `execute-template`).
- **[chezmoi templates](https://www.chezmoi.io/reference/templates/)** — the `{{ .chezmoi.homeDir }}` and `{{ .chezmoi.hostname }}` syntax used throughout this template.
- **[chezmoi encryption](https://www.chezmoi.io/user-guide/encryption/age/)** — how `chezmoi add --encrypt` works with age.
- **[age homepage](https://github.com/FiloSottile/age)** — keypair format, `age-keygen`, `age` and `age -d` commands.
- **[Apple launchd guide](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html)** — 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`](https://gitea.tojo.team/cardinale/task-durations) (separate; install instructions in this template's README).
## 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 <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:
```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 `<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.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://<forge>/<user>/<repo>.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.