Ansible Customization Guide¶
This document explains how to customize the ansible setup for your dotfiles.
Directory Structure¶
After chezmoi apply, ansible files are deployed to ~/.ansible/:
~/.ansible/
├── ansible.cfg # Ansible configuration (sets roles_path, inventory)
├── inventories/
│ └── localhost.ini # Local inventory
├── playbooks/
│ ├── base.yml # Cross-platform essentials
│ ├── linux.yml # Linux-specific setup
│ └── macos.yml # macOS-specific setup
└── roles/
├── base/ # git, curl, ripgrep, fd, etc.
├── homebrew/ # macOS Homebrew installation
├── neovim/ # Neovim with version check
└── lazyvim_deps/ # fzf, lazygit, tree-sitter-cli
Prerequisites¶
Install ansible and required collections:
# Install ansible with uv
uv tool install ansible-core
# Install community.general collection (for homebrew module)
ansible-galaxy collection install community.general
Running Playbooks¶
Run from ~/.ansible/ directory (ansible.cfg sets inventory and roles_path automatically):
Full Setup¶
cd ~/.ansible
# macOS
ansible-playbook playbooks/macos.yml
# Linux
ansible-playbook playbooks/linux.yml
Specific Tags¶
cd ~/.ansible
# Only install neovim
ansible-playbook playbooks/macos.yml --tags neovim
# Install neovim and its dependencies
ansible-playbook playbooks/macos.yml --tags "neovim,lazyvim_deps"
Skip Tags¶
# Skip tasks requiring sudo (for non-admin users)
ansible-playbook playbooks/linux.yml --skip-tags sudo
Dry Run¶
# Check what would change without applying
ansible-playbook playbooks/macos.yml --check
# Verbose output
ansible-playbook playbooks/macos.yml --check -v
Available Tags¶
| Tag | Description | Requires Sudo |
|---|---|---|
base |
Essential tools (git, curl, ripgrep, fd, jq) | Linux only |
homebrew |
macOS Homebrew installation | No |
neovim |
Neovim installation with version check | Linux only |
lazyvim_deps |
LazyVim dependencies | Linux only |
networking_tools |
Networking CLI tools (nmap, mtr, httpie, gping, trippy, etc.) | Linux only (partial) |
sudo |
All tasks requiring elevated privileges | Yes |
Adding New Roles¶
- Create role directory structure:
- Create tasks file
~/.ansible/roles/myrole/tasks/main.yml:
---
- name: Install my package (macOS)
when: ansible_os_family == "Darwin"
community.general.homebrew:
name: mypackage
state: present
- name: Install my package (Debian/Ubuntu)
when: ansible_os_family == "Debian"
become: true
tags: [sudo]
ansible.builtin.apt:
name: mypackage
state: present
- Add role to playbook:
Syncing Changes Back to Chezmoi¶
After experimenting with changes in ~/.ansible/, add them back to chezmoi:
# Copy modified files back to chezmoi source
cp ~/.ansible/roles/myrole/tasks/main.yml ~/.local/share/chezmoi/dot_ansible/roles/myrole/tasks/main.yml
# Or use chezmoi re-add
chezmoi re-add ~/.ansible/roles/myrole/tasks/main.yml
OS Detection¶
Ansible facts used for OS detection:
| Fact | macOS | Ubuntu/Debian |
|---|---|---|
ansible_os_family |
Darwin | Debian |
ansible_distribution |
MacOSX | Ubuntu |
ansible_pkg_mgr |
homebrew | apt |
Example conditional:
- name: macOS only task
when: ansible_os_family == "Darwin"
# ...
- name: Ubuntu only task
when: ansible_distribution == "Ubuntu"
# ...
Sudo Handling¶
Linux¶
Most package installations require sudo. Tasks are tagged with sudo:
Skip these with --skip-tags sudo if you don't have sudo access.
macOS¶
Homebrew runs as user, no sudo needed. The only exception is system-level changes.
Troubleshooting¶
Syntax Check¶
Verbose Output¶
List Tasks¶
List Tags¶
Common Failures¶
GLIBC_2.XX not found when running an installed CLI (Ubuntu 22.04 / older distros)¶
Symptom — a CLI installed by the ansible roles fails at startup:
Root cause — the .tar.gz or .deb published under the tool's
unknown-linux-gnu target was built on a CI image (Ubuntu 24.04 / Debian 13)
whose glibc is newer than what the host distro ships. Ubuntu 22.04 LTS is
stuck on glibc 2.35, so any binary needing glibc ≥ 2.36 will fail to
start.
Fix (already applied in this repo as of the Jammy hardening patch): the ansible roles now prefer musl assets over gnu assets, and fall back to Linuxbrew (or skip-with-warning) when no safe musl asset exists. See docs/linux-package-sources.md → GitHub binary asset selection policy for the full policy.
If you still see the error on a box provisioned by this repo, one of these applies:
- A stale gnu binary is still on PATH from a previous apply. The new
role only downloads musl / brew when the
command -v <tool>check fails — so an old broken binary short-circuits the install. Remove it and re-runchezmoi apply:
- The tool has no upstream musl asset and Linuxbrew isn't installed.
Affected tools as of this writing:
tv(all arches),git-delta(arm64 only),eza(arm64 only). The role prints an explicit debug message telling you to install Linuxbrew. On Debian/Ubuntu:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
chezmoi apply # re-runs the role, brew-install branch taken this time
- A new tool was added to a role using
unknown-linux-gnuagain. When adding a role that downloads a Rust/Go binary, prefer the musl asset and fall back to brew-or-skip per the policy linked above. Pattern examples:ripgrep/bat/fd/zellij/tailspin/lnav/trippy.
eza install fails on some hosts with broken third-party apt repo¶
See the comment on the Add eza repository task in
dot_ansible/roles/devtools/tasks/main.yml — the deb.gierens.de repo
occasionally ships an expired GPG signature. The role tolerates this and
falls through to the GitHub-release fallback, so no manual fix is usually
needed. If the fallback also fails, remove the broken repo file:
sudo rm -f /etc/apt/sources.list.d/gierens.list /etc/apt/keyrings/gierens.gpg
sudo apt update
chezmoi apply # re-runs the role; GitHub-release fallback picks it up
LazyVim Requirements¶
LazyVim needs:
- Neovim >= 0.11.2
- ripgrep (for telescope live grep)
- fd (for telescope file finder)
- Node.js (for LSP servers)
- tree-sitter-cli (for syntax highlighting)
- lazygit (optional, for git integration)
- fzf (optional, for fuzzy finding)
All are installed by the base, neovim, and lazyvim_deps roles.