Skip to content

Instantly share code, notes, and snippets.

@rymiwe
Last active April 7, 2026 15:01
Show Gist options
  • Select an option

  • Save rymiwe/2e5b940ae1ba981551450d318a2ee6c5 to your computer and use it in GitHub Desktop.

Select an option

Save rymiwe/2e5b940ae1ba981551450d318a2ee6c5 to your computer and use it in GitHub Desktop.
Claude Code config backup with chezmoi - auto-sync settings, agents, rules across machines

Claude Code Config Backup

Automatically backup your Claude Code configuration to a private GitHub repo using chezmoi. Your settings, agents, rules, and project configs are version-controlled and synced across machines.

What you get:

  • Auto-backup of memory files, rules, settings, agents, and skills
  • Auto-push to your dotfiles repo via chezmoi's native autoPush
  • Auto-pull on session start to keep multi-machine setups in sync
  • Restore your full setup on any machine with two commands

How This Aligns with Claude Code Conventions

This setup follows the Claude Code memory hierarchy:

Memory Type Location Backed Up
User memory ~/.claude/CLAUDE.md Yes
User rules ~/.claude/rules/*.md Yes
Project memory ./CLAUDE.md or ./.claude/CLAUDE.md Yes (if not git-tracked)
Project local ./CLAUDE.local.md Yes
Project config ./.claude/ (agents, skills, settings) Yes

What Gets Backed Up

Chezmoi manages files at their real paths — no intermediate directories or sync scripts needed.

Global (~/.claude/):

  • CLAUDE.md — user-level memory
  • rules/ — user-level rules (supports subdirectories)
  • settings.json, settings.local.json — app settings and hooks
  • agents/, plans/ — custom agents and plans

Per-project (project/.claude/):

  • agents/, skills/ — project-specific agents and auto-loaded skills
  • settings.local.json — project hooks and permissions
  • CLAUDE.local.md — personal project overrides (root level, gitignored)

Prerequisites

  • chezmoi installed
  • A private GitHub repo for your dotfiles
  • Claude Code installed

Setup

  1. Install chezmoi (if not already):

    sh -c "$(curl -fsLS get.chezmoi.io)"
  2. Initialize your dotfiles repo:

    chezmoi init your-github-username
  3. Enable autoCommit and autoPush — create ~/.config/chezmoi/chezmoi.toml:

    [git]
        autoCommit = true
        autoPush = true

    Note: chezmoi does not have a native autoPull. The SessionStart hook (step 6) handles pulling at session start instead.

    To track this config in chezmoi itself (since chezmoi add won't accept its own config file):

    cp ~/.config/chezmoi/chezmoi.toml ~/.local/share/chezmoi/.chezmoi.toml
    cd ~/.local/share/chezmoi && git add .chezmoi.toml && git commit -m "Add chezmoi config" && git push
  4. Add your config files to chezmoi:

    # Global settings
    chezmoi add ~/.claude/CLAUDE.md
    chezmoi add ~/.claude/settings.json
    chezmoi add ~/.claude/settings.local.json
    chezmoi add ~/.claude/rules/
    
    # Per-project (repeat for each project)
    chezmoi add ~/code/my-project/.claude/settings.local.json
    chezmoi add ~/code/my-project/.claude/agents/
    chezmoi add ~/code/my-project/.claude/skills/
  5. Add the session sync script — save chezmoi-session-sync to ~/.local/bin/ and make it executable:

    mkdir -p ~/.local/bin
    # Copy chezmoi-session-sync to ~/.local/bin/chezmoi-session-sync
    chmod +x ~/.local/bin/chezmoi-session-sync
    chezmoi add ~/.local/bin/chezmoi-session-sync
  6. Add hooks — merge settings-hooks-snippet.json into ~/.claude/settings.local.json (update the SessionStart command path to your absolute home directory)

How It Works

  1. SessionStart hook: On session start/resume, runs chezmoi update --force to pull latest configs from remote — chezmoi has autoPush but no native autoPull, so this fills the gap
  2. PostToolUse hook: When you edit .claude/ or CLAUDE.md files, runs chezmoi add "$file"
  3. Stop hook: When Claude session ends, runs chezmoi re-add to catch any missed changes
  4. chezmoi autoCommit + autoPush: Automatically commits and pushes after each chezmoi add
  5. flock: Prevents concurrent backup runs from conflicting

The SessionStart hook uses a small script (~/.local/bin/chezmoi-session-sync) that handles three cases: clean pull (silent), rebase conflict (blocks session with resolution steps), and network failure (warns but doesn't block).

New Machine Setup

# 1. Clone your projects first (if managing project configs)
git clone https://github.com/you/my-app.git ~/code/my-app

# 2. Install chezmoi and apply
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply your-github-username

This restores everything: global configs work immediately, project .claude/ folders are placed inside already-cloned repos. The .chezmoi.toml in the repo automatically configures autoCommit and autoPush.

Daily Usage

Auto-backup handles everything. For manual operations:

# Add a new file to chezmoi tracking
chezmoi add ~/code/my-project/.claude/agents/new-agent/AGENT.md

# Re-sync all managed files
chezmoi re-add

# Pull latest configs from another machine
chezmoi update

What's NOT Backed Up

  • ~/.claude/debug/, cache/, projects/ — session data
  • ~/.claude/history.jsonl — command history
  • ~/.claude/credentials.json — auth tokens (sensitive)
  • ~/.claude/plugins/ — downloaded on install, regenerable
#!/bin/bash
# Sync chezmoi configs at Claude Code session start.
# Blocks on conflict; warns on network/other failures.
command -v chezmoi >/dev/null 2>&1 || exit 0
# Detect stale rebase from previous failed sync
if chezmoi git -- status 2>&1 | grep -q "rebase in progress"; then
echo "[chezmoi-sync] Previous rebase still in progress" >&2
echo " To abort: chezmoi git -- rebase --abort" >&2
echo " To continue: chezmoi git -- rebase --continue" >&2
exit 1
fi
output=$(chezmoi update --force 2>&1)
[ $? -eq 0 ] && exit 0
# Conflict vs network failure
if echo "$output" | grep -qi -e "conflict" -e "could not apply" -e "rebase"; then
echo "[chezmoi-sync] Conflict detected:" >&2
echo "$output" >&2
echo "Resolve: chezmoi git -- status" >&2
echo "Skip: chezmoi git -- rebase --abort" >&2
exit 1
fi
echo "[chezmoi-sync] chezmoi update failed (network?), skipping" >&2
exit 0
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "/home/YOU/.local/bin/chezmoi-session-sync",
"timeout": 15000
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo \"$CLAUDE_TOOL_INPUT\" | grep -qE 'rm -rf|rm -r [^-]|rm .* \\*|rm .* \\.\\*|git clean -fd|git reset --hard' && echo 'BLOCKED: Dangerous destructive command detected.' >&2 && exit 2 || true"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "file=$(echo \"$CLAUDE_TOOL_INPUT\" | jq -r '.file_path // empty'); test -n \"$file\" && (echo \"$file\" | grep -qE 'CLAUDE\\.md$|CLAUDE\\.local\\.md$|\\.claude/' && flock -w 5 ~/.claude-backup.lock -c \"chezmoi add \\\"$file\\\"\" >/dev/null 2>&1 &); true"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "flock -w 5 ~/.claude-backup.lock -c 'chezmoi re-add' >/dev/null 2>&1 &"
}
]
}
]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment