Managing Chezmoi Packages
This skill handles all aspects of package and dependency management in chezmoi dotfiles repositories, with emphasis on security, reproducibility, and automated updates.
Core Principles
- •Version Pinning: Always pin to immutable references (commit SHAs, specific versions, digests)
- •Renovate Automation: Ensure all dependencies have corresponding Renovate rules
- •Organization: Group externals by primary program using
.chezmoiexternals/directory - •Minimal Edits: Make focused changes without unrelated modifications
- •Preview First: Show proposed changes before applying
When to Use This Skill
Invoke this skill when the user requests:
- •Adding/updating/removing packages or tools
- •Managing chezmoi external dependencies
- •Pinning versions or updating SHAs
- •Organizing external files by program
- •Setting up Renovate automation for dependencies
- •Choosing between package ecosystems (Homebrew, mise, etc.)
Workflow
1. Identify the Request
Determine what the user wants:
- •Add: New package or external dependency
- •Update: Change version/SHA of existing package
- •Remove: Delete package or external
- •Organize: Migrate externals to
.chezmoiexternals/structure - •Pin: Add immutable version/SHA reference
2. Select the Ecosystem
Choose the appropriate package manager (see ./ecosystem-guide.md for details):
| Use Case | Ecosystem | Location |
|---|---|---|
| macOS packages (Homebrew) | brew/cask/mas | home/.chezmoidata/packages.yaml |
| CLI developer tools | mise (Aqua) | .mise.toml or home/dot_config/mise/config.toml |
| Python tools | pip | home/dot_config/dotfiles/requirements.txt |
| Docker/devcontainer | docker | home/dot_config/docker-compose/*.yml, .devcontainer/ |
| External files/repos | chezmoi externals | home/.chezmoiexternals/*.toml[.tmpl] |
| Install script CLIs | cli-versions | home/dot_config/dotfiles/cli-versions.toml |
3. For Chezmoi Externals: Use .chezmoiexternals/ Directory
IMPORTANT: Organize externals by primary program using the .chezmoiexternals/ directory structure.
Directory Structure
home/.chezmoiexternals/ ├── zsh.externals.toml # Zsh plugins and tools ├── bat.externals.toml # Bat themes and syntaxes ├── tmux.externals.toml # Tmux configurations └── nvim.externals.toml # Neovim plugins
How It Works
- •Files in
home/.chezmoiexternals/are treated as.chezmoiexternal.<format>files - •Each file defines externals for a specific program
- •Use
.tmplsuffix for templating support (OS conditionals, variables) - •Paths in each file are relative to the home directory
Example: zsh.externals.toml
{{ if lookPath "zsh" }}
# Zsh plugins and tools
[".zsh/znap/zsh-snap"]
type = "git-repo"
url = "https://github.com/marlonrichert/zsh-snap.git"
revision = "25754a45d9ceafe6d7d082c9ebe40a08cb85a4f0"
refreshPeriod = "168h"
[".zsh/plugins/zsh-autosuggestions"]
{{ end }}type = "git-repo"
url = "https://github.com/zsh-users/zsh-autosuggestions.git"
revision = "85919cd1ffa7d2d5412f6d3fe437ebdbeeec4fc5"
refreshPeriod = "168h"
4. External Types and Patterns
Chezmoi supports four external types (detailed in ./externals-reference.md):
git-repo
For complete Git repositories (plugins, frameworks):
[".zsh/plugins/plugin-name"] type = "git-repo" url = "https://github.com/user/repo.git" revision = "<commit-sha>" # MUST pin to SHA refreshPeriod = "168h"
file
For single files (themes, configs):
[".config/tool/theme.tmTheme"] type = "file" url = "https://github.com/user/repo/raw/<commit-sha>/file.ext" refreshPeriod = "168h"
archive-file
For extracting single binary from release archive:
[".local/bin/tool"] type = "archive-file" url = "https://github.com/user/repo/releases/download/v1.2.3/tool.tar.gz" executable = true path = "tool" checksum = "sha256:abc123..."
archive
For extracting entire archive into directory:
[".config/tool"] type = "archive" url = "https://github.com/user/repo/archive/<commit-sha>.tar.gz" exact = true stripComponents = 1 refreshPeriod = "168h"
5. Version Pinning Requirements
CRITICAL: Always use immutable references:
| Type | Pinning Method | Example |
|---|---|---|
| Git repo | Commit SHA in revision | revision = "abc123..." |
| GitHub file | Commit SHA in URL path | raw/<sha>/file.ext |
| Release binary | Version tag + checksum | v1.2.3 + checksum = "sha256:..." |
| Docker image | Digest | image:tag@sha256:... |
NEVER use:
- •
latesttags - •Mutable branch names without SHA pinning
- •Version ranges or wildcards
- •URLs without commit SHAs or checksums
6. Ensure Renovate Integration
For each external dependency, verify or add corresponding Renovate rule in renovate.json5.
See ./renovate-integration.md for detailed patterns.
Quick reference:
{
customType: 'regex',
fileMatch: ['^home/\\.chezmoiexternals/.*\\.toml(\\.tmpl)?$'],
matchStrings: [
'revision = "(?<currentDigest>[a-f0-9]{40})".*?# renovate: repo=(?<depName>.*?) branch=(?<currentValue>.*?)\\n',
],
datasourceTemplate: 'git-refs',
}
7. Apply Changes
For .chezmoiexternals/ files
- •Create or update the appropriate
.externals.tomlfile - •Add comments explaining each dependency
- •Include Renovate annotations for tracking:
toml
# renovate: repo=user/repo branch=main [".path/to/dependency"] type = "git-repo" url = "https://github.com/user/repo.git" revision = "<commit-sha>"
For packages.yaml
- •Edit
home/.chezmoidata/packages.yaml - •Add to appropriate section (darwin/linux, brews/casks/mas)
- •Follow existing patterns
8. Verification Commands
Preview changes:
chezmoi diff
Check external URLs:
# Verify latest commit SHA gh api repos/USER/REPO/commits/BRANCH --jq .sha # Check latest release tag gh api repos/USER/REPO/releases/latest --jq .tag_name # Verify file exists at SHA curl -fsSL https://github.com/USER/REPO/raw/SHA/path/to/file
Apply changes:
chezmoi apply
Test external updates:
chezmoi update --force
Common Workflows
Adding a New Zsh Plugin
# 1. Get latest commit SHA gh api repos/zsh-users/zsh-history-substring-search/commits/master --jq .sha # 2. Add to home/.chezmoiexternals/zsh.externals.toml # 3. Add Renovate rule to renovate.json5 # 4. Preview and apply chezmoi diff chezmoi apply
Adding a Homebrew Package
# 1. Edit home/.chezmoidata/packages.yaml # 2. Add to appropriate section (brews/casks) # 3. Renovate will track automatically (homebrew datasource)
Migrating Existing Externals to .chezmoiexternals/
- •Identify program groupings in
home/.chezmoiexternal.toml - •Search for references to the old file before migration:
Common references to fix:bash
grep -r "\.chezmoiexternal\.toml\.tmpl" home/
- •Scripts using
{{ include ".chezmoiexternal.toml" }}for hashing - •Documentation or comments mentioning the file
- •Scripts using
- •Create program-specific files in
home/.chezmoiexternals/ - •Move related externals to appropriate file
- •Update any references found in step 2 to point to new files (e.g.,
.chezmoiexternals/bat.externals.toml) - •Keep conditionals (e.g.,
{{ if lookPath "zsh" }}) - •Verify with
chezmoi diff(will error if references are broken) - •Remove old file only after all references are updated and
chezmoi diffsucceeds
Updating External to Latest SHA
# 1. Fetch current SHA gh api repos/USER/REPO/commits/BRANCH --jq .sha # 2. Update revision in .chezmoiexternals/*.toml # 3. Apply chezmoi apply
Output Format
When making changes, provide:
Decision: - Ecosystem: <brew|mise|python|docker|chezmoi-external|cli-versions> - Rationale: <1-2 sentences> - Organization: <which .chezmoiexternals/ file or other manifest> Files To Edit: - <path1> - <path2> Proposed Changes: <concise diff-like hunks showing additions/modifications> Renovate Integration: - Rule Status: <exists|needs-addition|needs-update> - Pattern: <brief description of regex or datasource> Verification Commands: - chezmoi diff - <optional gh api commands to verify versions> Next Steps: - [ ] Review proposed changes - [ ] Preview with chezmoi diff - [ ] Apply with chezmoi apply
Important Constraints
- •Never execute package managers without explicit permission
- •Always preview with
chezmoi diffbefore applying - •Use minimal edits: Change only what's necessary
- •Maintain comments: Explain why each dependency exists
- •Follow patterns: Match existing style and structure
- •Version pinning: No mutable references
Platform-Specific Handling
Use Go templates for platform-specific externals:
{{ if eq .chezmoi.os "darwin" }}
[".local/bin/tool-mac"]
{{ else if eq .chezmoi.os "linux" }}
type = "archive-file"
url = "https://github.com/user/tool/releases/download/v1.0.0/tool-darwin-{{ .chezmoi.arch }}.tar.gz"
executable = true
[".local/bin/tool-linux"]
{{ end }}type = "archive-file"
url = "https://github.com/user/tool/releases/download/v1.0.0/tool-linux-{{ .chezmoi.arch }}.tar.gz"
executable = true
Troubleshooting
External fails to download:
- •Verify URL accessibility:
curl -fsSL <url> - •Check commit SHA exists:
gh api repos/USER/REPO/commits/SHA - •Review chezmoi logs:
chezmoi apply -v
Renovate not detecting dependency:
- •Verify regex pattern matches your format
- •Check fileMatch glob is correct
- •Test regex: use online regex tester with actual file content
- •Ensure annotations are present if required
Checksum mismatch:
- •Download file and compute SHA:
curl -fsSL <url> | shasum -a 256 - •Update checksum in external definition
- •Verify URL points to correct version
Best Practices
- •Group by program: Use
.chezmoiexternals/PROGRAM.externals.toml - •Document dependencies: Add comments explaining purpose
- •Annotate for Renovate: Include
# renovate:comments - •Use templates: Leverage
{{ if }}for conditional installs - •Set refreshPeriod: Balance freshness vs. performance (168h = weekly)
- •Test on clean machine: Verify externals work from scratch
- •Pin everything: No mutable references, ever
Reference Documentation
- •
./externals-reference.md- Complete external type specifications - •
./renovate-integration.md- Renovate automation patterns - •
./ecosystem-guide.md- Package manager selection guide