--- title: Apply scripts description: Every run_ script chezmoi executes during apply, when each one fires, and what it does on each OS and role. --- Six scripts run during `chezmoi apply`. Four live in `.chezmoiscripts/`, a directory whose scripts run as if they sat at the source root without creating a matching target directory. Two sit at the repo root. All six are templates and all use `#!/bin/sh` with `set -eu`. ## Execution order `before_` scripts run before any file is written; `after_` scripts run after every file, symlink, and external is in place. Within a phase chezmoi runs scripts in ASCII order of their target names, so the numeric prefixes come first. Install system packages from `packages.yaml`. chezmoi writes the target state. Install gh extensions. Enable systemd user units on Linux. tpm clone, bat cache, font cache. Rebuild bat cache when its theme or config changes. Reinstall yazi plugins when the manifest changes. | Script | Phase | Frequency | Re-run trigger | | --- | --- | --- | --- | | `.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl` | before | onchange | sha256 of `.chezmoidata/packages.yaml`; also the role and OS, which change the rendered package list | | `.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl` | after | onchange | sha256 of `packages.shared.gh_extensions` as JSON | | `.chezmoiscripts/run_once_after_30-user-services.sh.tmpl` | after | once | Runs once per distinct rendered content | | `.chezmoiscripts/run_onchange_after_40-post.sh.tmpl` | after | onchange | Only edits to the script itself (or an OS change) | | `run_onchange_after_build-bat-cache.sh.tmpl` | after | onchange | sha256 of `dot_config/bat/themes/cyberdream.tmTheme` and `dot_config/bat/config` | | `run_onchange_after_install-yazi-plugins.sh.tmpl` | after | onchange | sha256 of `dot_config/yazi/package.toml` | `run_onchange_` scripts re-run whenever their rendered content differs from the last successful run. The hash triggers work by writing a checksum of another file into a comment, so editing that file changes the script's content: ```sh # packages.yaml hash: {{ include ".chezmoidata/packages.yaml" | sha256sum }} ``` `run_once_` scripts run once per unique rendered content and again only if that content changes or the previous run failed. ## 10-packages [#10-packages] `.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl` installs everything in [`packages.yaml`](/chezmoi/data#packagesyaml). It runs before files are applied so the tools exist when configs land. 1. Uses `pacman` directly when running as root, otherwise `sudo pacman`. 2. `pacman -S --needed --noconfirm` with every entry in `packages.arch.pacman`. 3. For roles `desktop` and `laptop`, a second `pacman -S --needed --noconfirm` with `packages.arch.desktop.pacman`. 4. Builds the AUR list: `packages.arch.desktop.aur` plus `packages.arch.aur` for `desktop`/`laptop`, only `packages.arch.aur` for other roles. 5. If the list is non-empty and `paru` exists, runs `paru -S --needed --noconfirm` on it. Without `paru` it prints `warning: paru not found — skipping AUR packages: …` and continues. 1. Exits with an error pointing at https://brew.sh if `brew` is missing. 2. `brew install` with every entry in `packages.darwin.brew`. 3. `brew install --cask` with every entry in `packages.darwin.cask`. The role is not consulted on macOS. On any other OS the script renders to just the shebang and comments and does nothing. ## 20-gh-extensions [#20-gh-extensions] `.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl` installs each `packages.shared.gh_extensions` entry on every OS. - Exits 0 with `warning: gh not installed — skipping extensions` if `gh` is missing. - Exits 0 with `warning: gh not authenticated — run 'gh auth login', then 'chezmoi apply' again` if `gh auth status` fails. - Reads `gh extension list`, then runs `gh extension install ` only for extensions not already present. :::warning A skipped run still exits 0, so chezmoi records this content as done and a plain re-apply does not retry it, despite what the warning text says. After `gh auth login`, either run `gh extension install` for each entry by hand, or clear chezmoi's onchange state with `chezmoi state delete-bucket --bucket=entryState` and apply again (this re-runs every `run_onchange_` script). ::: ## 30-user-services [#30-user-services] `.chezmoiscripts/run_once_after_30-user-services.sh.tmpl` enables session-critical systemd user units on Linux. - If `~/.config/systemd/user/nirinit.service` exists and `systemctl` is available, runs `systemctl --user daemon-reload` and `systemctl --user enable nirinit.service`. Failures are ignored. - On non-Linux systems it renders to `#!/bin/sh` / `exit 0`. Other personal automation units (brain-lens, omp-loop, rclone, hermes, voxtype) are deliberately not enabled; the script comment says to enable them by hand per machine. The repo does not currently contain a `dot_config/systemd/` directory, so the unit file has to exist on the machine already for this script to do anything. ## 40-post [#40-post] `.chezmoiscripts/run_onchange_after_40-post.sh.tmpl` is post-apply housekeeping. It has no hash comment, so it only re-runs when the script itself is edited. | Step | Condition | Action | | --- | --- | --- | | tmux plugin manager | `tmux` installed and `~/.config/tmux/plugins/tpm` missing | `git clone --depth=1 https://github.com/tmux-plugins/tpm ~/.config/tmux/plugins/tpm` | | bat cache | `bat` installed | `bat cache --build` | | Font cache | Linux, `fc-cache` installed | `fc-cache -f` | Each step ignores failures (`|| true`). `tmux.conf` expects tpm at that path; see [tmux](/terminal/tmux). ## build-bat-cache [#build-bat-cache] `run_onchange_after_build-bat-cache.sh.tmpl` rebuilds bat's syntax and theme cache when the managed inputs change. It hashes `dot_config/bat/themes/cyberdream.tmTheme` and `dot_config/bat/config`, exits quietly if `bat` is missing, and otherwise runs `bat cache --build`. This registers the cyberdream theme and the PureScript syntax cloned by [`.chezmoiexternal.toml`](/chezmoi/externals-and-ignore#externals). ## install-yazi-plugins [#install-yazi-plugins] `run_onchange_after_install-yazi-plugins.sh.tmpl` reinstalls yazi plugins whenever `dot_config/yazi/package.toml` changes. It exits quietly if `ya` is missing or `${XDG_CONFIG_HOME:-$HOME/.config}/yazi/package.toml` does not exist, and otherwise runs `ya pkg install`. The installed plugins land in `~/.config/yazi/plugins/`, which `.chezmoiignore.tmpl` excludes. The plugin list is on the [yazi page](/tools/yazi).