9.1 KiB
Dotfiles Manager Documentation
A declarative dotfiles management system that handles package installation, binary management, configuration file linking, and system setup through a simple YAML manifest.
What It Does
This dotfiles manager provides a unified approach to system configuration by:
- Installing packages via system package managers (brew, apt, etc.)
- Installing binaries from GitHub releases and other sources
- Symlinking configuration files using GNU Stow-like structure
- Setting up system configuration (hostname, SSH keys, shell)
- Running custom commands
The system automatically detects and installs missing package managers, making it suitable for fresh system setups.
Directory Structure
~/.dotfiles/
├── dotfiles.py # Main execution script
├── manifest.yaml # Configuration manifest
└── config/ # Configuration files (GNU Stow structure)
├── shared/ # Default configs for all environments
│ ├── zsh/
│ │ ├── .zshrc # → ~/.zshrc
│ │ └── .config/
│ │ └── zsh/
│ └── bin/
│ └── scripts # → ~/bin/scripts
└── <environment>/ # Environment-specific overrides
└── <config>/
Manifest Structure
Global Binaries Section
Define reusable binary installations that can be referenced by environments:
binaries:
neovim:
version: "0.10.4"
source: "github:neovim/neovim"
asset-pattern: "nvim-{{os}}-{{arch}}.tar.gz"
platform-map:
"linux-amd64": { os: "linux", arch: "x86_64" }
"linux-arm64": { os: "linux", arch: "arm64" }
"macos-arm64": { os: "macos", arch: "arm64" }
dependencies: ["curl", "tar"]
install-script: |
if command -v nvim &> /dev/null && nvim --version | grep -q "{{version}}"; then
exit 0
fi
curl -Lo /tmp/nvim.tar.gz "{{downloadUrl}}"
rm -rf ~/.local/share/nvim
mkdir -p ~/.local/share/nvim ~/.local/bin
tar -xzf /tmp/nvim.tar.gz -C ~/.local/share/nvim --strip-components=1
ln -sf "$HOME/.local/share/nvim/bin/nvim" "$HOME/.local/bin/nvim"
rm -f /tmp/nvim.tar.gz
Binary Properties:
version: Version to installsource: Source location (currently supportsgithub:owner/repoformat)asset-pattern: Download filename pattern with{{os}},{{arch}}placeholdersplatform-map: Maps system platform to asset naming conventionsdependencies: Required system packages (installed via package manager)install-script: Shell script for installation
Binary Installation Variables: The install script receives these variables:
{{downloadUrl}}: Computed download URL for binary assets{{version}}: Binary version{{os}}and{{arch}}: Platform-specific values from platform-map
Environments Section
Environment-specific configurations that define complete system setups:
environments:
macos-host:
os: macos
hostname: macbook-pro
package-manager: brew
packages:
formula:
- dnsmasq
- neovim
cask:
- brave-browser
- name: rectangle
link: false
post-install-comment: "Needs manual configuration in System Preferences"
configs:
- zsh
- bin
ssh_keygen:
- type: ed25519
comment: "$USER@$TARGET_HOSTNAME"
filename: id_ed25519_internal
Environment Properties
Basic Configuration:
os: Target operating system (macosorlinux)hostname: System hostname to setpackage-manager: Package manager to use (brew,apt, etc.)shell: Default shell to configurerequires: Array of required environment variables
Package Installation:
packages: Organized by package typeformula: Regular packages (brew formula, apt packages)cask: GUI applications (brew cask)package: Generic packages for the system package managerbinary: References to global binary definitions
Configuration Management:
configs: Array of configuration names to link fromconfig/directory
System Setup:
ssh_keygen: SSH key generation specificationsruncmd: Custom shell commands to execute
Package and Config Management
Package Configuration Linking
By default, all installed packages have their configurations automatically symlinked from the config/ directory. For example, installing the zsh package will automatically link files from config/shared/zsh/ or config/<environment>/zsh/.
To disable automatic config linking for a specific package:
packages:
formula:
- name: rectangle
link: false
Configs Section
Use the configs section to symlink configurations without installing packages. This is useful for:
- Custom scripts and binaries (
bin) - Configurations for software installed outside the package manager
- Shared configuration files
configs:
- zsh # Links config/shared/zsh/ or config/<env>/zsh/
- bin # Links custom scripts from config/shared/bin/
- tmux # Links tmux configs without installing tmux package
Package Specifications
Packages can be specified as simple strings or objects with additional properties:
packages:
formula:
- git # Simple package name
- name: rectangle # Package object with properties
link: false
post-install-comment: "Manual configuration required"
- name: neovim # Package with post-installation script
post-install: |
nvim --headless '+PackerSync' +qa
post-link: |
echo "Neovim configuration linked"
binary:
- neovim # Reference to global binary
- name: tree-sitter # Binary with post-installation
post-install: |
tree-sitter --version
Package Object Properties:
name: Package namepost-install: Script to run after package installationpost-install-comment: Human-readable message after package installationlink: Boolean to control config linking (default: true)post-link: Script to run after config linkingpost-link-comment: Human-readable message after config linking
Config Object Properties:
post-link: Script to run after config linkingpost-link-comment: Human-readable message after config linking
SSH Key Generation
ssh_keygen:
- type: ed25519
comment: "$USER@$TARGET_HOSTNAME"
filename: id_ed25519_internal
SSH Key Properties:
type: Key type (ed25519,rsa, etc.)comment: Key comment (supports variable substitution)filename: Output filename (optional, defaults to standard naming)
Custom Commands
runcmd:
- mkdir -p ~/{tmp,projects}
- git remote set-url origin "$DOTFILES_GIT_REMOTE"
- systemctl --user enable podman.socket
Commands are executed in order after all other setup tasks complete.
Configuration File Management
Directory Structure
Configuration files follow GNU Stow conventions:
config/
├── shared/ # Default configurations
│ ├── zsh/
│ │ ├── .zshrc # Links to ~/.zshrc
│ │ └── .config/
│ │ └── zsh/
│ │ └── aliases # Links to ~/.config/zsh/aliases
│ └── bin/
│ └── my-script # Links to ~/bin/my-script
└── macos-host/ # Environment-specific overrides
└── zsh/
└── .zshrc # Overrides shared zsh config
Linking Priority
- Environment-specific configs (
config/<environment>/) take precedence - Shared configs (
config/shared/) used as fallback - Files are symlinked to preserve the exact directory structure
Variable Substitution
Variables can be used in scripts and strings:
$USER: Current username$TARGET_HOSTNAME: Target hostname (from environment or--setparameter)$HOME: User home directory
Custom variables can be provided at runtime:
./dotfiles.py --environment linux-vm --set TARGET_HOSTNAME=myserver --set DOTFILES_GIT_REMOTE=git@github.com:user/dotfiles.git
Usage
Basic Environment Installation
# Install complete environment
./dotfiles.py --environment macos-host
# Install with custom variables
./dotfiles.py --environment linux-vm --set TARGET_HOSTNAME=development-server
Example Environments
macOS Desktop Setup:
macos-host:
os: macos
hostname: macbook-pro
package-manager: brew
packages:
formula: [git, tmux, zsh]
cask:
- brave-browser
- name: discord
post-link-comment: "Import settings manually"
configs: [bin] # Only link bin, other configs linked automatically
ssh_keygen:
- type: ed25519
comment: "$USER@$TARGET_HOSTNAME"
Linux Server Setup:
linux-server:
requires: [TARGET_HOSTNAME]
os: linux
hostname: $TARGET_HOSTNAME
shell: zsh
packages:
package: [zsh, tmux, git, htop]
binary: [neovim, tree-sitter]
configs: [bin] # Link custom scripts
runcmd:
- mkdir -p ~/projects
- systemctl --user enable podman.socket