Hybrid setup: chezmoi for dotfiles, Ansible for system provisioning.
home/— chezmoi source directory. All dotfiles and~/.shell/*.shmodules.ansible/— Ansible playbook with roles: preflight, packages, shell, tmux, fonts, node, neovim.scripts/— Docker smoke test.
- chezmoi templates use
.tmplsuffix. OS-conditional logic via{{ if eq .chezmoi.os "darwin" }}. - chezmoi source is
home/, not the default~/.local/share/chezmoi. private_dot_shell/maps to~/.shell/,private_dot_config/private_nvim/maps to~/.config/nvim/.- Shell modules are sourced by both zshrc and bashrc. Use
# shellcheck shell=bashheader (not#!/bin/sh). - Git aliases: shell wrappers (
alias gst='git status') go ingit.sh. Git-internal aliases (l = log ...) stay indot_gitconfig.tmpl. The oh-my-zshgitplugin is excluded to avoid conflicts. - Ansible roles use FQCN (
ansible.builtin.*,community.general.*). Role variables must be prefixed with the role name. - No
become: yeson Homebrew tasks. Onlybecome: trueon apt tasks. - No
failed_when: false— use specific conditions instead. - Pin
version:on allansible.builtin.gittasks. Some repos usemain, notmaster. - No hardcoded paths like
/usr/bin/curl— use bare command names for cross-platform. - macOS-only code must be in chezmoi-guarded templates.
make lint— yamllint + ansible-lint (must pass at production profile).make docker-test— full Ubuntu 24.04 smoke test (packages + chezmoi + idempotence).- CI runs on push/PR: lint on Ubuntu, chezmoi template verify on both macOS and Ubuntu.
- Dotfile changes: edit in
home/, runchezmoi apply. - Package changes: edit
ansible/group_vars/all/{macos,ubuntu}.yml, runmake system. - After any change: run
make lintbefore committing.