-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration
Complete reference for heimdal.yaml — the single configuration file that drives Heimdal.
- File Location
- Basic Structure
- Root
heimdalSection - Top-Level Packages
- Profiles
- Packages Configuration
- Dotfiles Configuration
- Templates Configuration
- Hooks
- Ignore Patterns
- Profile Inheritance
- macOS Defaults
- Validation
- Complete Example
heimdal.yaml lives inside your dotfiles directory (e.g., ~/.dotfiles/heimdal.yaml). The state file is kept separately at ~/.heimdal/state.json and is never stored in your dotfiles repo.
You can point to a specific config with the --config flag:
heimdal validate --config /path/to/heimdal.yamlheimdal:
version: "1"
repo: "git@github.com:you/dotfiles.git" # optional
# Top-level packages — applied to EVERY profile
packages:
common: [git, curl, vim] # installed via the detected PM on any OS
homebrew: [mas] # macOS only, every profile
profiles:
default:
packages:
common: [ripgrep, fzf]
homebrew: [iterm2]
dotfiles:
- .vimrc
- .zshrcGlobal settings for Heimdal:
heimdal:
version: "1" # Config schema version — required
repo: "git@github..." # Git repository URL — optional, used by sync/init| Field | Type | Required | Description |
|---|---|---|---|
version |
string | Yes | Config schema version. Must be "1". |
repo |
string | No | Git remote URL. Required if you use heimdal sync or heimdal init --repo. |
Packages defined at the top level (outside of any profile) are applied to every profile:
packages:
common: [git, curl, vim] # installed via whichever PM is detected on the current OS
homebrew: [mas] # macOS only, every profile
apt: [build-essential] # Debian/Ubuntu only, every profileThis is the place for universal tools you want on all machines regardless of profile.
Profiles define machine-specific configurations. At least one profile is required.
profiles:
default:
packages: ...
dotfiles: ...
templates: ...
hooks: ...
ignore: ...
work:
extends: default
packages: ...Use extends to inherit from another profile. The merge rules are:
-
packages,dotfiles,templates,ignore— unioned (child entries are added on top of parent entries) -
hooks— replaced by the child (child hooks completely override parent hooks)
profiles:
default:
packages:
homebrew: [git, vim]
dotfiles:
- .vimrc
hooks:
post_apply: ["echo base done"]
work:
extends: default
packages:
homebrew: [slack, zoom] # unioned: work gets git, vim, slack, zoom
hooks:
post_apply: ["echo work done"] # replaces parent hookPackages are organized by package manager key. Heimdal only installs from the manager(s) available on the current OS — keys for other platforms are silently skipped.
profiles:
default:
packages:
common: [ripgrep, fzf] # installed via whichever PM is detected
homebrew: [iterm2] # macOS — Homebrew formulae
homebrew_casks: [iterm2] # macOS — Homebrew casks
apt: [build-essential] # Debian/Ubuntu
dnf: [gcc] # Fedora/RHEL
pacman: [base-devel] # Arch Linux
apk: [alpine-sdk] # Alpine Linux
mas: # macOS App Store
- { id: 497799835, name: Xcode }
- "Xcode" # plain string also accepted| Key | Manager | Platform |
|---|---|---|
common |
Detected PM | Any — installs via the first available PM |
homebrew |
Homebrew formulae | macOS / Linux |
homebrew_casks |
Homebrew casks | macOS |
apt |
APT | Debian / Ubuntu |
dnf |
DNF | Fedora / RHEL |
pacman |
Pacman | Arch Linux |
apk |
APK | Alpine Linux |
mas |
Mac App Store | macOS |
MAS entries can be a plain string (app name) or an object with id and name:
mas:
- { id: 497799835, name: Xcode }
- "Amphetamine"A plain string is a path relative to the dotfiles directory. Heimdal symlinks it to the same path under ~:
dotfiles:
- .vimrc # ~/.vimrc
- .zshrc # ~/.zshrc
- .config/nvim # ~/.config/nvimUse a source/target object for custom destinations or conditional application:
dotfiles:
- source: .config/nvim
target: ~/.config/nvim
when:
os: [macos, linux]
hostname: "dev-*"
profile: [default]| Field | Type | Description |
|---|---|---|
os |
string[] | Apply only on these OS values: macos or linux
|
hostname |
string | Glob pattern matched against the machine hostname |
profile |
string[] | Apply only when one of these profiles is active |
If the dotfiles: list is empty or omitted, Heimdal falls back to a GNU Stow-style depth-1 walk: every top-level file/directory in the dotfiles directory is symlinked to ~.
Templates are files rendered with variable substitution before being symlinked:
profiles:
default:
templates:
- src: .gitconfig.tmpl
dest: ~/.gitconfig
vars:
name: "My Name"
email: "me@example.com"| Field | Description |
|---|---|
src |
Template file path (relative to dotfiles dir) |
dest |
Destination path for the rendered output |
vars |
Key-value pairs available as {{ key }} in the template |
System variables (os, hostname, user, home, env.VAR, secrets.NAME) are always available in templates. Undefined variables are preserved as-is in the output.
See Template System for full details.
Run shell commands before or after operations. When a child profile extends a parent, hooks are replaced (not merged).
profiles:
default:
hooks:
pre_apply: []
post_apply: ["echo done"]
pre_sync: []
post_sync: []Simple string:
hooks:
post_apply:
- "brew cleanup"
- "echo 'Applied!'"Full object format:
hooks:
post_apply:
- command: "brew cleanup"
os: [macos]
fail_on_error: true| Hook | When It Runs |
|---|---|
pre_apply |
Before applying the profile |
post_apply |
After applying the profile |
pre_sync |
Before syncing |
post_sync |
After syncing |
Ignore patterns tell Heimdal which files to skip when creating symlinks. They support glob syntax.
Per-profile ignore:
profiles:
default:
ignore: [".DS_Store", "*.md"]macOS only. Ignored on other platforms.
Control how Heimdal exports and imports macOS preference domains (plist files). See macOS Defaults Sync for full details.
defaults:
enabled: true
include:
- com.apple.dock
- com.apple.finder
- com.apple.NSGlobalDomain
exclude:
- com.apple.Safari.SandboxBroker
path: macos-defaults| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Enable defaults sync. Set to false to disable without removing the section. |
include |
string[] | [] |
Domains to process. If empty, all non-excluded domains are included. |
exclude |
string[] | [] |
Domains to exclude. Takes precedence over include. |
path |
string | macos-defaults |
Subdirectory within the dotfiles repo for exported plist files. |
When enabled: true, heimdal apply automatically exports all matching domains after the templates stage. Use heimdal defaults diff/import/sync for manual control.
# Validate the config in the current directory
heimdal validate
# Validate a specific file
heimdal validate --config custom.yaml
# Preview what would be applied without touching the system
heimdal apply --dry-runHeimdal validates:
- YAML syntax
- Required
heimdal.versionfield - Valid profile
extendsreferences - Valid hook syntax
heimdal:
version: "1"
repo: "git@github.com:yourusername/dotfiles.git"
# Applied to every profile on every machine
packages:
common: [git, curl, vim]
homebrew: [mas]
# macOS preferences sync (macOS only, ignored elsewhere)
defaults:
enabled: true
include:
- com.apple.dock
- com.apple.finder
- com.apple.NSGlobalDomain
path: macos-defaults
profiles:
default:
packages:
common: [ripgrep, fzf]
homebrew: [iterm2]
homebrew_casks: [iterm2]
apt: [build-essential]
dnf: [gcc]
pacman: [base-devel]
apk: [alpine-sdk]
dotfiles:
- .vimrc
- .zshrc
- source: .config/nvim
target: ~/.config/nvim
when:
os: [macos, linux]
templates:
- src: .gitconfig.tmpl
dest: ~/.gitconfig
vars:
name: "My Name"
email: "me@example.com"
hooks:
pre_apply: []
post_apply: ["echo done"]
pre_sync: []
post_sync: []
ignore: [".DS_Store", "*.md"]
work:
extends: default
packages:
homebrew: [slack, zoom]# Validate configuration
heimdal validate
# Apply configuration
heimdal apply
# Preview changes (no modifications)
heimdal apply --dry-run
# Apply with conflict handling
heimdal apply --force
heimdal apply --backup