Imported from prdlk/dotfiles master (efdd827), which supersedes the omarchy branch (3031416). Drops the Umbriel, Noctalia, niri, CachyOS, macOS, and Blume docs-site layers; docs/ is plain Markdown.
13 KiB
Apply scripts
Every run_ script chezmoi executes during apply, when each one fires, and what it does on each OS and role.
Seven scripts run during chezmoi apply. Five 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 seven are templates; 20-gh-extensions is a fish script, the rest use #!/bin/sh with set -eu (except 25-skills, which uses set -u).
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.
-
10-packages (before, onchange)
Install system packages from
packages.yaml. -
Files, symlinks, externals
chezmoi writes the target state.
-
15-tools (after, onchange)
rustup and cargo crates, omp, global mise tools, strata on Linux desktops.
-
20-gh-extensions (after, onchange)
Install gh extensions from a fish session.
-
25-skills (after, onchange)
Install and prune agent skills.
-
30-user-services (after, once)
Enable systemd user units (kitty-day-save, projects-sync.timer).
-
40-post (after, onchange)
bat cache, font cache.
-
build-bat-cache (after, onchange)
Rebuild bat cache when its theme or config changes.
-
install-yazi-plugins (after, onchange)
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_15-tools.sh.tmpl |
after | onchange | sha256 of packages.shared.cargo and packages.shared.mise as JSON; also the OS and role, which add the strata step |
.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl |
after | onchange | sha256 of packages.shared.gh_extensions as JSON |
.chezmoiscripts/run_onchange_after_25-skills.sh.tmpl |
after | onchange | sha256 of .skills 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 | 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 ~/.config/yazi/package.toml (empty when the file is absent) |
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:
# 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
.chezmoiscripts/run_onchange_before_10-packages.sh.tmpl installs everything in packages.yaml. It runs before files are applied so the tools exist when configs land. On a non-Linux OS it renders to just the shebang and does nothing.
Steps
- Uses
pacmandirectly when running as root, otherwisesudo pacman. pacman -Tfilters each list down to names no installed package provides (somise-binsatisfiesmise,yazi-gitsatisfiesyazi), thenpacman -S --needed --noconfirminstalls the rest ofpackages.arch.pacman.- For roles
desktopandlaptop, the same forpackages.arch.desktop.pacman, and forpackages.arch.desktop.omarchywhenpacman-conf -llists anomarchyrepo. - Builds the AUR list:
packages.arch.desktop.aurpluspackages.arch.aurfordesktop/laptop, onlypackages.arch.aurfor other roles, then drops every namepacman -Tsays is already provided. Desktop apps already installed from a sync repo ([omarchy]) are therefore neither rebuilt nor replaced. - If anything is left and neither
yaynorparuis installed, bootstrapsyay: from a sync repo whenpacman -Si yayfinds one, otherwise by buildingyay-binfrom the AUR withmakepkg -si(installsgitandbase-develfirst; skipped as root, since makepkg refuses root). Omarchy shipsyay, so this is normally a no-op. - Runs
yay -S --needed --noconfirmon the remaining names, falling back toparu. yay prefers a sync repo over the AUR when both have the name. If no helper could be bootstrapped it printswarning: no yay/paru and none could be bootstrapped — skipping AUR packages: …and continues.
15-tools
.chezmoiscripts/run_onchange_after_15-tools.sh.tmpl installs the tools that do not come from pacman. It prepends ~/.cargo/bin to PATH, since chezmoi's environment can predate the shell config that adds it. Any failing step aborts the script, so chezmoi keeps the old hash and retries on the next apply.
| Step | Condition | Action |
|---|---|---|
| rustup | cargo not on PATH |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path. -y because there is no prompt under chezmoi; --no-modify-path because the shell rc files are symlinks into this repo and already source ~/.cargo/env |
| cargo crates | every OS | cargo install --locked <crate> for each packages.shared.cargo entry missing from cargo install --list |
| mise tools | mise installed (warning otherwise) |
mise use -g <tools…> for each packages.shared.mise entry absent from mise ls --global --json, then mise install <tools…>. A tool already in the global config keeps its pinned version. omp and opencode come from here |
| old omp binary | ~/.local/bin/omp is a regular file and mise which omp resolves |
Deletes it: a copy from omp's own installer (omp.sh/install) sits ahead of mise's shims on PATH |
| strata | Linux, roles desktop/laptop, no ~/.local/bin/strata |
curl -fsSL https://raw.githubusercontent.com/lgse/strata/main/install.sh | bash -s -- --with-desktop-entry --with-file-manager |
| strata file chooser | Linux, roles desktop/laptop, ~/.local/bin/strata exists and ~/.local/share/xdg-desktop-portal/portals/strata.portal does not |
strata --install-portal |
The strata flags install the binary, ~/.local/share/applications/io.github.lgse.Strata.desktop, and the org.freedesktop.FileManager1 D-Bus service in ~/.local/share/dbus-1/services ("Open file location" from other apps). The folder default (inode/directory) comes from the managed ~/.config/mimeapps.list instead of --with-folder-association, because xdg-mime default would replace that symlink with a plain file. The installer's own dependency step runs sudo -n pacman, which fails without cached credentials, so its runtime packages are declared in packages.arch.desktop.pacman and are already present when it runs.
strata --install-portal makes strata the system file chooser for portal-aware apps (browsers, GTK file dialogs). It writes strata.portal and the org.freedesktop.impl.portal.desktop.strata D-Bus service under ~/.local/share, prepends strata; to the org.freedesktop.impl.portal.FileChooser line of ~/.config/xdg-desktop-portal/<desktop>-portals.conf (hyprland-portals.conf, copied from /usr/share/xdg-desktop-portal/ when absent, so the compositor's backends stay as fallbacks), marks the in-app offer answered (~/.config/strata/portal-opt-in-v1), and restarts xdg-desktop-portal.service. That config file is strata's, not chezmoi's: strata --uninstall-portal restores it. Check: gdbus call --session --dest org.freedesktop.impl.portal.desktop.strata --object-path /org/freedesktop/portal/desktop --method org.freedesktop.DBus.Properties.Get org.freedesktop.impl.portal.FileChooser version prints uint32 4. Apps that draw their own picker instead of calling the portal are unchanged.
20-gh-extensions
.chezmoiscripts/run_onchange_after_20-gh-extensions.sh.tmpl installs each packages.shared.gh_extensions entry. It is a fish script (#!/usr/bin/env fish), so fish sources ~/.config/fish first: PATH (mise, ~/.local/bin, ~/.cargo/bin) and GITHUB_TOKEN (from gh auth token in conf.d/10-env.fish) are those of a fish session. It runs after every file is applied and after 15-tools, so the fish config and ~/.cargo/env.fish exist.
- Exits 0 with
warning: gh not installed — skipping extensionsifghis missing. - Exits 0 with
warning: gh not authenticated — run 'gh auth login', then 'chezmoi apply' againifgh auth statusfails. - Reads
gh extension list, then runsgh extension install <repo>only for extensions not already present. - Exits 1 listing the failed extensions if any install failed, so the next apply retries.
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 rungh extension installfor each entry by hand, or clear chezmoi's onchange state withchezmoi state delete-bucket --bucket=entryStateand apply again (this re-runs everyrun_onchange_script).
25-skills
.chezmoiscripts/run_onchange_after_25-skills.sh.tmpl installs the agent skills declared in skills.yaml with the Skills CLI (npx -y skills@1.7.0). See Skills.
- Exits 0 with a warning if
npxis missing. - One-time migration: deletes any directory in
~/.agents/skillsor~/.claude/skillsthat contains symlinks into the chezmoi source directory (the old vendored layout), and removes~/.agents/.skill-lock.jsonif it is a symlink into the source directory. - Removes skills listed in
${XDG_STATE_HOME:-~/.local/state}/chezmoi/skills.txtthat are no longer declared, withskills remove -g -y. - Runs one
skills add <source> -g -y -a <agents> --skill <names…>per source entry. Output is captured; on failure the last 8 lines are printed. - Writes the declared names to
skills.txt. Claude-only installs are not in the CLI's lock, so the script keeps its own record. - Exits 1 if any source failed, so chezmoi keeps the old hash and retries on the next apply.
30-user-services
.chezmoiscripts/run_once_after_30-user-services.sh.tmpl enables session-critical systemd user units on Linux.
- Same check for
~/.config/systemd/user/kitty-day-save.service(fromdot_config/systemd/user/, so Linux desktop/laptop roles only), thensystemctl --user enable --now kitty-day-save.service. See kitty-day-save. - Same check for
~/.config/systemd/user/projects-sync.timer, thensystemctl --user enable --now projects-sync.timer. See projects-sync. - 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. Their unit files are not in the repo, so they have to exist on the machine already.
40-post
.chezmoiscripts/run_onchange_after_40-post.sh.tmpl is post-apply housekeeping. It re-runs when the script is edited.
| Step | Condition | Action |
|---|---|---|
| bat cache | bat installed |
bat cache --build |
| Font cache | Linux, fc-cache installed |
fc-cache -f |
Each step ignores failures (|| true). tpm is cloned by .chezmoiexternal.toml, not here.
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.
install-yazi-plugins
run_onchange_after_install-yazi-plugins.sh.tmpl reinstalls yazi plugins whenever ~/.config/yazi/package.toml changes (the template hashes it via joinPath .chezmoi.homeDir, guarded with stat). 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. If that fails, it deletes ya's clone cache (${XDG_CACHE_HOME:-$HOME/.cache}/yazi/packages), since clones made by an older ya can break a newer one, and retries once. ~/.config/yazi is the prdlk/yazi external checkout, so the plugins land in its plugins/, which that repo's .gitignore excludes apart from the vendored bunny.yazi. The plugin list is on the yazi page.