.dotfiles Manual

Concepts

Fleet Architecture

A "fleet" is two or more workstations sharing a single .dotfiles source repository. The fleet model handles per-host customization, drift detection, and cross-host trust propagation.

Single Source, Many Hosts

All hosts clone the same repository. Platform and per-host differences are resolved at chezmoi apply time using three sources of data:

  1. defaults/.chezmoidata.toml — defaults for all hosts
  2. defaults/.chezmoidata/hardware.toml — the [hardware] defaults and the [machines.*] presets (macbook-t2, surface-pro, geekom-a9)
  3. ~/.config/chezmoi/chezmoi.toml — per-host overrides, generated by chezmoi init

The machine key in chezmoi.toml selects which preset applies:

# ~/.config/chezmoi/chezmoi.toml on a MacBook
[data]
machine = "macbook-t2"
theme = "tahoe-dark"

A template starts from .hardware and swaps in the preset when machine names one. This is how defaults/dot_config/niri/config.kdl.tmpl does it:

{{ $hw := .hardware -}}
{{- $machine := .machine -}}
{{- if and $machine (ne $machine "") -}}
  {{- $m := index .machines $machine -}}
  {{- if $m -}}
    {{- $hw = $m -}}
  {{- end -}}
{{- end -}}
scale {{ $hw.scale }}

Hardware Presets

defaults/.chezmoidata/hardware.toml ships three presets: macbook-t2, surface-pro and geekom-a9. Each preset, like the [hardware] defaults, sets:

Field Purpose
profile laptop or desktop
scale, hidpi Display scale (1.0 by default, 2.0 on macbook-t2, 1.5 on surface-pro) and HiDPI
touchscreen, touchpad Input devices present
touchpad_accel, touchpad_accel_profile Touchpad acceleration
max_refresh Highest refresh rate; above 60 enables variable refresh in Niri
gpu integrated or discrete
keyboard_layout XKB layout, us by default
output_name, output_mode The Niri output and its mode

Add a new preset by appending a [machines.<name>] table to hardware.toml: no code changes needed. Feature flags are not part of a preset; set them per host under [data.features].

Drift Detection

dot doctor drift show compares this machine against the source and reports four classes of drift:

Drift Type Meaning
Managed drift A deployed file differs from the rendered source (the chezmoi status lines)
Untracked source A file in the chezmoi source tree is not tracked by Git
Orphan deployed A file that chezmoi used to manage is still deployed after its source was removed
Stale source A source file is older than its deployed target: someone edited the deployed file, and the next apply would revert it

It exits 0 when every section is clean, 1 when it finds drift and 2 when chezmoi or Git is missing.

Drift is normal during development. dot apply overwrites managed drift (dot doctor fix runs chezmoi apply --force for the same purpose); dot diff previews the change without applying.

Fleet Attestation

Each host writes its own attestation record. Point every host at one shared directory to collect them:

dot attest show --fleet-store /mnt/fleet --fleet-id home
# writes /mnt/fleet/home/<hostname>/workstation-attestation.json
# plus a timestamped copy next to it

DOTFILES_FLEET_STORE and DOTFILES_FLEET_ID set the same values from the environment. There is no command that compares the records across hosts: review them side by side, or run the verifier on each (see Trust Model). The records are unsigned.

Fleet Deployment Workflow

Recommended rollout procedure for fleet-wide changes:

  1. Develop on one host — make the change, preview it with dot diff, then dot apply
  2. Open a PR — CI validates shellcheck, tests, security scanners
  3. Merge to main — signed commit required
  4. Per-host pull — on each fleet host: dot config update (pull the source and apply the dotfiles), or dot fleet apply --cmd "dot config update" from one host over SSH
  5. Verify alignment — on each host, dot fleet status (version and drift) and dot attest show --fleet-store <dir>

For urgent rollback: every host can independently run dot doctor rollback rollback to restore its most recent backup of the core dotfiles (kept in ~/.local/share/dotfiles/backups/; see Self-Healing).

Cross-Host Trust

Each host has its own SSH ED25519 signing key. To establish mutual trust:

  1. On each host: cat ~/.ssh/id_ed25519.pub — capture the public key
  2. Add every host's public key to ~/.config/git/allowed_signers (the file gpg.ssh.allowedSignersFile points at) on every other host
  3. Keep allowed_signers in the source repository if you want it shared (it's public-key material, safe to share)
  4. Any host can then verify commits signed on any other host

This creates a web-of-trust among your own fleet. No central CA, no external service — just SSH keys.

Machine-Scoped Secrets

Some secrets must decrypt only on specific hosts (e.g. a work VPN config that doesn't belong on a personal laptop). The SOPS approach:

# defaults/dot_config/vpn.sops.yaml
vpn_key: ENC[AES256_GCM,data:...]
sops:
  age:
    - recipient: age1... # work laptop only
      enc: |
        -----BEGIN AGE ENCRYPTED FILE-----
        ...

Only the host with the matching Age private key can decrypt. Other hosts see the encrypted file but cannot read the content.

Fleet Operational Commands

Command Purpose
dot fleet status This node's ID, namespace, version, OS, shell, drift state and last apply (--json for machine output)
dot fleet drift show This node's drift, recorded in the drift history
dot fleet apply SSH to every host in ~/.config/dotfiles/fleet.toml and run a command there (--host, --cmd, --dry-run, --jobs, --verify-hosts)
dot fleet push <user@host> Stream chezmoi archive from this host into the remote $HOME over SSH (without a user@host, it behaves like dot fleet apply)
dot fleet namespace list The active namespace and the [namespaces.*] defined in .chezmoidata.toml
dot fleet log show Recent fleet events: the fleet_<event> records of ~/.local/state/dot/fleet/log.jsonl (log.v1)
dot fleet policy show / dot fleet policy set <advisory|strict> The RBAC enforcement mode in agent-profiles.json

fleet.toml lists one [hosts.<name>] table per host with an ssh target and an optional profile. By default dot fleet apply runs dot config update && dot doctor on each host (pull the source, apply it, then check the host), four hosts at a time.

Limitations

  • dot fleet status and dot fleet drift show report on the host they run on; only dot fleet apply and dot fleet push reach other hosts, over SSH (see Roadmap)
  • Secret rotation requires re-encrypting for all recipients; there is no dot command for it, so re-encrypt with sops updatekeys or by re-adding the file with chezmoi add --encrypt
  • There is no central policy store — policy is versioned in the Git repository itself

See Also