Skip to content
dots
Esc
↑↓navigate↵open⌘Jpreview
On this page

Externals and ignore rules

The git repos chezmoi clones into $HOME and every rule in .chezmoiignore.tmpl, including the role gate for the Linux desktop layer.

.chezmoiexternal.toml

Externals are content chezmoi fetches instead of storing in the repo. Both entries are git-repo externals: chezmoi runs git clone when the target directory is missing. Because they are real git checkouts, they are never symlinked into the source tree.

[".config/nvim"]
    type = "git-repo"
    url = "https://github.com/prdlk/nvim.git"
    [".config/nvim".pull]
        args = ["--ff-only"]

[".config/bat/syntaxes/sublime-purescript-syntax"]
    type = "git-repo"
    url = "https://github.com/tellnobody1/sublime-purescript-syntax.git"
    [".config/bat/syntaxes/sublime-purescript-syntax".pull]
        args = ["--ff-only"]
Target Repo Used by
~/.config/nvim prdlk/nvim Neovim config, kept in its own repo
~/.config/bat/syntaxes/sublime-purescript-syntax tellnobody1/sublime-purescript-syntax PureScript syntax for bat, compiled into bat’s cache by the bat cache scripts

No refreshPeriod

Neither entry sets refreshPeriod, so it stays at chezmoi’s default of never. chezmoi clones each repo on a fresh machine and otherwise leaves it alone: chezmoi apply and chezmoi update do not pull. The local nvim checkout always wins over the remote, so in-progress Neovim edits and unpushed commits are never disturbed by an apply.

To update explicitly, run chezmoi apply --refresh-externals (-R), which pulls with git pull --ff-only. --ff-only makes the pull fail instead of creating a merge commit when the local checkout has diverged.

.chezmoiignore.tmpl

Patterns match target paths (relative to $HOME). Matching entries are neither written nor removed. The file is a template, so the desktop block appears only on machines where it applies. Source entries that start with . (.github/, .claude/, .crush/, .gitignore) are ignored by chezmoi without needing a rule.

Repo docs

MIGRATION-NOTES.md
README.md
CLAUDE.md
AGENTS.md
docs
.blume
node_modules
blume.config.ts
package.json
bun.lock
public
dist

Files at the source root that would otherwise land in $HOME as ~/README.md, ~/docs, ~/package.json, and so on. This covers the repo README and agent instruction files, plus this Blume docs site and its build output.

Runtime and plugin state inside managed trees

Pattern Why
.config/lazygit/.omc/** Tool state written inside the lazygit config dir
.config/yazi/plugins/** Installed by ya pkg install from package.toml (script)
.config/tmux/plugins/** tpm and the plugins it installs (40-post)
.config/fish/fish_variables fish universal variables, rewritten by fish at runtime
.config/nvim/lazy-lock.json lazy.nvim lockfile inside the nvim external
.config/nvim/.git, .config/nvim/.git/** The external’s git metadata
.config/nvim/.omc/**, .config/nvim/.crush/**, .config/nvim/.understand-anything/** Agent tool state inside the nvim checkout

.gitignore covers the source side of the same problem: dot_config/lazygit/dot_omc, dot_config/tmux/plugins, and __pycache__/ never get committed even though symlink mode lets tools write into the source tree.

mise

.config/mise
.config/mise/**

mise tool versions stay local to each machine and are not managed.

Linux desktop layer (role-gated)

{{ if or (ne .chezmoi.os "linux") (and (ne .role "desktop") (ne .role "laptop")) }}
.config/niri
.config/niri/**
.config/noctalia
.config/noctalia/**
.config/niri-dynamic-workspaces
.config/niri-dynamic-workspaces/**
.config/fontconfig
.config/fontconfig/**
.config/mimeapps.list
.config/systemd
.config/systemd/**
.local/bin/niri-launch
.config/fish/auto-Niri.fish
.local/bin/cp-appid
.config/tmux/niri-title.sh
{{ end }}

The block is emitted, and these paths skipped, unless the OS is linux and the role is desktop or laptop. mac and server machines, and any non-Linux machine regardless of role, never receive the niri compositor config (dot_config/niri/), fontconfig (dot_config/fontconfig/fonts.conf), default-app associations (dot_config/mimeapps.list), the fish auto-start hook (dot_config/fish/auto-Niri.fish), the tmux window-title helper, or the niri-launch and cp-appid scripts. The noctalia, niri-dynamic-workspaces, and systemd rules match nothing in the current source tree; they only take effect if those configs are added later.

Machine Desktop layer
Linux, desktop or laptop Applied
Linux, server or mac Ignored
macOS or other OS, any role Ignored

See Desktop for what the layer contains. Gaps in the gate: the block lists niri-launch but not its siblings (niri-launch-ai, niri-launch-browser, niri-launch-terminal, niri-launch-webapp), and the Hyprland and waybar configs (dot_config/hypr/, dot_config/waybar/) are not gated at all, so those apply on every role. dot_config/niri/scripts/ is covered by .config/niri/**.

Secrets in runtime state

.config/noctalia/plugins
.config/noctalia/plugins/**

noctalia writes plugin state containing embedded tokens here. These paths are ignored on every machine so tokens are never pulled into the repo.

Python byte-cache

.config/kitty/__pycache__
.config/kitty/__pycache__/**

kitty imports tab_bar.py and the other Python helpers in ~/.config/kitty, and Python writes __pycache__ next to them. In symlink mode that directory would otherwise appear in the source tree.

Was this page helpful?