# Dotfiles Manages dotfiles, packages, and system state across multiple machines, with per-host and per-group overrides. ## Quick start curl https://git.capella.pro/capella/dotfiles/raw/master/start | bash -s -- sync Or if already installed: dotsync ## Usage start sync [--machine|--group ] [dot_file] start list start status start packages [install|diff|save] `sync` also commits and pushes the repo. It is unprivileged and fast; `packages` needs sudo, so it is deliberately not run as part of `sync`. ## Repository layout dots/ # common dotfiles (all hosts) dots./ # host-specific dotfiles dots.@/ # group-level dotfiles to_sync[.|.@] # which dotfiles to deploy pkglist[.|.@] # which packages to install groups. # group membership, one per line start # this tool bootstrap # system state that needs root (see below) ## Multi-host Each host is identified by its hostname (`uname -n`). ### File overrides Resolution order (**last wins**): common -> groups (alphabetical) -> host. A host copy of a file replaces the common one entirely, so host overrides must be complete files, not fragments. ### Sync lists to_sync # files synced to all hosts to_sync. # additional files for a specific host to_sync.@ # additional files for a group ### Groups groups. # one group name per line Example `groups.jellyfish`: wayland Hosts in the same group share `to_sync.@`, `dots.@/` and `pkglist.@`. ### In-file markers For files that are mostly shared with a few per-host differences, use markers instead of duplicating the whole file: # @host jellyfish set $mod Mod4 # @end # @host tompot set $mod Mod1 # @end # @group wayland exec waybar # @end - Lines between `@host ` and `@end` are included only on that host - Lines between `@group ` and `@end` are included for hosts in that group - Lines outside any markers are always included - The comment prefix (`#`, `//`, `;`, etc.) is auto-detected - Files with markers are processed and written (not symlinked) - Files without markers are symlinked as usual Generated files carry a `DO NOT EDIT` header naming their source. Edit the file under `dots/`, not the copy in `$HOME`. ## Adding dotfiles # Add to common (all hosts): dotsync sync .config/foo # Add for this host only: dotsync sync --machine .config/bar # Add for a group: dotsync sync --group wayland .config/baz ## Packages dotsync packages # install tracked packages missing here dotsync packages diff # show drift both ways, change nothing dotsync packages save # write this host's packages to pkglist. Package lists are **additive**, not last-wins: `pkglist`, `pkglist.@` and `pkglist.` are unioned. A host list adds to the common one and can never remove from it. This is the opposite of how dotfiles resolve -- overriding makes sense for a config file, not for a package set. Put a package in `pkglist` when you want it everywhere, and in `pkglist.` only when it is genuinely specific to that machine (hardware, or a role the other hosts do not have). Lists record **explicitly installed** packages only (`yay -Qqe`), so packages pulled in as dependencies stay out and get resolved automatically. Locally built `-debug` artifacts are filtered out: makepkg generates them on whichever machine did the build, and they are not installable elsewhere. `packages` never removes anything. Dropping an entry from a list makes it show up under "installed but NOT tracked" in `diff`; uninstall it yourself. A sync command that can silently uninstall is not worth the convenience. ## System state `bootstrap` covers what dotsync cannot: things outside `$HOME` that need root. ./bootstrap It is idempotent -- files are only written when their content differs, and units are skipped when already enabled, or when the package providing them is not installed on this host. Run it after `dotsync packages`. Currently it manages: - `KillUserProcesses=no`, as a logind drop-in so package upgrades cannot revert it (the default kills `etterminal` and takes the whole `etserver` down) - `greetd` autologin into sway - `iwd` stop timeout - enabling the system and user units the desktop needs It needs a real terminal, since sudo has to prompt. Host differences use a plain `case $(uname -n)`, not `@host` markers -- those only apply to files deployed into `$HOME`.