Skip to content

Configuration

Location Shared? Purpose
<repo>/anvil.toml Yes (Git) Profiles, links, hooks, packages, harden
~/.config/anvil/config.toml No (local) repo_path, profiles, age_identity, aur_helper
~/.local/state/anvil/backups/ No (local) Backup journals for anvil undo
~/.config/anvil/config.toml
repo_path = "/home/you/.dotfiles"
profiles = ["base", "hyprland"]
age_identity = "~/.config/age/key.txt"
# Machine-local AUR helper. Not in anvil.toml.
# auto (default) = first of paru, yay on PATH — never auto-picks anzen
aur_helper = "auto" # or "paru" | "yay" | "anzen" | "/abs/path"

anvil init writes this file automatically. Edit it by hand if you move the clone. aur_helper is not a valid key in anvil.toml.

A full annotated sample lives at examples/anvil.toml.

[anvil]
version = "1"
default_profile = "base"
# clone_dir = "~/.dotfiles" # used as init default only
[profiles.base]
links = [
{ src = ".zshrc", dest = "~/.zshrc" },
{ src = ".gitconfig", dest = "~/.gitconfig" },
{ src = ".config/nvim", dest = "~/.config/nvim" },
# optional: copy instead of symlink
# { src = "mimeapps.list", dest = "~/.config/mimeapps.list", copy = true },
# optional: age-encrypted secret
# { src = "secrets/npmrc.age", dest = "~/.npmrc", mode = "600", decrypt = "age" },
]
hooks.after_apply = ["scripts/post-apply.sh"]
packages.pacman = ["git", "ufw", "age"]
# packages.aur = ["some-aur-package"]
[profiles.base.harden]
mode = "check" # or "enforce" (sysctl drop-in via sudo)
sysctl = [{ key = "kernel.kptr_restrict", value = "2" }]
ssh = { password_auth = false, root_login = false }
firewall = { backend = "ufw", default = "deny", allow = ["22/tcp"] }
[profiles.work]
extends = "base"
links = [
{ src = "work/.gitconfig", dest = "~/.gitconfig" }, # later wins on same dest
]
[machines]
"framework-arch" = ["base", "hyprland"]
Field Required Description
version yes Schema version ("1")
default_profile no Used when no CLI -p, local profiles, or machine match
clone_dir no Default clone path for init (~/.dotfiles)
Field Description
extends Parent profile name (chain; cycles error)
links File link entries
hooks.before_apply / after_apply Repo-relative scripts (no .., no absolute paths)
packages.pacman / packages.aur Package names (Arch)
harden Posture checks / optional enforce

Merge rules: ordered profile lists (CLI / machines / local) are primary. extends prepends parents. Later links win on the same dest. Hooks and packages concatenate (packages deduped).

Field Required Description
src yes Path relative to the repo root
dest yes System path (~ and ~/... expanded)
copy no true = copy file/dir instead of symlink
mode no Octal mode string, e.g. "600" (also inferred under ~/.ssh/)
decrypt no "age" — decrypt src to dest with the age CLI

Hostname → list of profiles. Matched via the system hostname when no -p or local profiles override.