Sync Claude Code Config Across Multiple Machines with chezmoi: Complete Guide

Table of Contents
Sync Claude Code Config Across Multiple Machines with chezmoi: Complete Guide #
Change once, sync everywhere. One command for new machines.
1. The Problem: Multi-Machine Config Sync Pain #
I have 3 Macs: one MacBook and two Mac Minis. Each has Claude Code installed with a bunch of Skills — gstack, humanizer, marketing skills, etc. Might add cloud servers later.
After using them for a while, problems emerged:
- Skills installed on MacBook aren’t on the Mini
- Changed
CLAUDE.mdglobal config, other machines still have the old version - Setting up a new machine from scratch takes at least 30 minutes
- Skills updated, have to
git pullon every machine manually
What I need:
✅ Change once, all machines sync automatically
✅ Skills auto-update
✅ One command to set up new machines
✅ Different machines can have different configs (e.g., server needs extra skills)
2. Why chezmoi #
There are several dotfiles management tools out there. Here’s my comparison:
| Approach | Pros | Cons |
|---|---|---|
| Manual copy | Simple | Tedious, error-prone, unsustainable |
| Bare Git repo | Pure Git, no deps | Complex setup, merge conflicts |
| Mackup | macOS friendly | No custom paths, inflexible |
| chezmoi | Templates, encryption, cross-platform, external sources | Learning curve |
I chose chezmoi because:
- Template support — Different machines can render different configs
- External sources — Auto-pull skills from GitHub with periodic updates
- Encryption support — API keys can sync securely (not covered here)
- One-command init —
chezmoi init --applyfor new machines
3. Prerequisites #
3.1 Install chezmoi #
macOS:
brew install chezmoi
Linux:
sh -c "$(curl -fsLS get.chezmoi.io)"
Verify installation:
chezmoi --version
# chezmoi version 2.70.0
3.2 Create GitHub Repository #
Create a repository on GitHub, e.g., dotfiles. Can be public or private.
Tip: If your CLAUDE.md contains no sensitive info, a public repo is more convenient (no SSH setup needed).
3.3 Initialize chezmoi #
# Initialize (creates ~/.local/share/chezmoi directory)
chezmoi init
# Enter chezmoi directory
cd ~/.local/share/chezmoi
# Link remote repository (replace with yours)
git remote add origin https://github.com/yourusername/dotfiles.git
4. Understanding Claude Code Config Structure #
Before diving in, understand what’s in ~/.claude and what needs syncing:
~/.claude/
├── CLAUDE.md ✅ Sync - Global instructions
├── settings.json ✅ Sync - Plugin and permission config
├── skills/ ✅ Sync - Skill packages
│ ├── gstack/
│ ├── humanizer/
│ └── marketingskills/
├── projects/ ❌ Don't sync - Different per machine
├── sessions/ ❌ Don't sync - Runtime data
├── history.jsonl ❌ Don't sync - Chat history, too large
├── cache/ ❌ Don't sync - Cache
└── debug/ ❌ Don't sync - Debug logs
Three sources of Skills:
| Source | Example | Sync Method |
|---|---|---|
| Marketplace | obsidian, frontend-design | Stored in settings.json, auto-installed by Claude Code |
| Public GitHub | gstack, humanizer | Pull via chezmoi external |
| Private/custom | Your own skills | chezmoi add directly, or private repo |
5. Basic Sync: CLAUDE.md and settings.json #
5.1 Add Config Files #
# Add global instructions file
chezmoi add ~/.claude/CLAUDE.md
# Add plugin config
chezmoi add ~/.claude/settings.json
chezmoi naming conventions:
After running the above, you’ll see a private_dot_claude folder in the chezmoi directory. This is chezmoi’s naming convention:
dot_prefix = dot-prefixed files/dirs (.claude→dot_claude)private_prefix = file permissions 600 (only owner can read/write)
So ~/.claude becomes private_dot_claude.
5.2 View Added Files #
ls ~/.local/share/chezmoi/private_dot_claude/
# CLAUDE.md settings.json
5.3 Verify #
# See what chezmoi manages
chezmoi managed
# /Users/yourusername/.claude/CLAUDE.md
# /Users/yourusername/.claude/settings.json
6. Configure .chezmoiignore #
To avoid adding unwanted files, create .chezmoiignore:
cat > ~/.local/share/chezmoi/.chezmoiignore << 'EOF'
# Claude Code runtime data, don't sync
.claude/sessions
.claude/cache
.claude/history.jsonl
.claude/debug
.claude/telemetry
.claude/backups
.claude/projects
.claude/file-history
EOF
This way, even if you accidentally run chezmoi add ~/.claude, these directories are ignored.
7. Managing GitHub Skills with External #
This is the most valuable part — letting chezmoi auto-pull skills from GitHub with periodic updates.
7.1 Create External Config #
cat > ~/.local/share/chezmoi/.chezmoiexternal.toml << 'EOF'
# Claude Code Skills - Auto-install and update from GitHub
# chezmoi apply checks for updates (after refreshPeriod)
# Force refresh: chezmoi apply --refresh-externals
# GStack - Garry Tan's engineering team simulation
[".claude/skills/gstack"]
type = "archive"
url = "https://github.com/garrytan/gstack/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h" # Check weekly
# Humanizer - Remove AI-generated traces
[".claude/skills/humanizer"]
type = "archive"
url = "https://github.com/blader/humanizer/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
# Marketing Skills - CRO/SEO/copywriting/growth
[".claude/skills/marketingskills"]
type = "archive"
url = "https://github.com/coreyhaines31/marketingskills/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
# Frontend Slides - Create animated HTML presentations
[".claude/skills/frontend-slides"]
type = "archive"
url = "https://github.com/zarazhangrui/frontend-slides/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
EOF
7.2 Config Explanation #
| Field | Meaning |
|---|---|
[".claude/skills/xxx"] | Target path (relative to home) |
type = "archive" | Download tar.gz and extract |
url | GitHub repo archive download URL |
stripComponents = 1 | Strip top-level directory when extracting (GitHub archives include one) |
refreshPeriod = "168h" | 168 hours = 7 days, checks for updates after this period |
7.3 Apply Config #
chezmoi apply
First run downloads all skills, wait a moment.
7.4 Verify #
ls ~/.claude/skills/
# frontend-slides gstack humanizer marketingskills
8. Verify Complete Config #
Before committing, verify everything works:
# 1. See files managed by chezmoi
chezmoi managed
# 2. View diff (local vs chezmoi source)
chezmoi diff
# 3. Verify skills directory
ls ~/.claude/skills/
# 4. Verify CLAUDE.md
head -10 ~/.claude/CLAUDE.md
# 5. Verify settings.json
cat ~/.claude/settings.json
9. Commit and Push #
cd ~/.local/share/chezmoi
# Add all files
git add .
# Commit
git commit -m "feat: add Claude Code config and skills"
# Push
git push -u origin main
10. Advanced: Different Configs for Different Machines #
If your server needs extra skills that your laptop doesn’t, use templates.
10.1 Check Each Machine’s Hostname #
Run on each machine:
hostname
Note them down, e.g.:
- MacBook:
my-macbook.local - Mac Mini 1:
my-mini-1.local - Mac Mini 2:
my-mini-2.local
10.2 Convert External Config to Template #
# Rename to template file
mv ~/.local/share/chezmoi/.chezmoiexternal.toml \
~/.local/share/chezmoi/.chezmoiexternal.toml.tmpl
10.3 Edit Template #
cat > ~/.local/share/chezmoi/.chezmoiexternal.toml.tmpl << 'EOF'
# ============================================
# Skills for all machines
# ============================================
[".claude/skills/humanizer"]
type = "archive"
url = "https://github.com/blader/humanizer/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
[".claude/skills/gstack"]
type = "archive"
url = "https://github.com/garrytan/gstack/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
# ============================================
# Skills only for Mini 1 (main dev machine)
# ============================================
{{ if eq .chezmoi.hostname "my-mini-1.local" }}
[".claude/skills/frontend-slides"]
type = "archive"
url = "https://github.com/zarazhangrui/frontend-slides/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
{{ end }}
# ============================================
# Skills only for Mini 2 (server)
# ============================================
{{ if eq .chezmoi.hostname "my-mini-2.local" }}
[".claude/skills/server-monitoring"]
type = "archive"
url = "https://github.com/xxx/server-monitoring/archive/main.tar.gz"
stripComponents = 1
refreshPeriod = "168h"
{{ end }}
EOF
Template syntax:
{{ if eq .chezmoi.hostname "xxx" }}— If hostname equals xxx{{ end }}— End condition- Can also use
{{ if contains .chezmoi.hostname "mini" }}for fuzzy matching
10.4 Verify Template #
# See what renders for current machine
chezmoi execute-template < ~/.local/share/chezmoi/.chezmoiexternal.toml.tmpl
11. One-Command Setup for New Machines #
This is the best part — new machines need just two steps:
Public Repository #
# 1. Install chezmoi
brew install chezmoi # or sh -c "$(curl -fsLS get.chezmoi.io)"
# 2. One-command init (replace with your GitHub username)
chezmoi init yourusername/dotfiles --apply
Private Repository #
# Need SSH URL
chezmoi init [email protected]:yourusername/dotfiles.git --apply
After completion, you automatically get:
- ✅
~/.claude/CLAUDE.mdglobal config - ✅
~/.claude/settings.jsonplugin settings - ✅ All configured GitHub skills
- ✅ Marketplace plugins install when Claude Code first launches
12. Daily Maintenance Commands #
# Check status (local vs chezmoi source)
chezmoi status
# View diff
chezmoi diff
# Apply updates (source → target)
chezmoi apply
# Pull from remote + apply
chezmoi update
# Force refresh all external skills
chezmoi apply --refresh-externals
# Add new file to chezmoi
chezmoi add ~/.claude/newfile
# Edit file in chezmoi (opens editor)
chezmoi edit ~/.claude/CLAUDE.md
# Apply after editing
chezmoi apply
13. FAQ #
Q1: chezmoi apply permission error #
Cause: Target file is locked by Claude Code
Solution: Close Claude Code and retry
# Or force overwrite
chezmoi apply --force
Q2: External skills not updating #
Cause: Haven’t reached refreshPeriod (default 7 days)
Solution: Force refresh
chezmoi apply --refresh-externals
Q3: Can’t pull private repository #
Cause: Using HTTPS without authentication
Solution: Use SSH
chezmoi init [email protected]:yourusername/dotfiles.git --apply
Q4: Hostname not matching #
Cause: Some systems have .local suffix, some don’t
Solution: Use contains instead of eq
{{ if contains .chezmoi.hostname "mini" }}
...
{{ end }}
Q5: Changed config locally, how to sync back to chezmoi? #
Method 1: Re-add
chezmoi add ~/.claude/CLAUDE.md
Method 2: Edit chezmoi source directly
chezmoi edit ~/.claude/CLAUDE.md
# After editing
chezmoi apply
Q6: Marketplace plugins not auto-installing #
This is expected. Marketplace plugins (like obsidian, frontend-design) are stored in settings.json, but actual plugins download when Claude Code launches.
chezmoi only syncs settings.json; plugin download is Claude Code’s job.
14. Complete Config Reference #
Directory Structure #
~/.local/share/chezmoi/
├── .chezmoiignore # Ignore rules
├── .chezmoiexternal.toml.tmpl # External skills config (template)
├── private_dot_claude/
│ ├── CLAUDE.md # Global instructions
│ └── settings.json # Plugin config
└── README.md # Optional: documentation
settings.json Example #
{
"enabledPlugins": {
"obsidian@obsidian-skills": true,
"frontend-design@claude-plugins-official": true
},
"extraKnownMarketplaces": {
"claude-plugins-official": {
"source": {
"source": "github",
"repo": "anthropics/claude-plugins-official"
}
}
}
}
CLAUDE.md Example #
# Python Web Backend Rules
## Environment
- Use uv for dependency management
- Use .venv/ virtual environment
- Run commands with uv run
## Project Structure
app/
__init__.py
routes.py
models.py
main.py
tests/
## Common Commands
- Start server: uv run uvicorn app.main:app --reload
- Run tests: uv run pytest
- Format: uv run ruff format .
15. Summary #
| Pain Point | Solution |
|---|---|
| Multi-machine config inconsistency | chezmoi unified management, Git sync |
| Manual skill installation tedious | External auto-pulls from GitHub |
| Different machines need different configs | Template syntax with hostname conditions |
| New machine setup time-consuming | chezmoi init --apply one command |
| Manual skill updates | refreshPeriod auto-checks |
One-line summary:
Dotfiles manager + GitHub = Ultimate sync solution for Claude Code config
Appendix: Recommended Claude Code Skills #
| Skill | Purpose | GitHub |
|---|---|---|
| gstack | Simulate full engineering team (CEO/Designer/QA) | garrytan/gstack |
| humanizer | Remove AI-generated traces | blader/humanizer |
| marketingskills | CRO/SEO/copywriting/growth (34 skills) | coreyhaines31/marketingskills |
| frontend-slides | Create animated HTML presentations | zarazhangrui/frontend-slides |
| baoyu-skills | Baoyu’s skill pack (translation, WeChat publishing, etc.) | JimLiu/baoyu-skills |
Beyond Claude Code #
chezmoi can manage far more than Claude Code config. The same approach works for:
- zshrc / bashrc — Your shell config
- git config — Global Git settings
- SSH config — Server connection config
- Vim / Neovim — Editor config
- tmux — Terminal multiplexer config
- Any other dotfiles
Once you start using chezmoi, you’ll never go back to manually copying configs.
The Lazy Way #
If you don’t want to configure step by step, just throw this article to your Claude Code or OpenClaw and let AI handle it:
“Help me configure chezmoi following this tutorial to sync my Claude Code config to GitHub.”
AI will help you create the repo, add configs, set up externals — you just need to confirm at the end.
If this article helped you, feel free to share it with friends who also use Claude Code.