Skip to content

Configuration

Aleem Isiaka edited this page Jun 16, 2026 · 4 revisions

Configuration Reference

Complete reference for heimdal.yaml — the single configuration file that drives Heimdal.

Table of Contents

File Location

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.yaml

Basic Structure

heimdal:
  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
      - .zshrc

Root heimdal Section

Global 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.

Top-Level Packages

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 profile

This is the place for universal tools you want on all machines regardless of profile.

Profiles

Profiles define machine-specific configurations. At least one profile is required.

profiles:
  default:
    packages: ...
    dotfiles: ...
    templates: ...
    hooks: ...
    ignore: ...

  work:
    extends: default
    packages: ...

Profile Inheritance

Use extends to inherit from another profile. The merge rules are:

  • packages, dotfiles, templates, ignoreunioned (child entries are added on top of parent entries)
  • hooksreplaced 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 hook

Packages Configuration

Packages 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

Supported Package Manager Keys

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 Package Format

MAS entries can be a plain string (app name) or an object with id and name:

mas:
  - { id: 497799835, name: Xcode }
  - "Amphetamine"

Dotfiles Configuration

Shorthand Syntax

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/nvim

Explicit Mapping

Use 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]

when Condition Fields

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

GNU Stow Fallback

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 Configuration

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.

Hooks

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: []

Hook Entry Formats

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

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 Defaults

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.

Validation

# 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-run

Heimdal validates:

  • YAML syntax
  • Required heimdal.version field
  • Valid profile extends references
  • Valid hook syntax

Complete Example

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]

Related Commands

# 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

Clone this wiki locally