Claude Almanac
Setup

Version-Controlled Claude Code Configuration

Keep Claude Code, VS Code, tmux, Ghostty, and Starship configuration in a git repo with symlinks

โฑ 10 min๐Ÿ“Š beginner๐Ÿ‘ค Alexander Sivura
Prerequisites:gitClaude Code installed
Outcome: A git repository managing your full Claude Code environment (settings, tmux, Ghostty, VS Code) via symlinks

Version-Controlled Claude Code Configuration

Keep your Claude Code configuration under version control so it's backed up, portable across machines, and auditable through git history.

The Problem

Claude Code stores configuration in ~/.claude/ -- settings, global instructions, rules, skills, and hooks. These files accumulate over time and represent significant investment. But they're scattered across your home directory with no backup, no history, and no way to sync across machines.

The same applies to the rest of your Claude Code environment: VS Code settings, tmux configuration (including agent teams focus protection hooks), Ghostty terminal config, and Starship prompt. These tools work together, and losing any piece means re-discovering settings you already dialed in.

The Pattern

Store everything in a git repo. Symlink from the expected locations back to the repo. Edit in one place, commit changes, push to sync.

~/Developer/repos/dotfiles-claude/     (git repo, source of truth)
  claude-home/
    settings.json     โ† ~/.claude/settings.json
    CLAUDE.md         โ† ~/.claude/CLAUDE.md
    rules/            โ† ~/.claude/rules/
    skills/           โ† ~/.claude/skills/
    hooks/            โ† ~/.claude/hooks/
  vscode/
    settings.json     โ† ~/Library/Application Support/Code/User/settings.json
    keybindings.json  โ† ~/Library/Application Support/Code/User/keybindings.json
  tmux/
    .tmux.conf        โ† ~/.tmux.conf
  ghostty/
    config            โ† ~/.config/ghostty/config
  starship/
    starship.toml     โ† ~/.config/starship.toml
  scripts/
    ghostty-claude.sh   (launcher, referenced by VS Code task)
    tmux-retry-teammate.sh (teammate spawn retry, referenced by tmux hooks)
  setup.sh            (creates all symlinks)

Arrows show symlink direction: the files in ~/.claude/, ~/.config/, etc. are symlinks pointing to the repo.

The scripts/ directory isn't symlinked anywhere -- scripts are referenced by absolute path from VS Code tasks and tmux hooks.

Step 1: Create the Repo

mkdir -p ~/Developer/repos/dotfiles-claude/{claude-home,vscode,tmux,ghostty,starship,scripts}
cd ~/Developer/repos/dotfiles-claude
git init

Step 2: Move Existing Config into the Repo

Copy your current config files into the repo:

# Claude Code
cp ~/.claude/settings.json claude-home/
cp ~/.claude/CLAUDE.md claude-home/ 2>/dev/null
cp -r ~/.claude/rules claude-home/ 2>/dev/null
cp -r ~/.claude/skills claude-home/ 2>/dev/null
cp -r ~/.claude/hooks claude-home/ 2>/dev/null

# VS Code (macOS path)
cp ~/Library/Application\ Support/Code/User/settings.json vscode/
cp ~/Library/Application\ Support/Code/User/keybindings.json vscode/

# Terminal tools
cp ~/.tmux.conf tmux/.tmux.conf 2>/dev/null
cp ~/.config/ghostty/config ghostty/config 2>/dev/null
cp ~/.config/starship.toml starship/starship.toml 2>/dev/null

Step 3: Create a Setup Script

Create setup.sh that replaces the originals with symlinks:

#!/bin/bash
set -euo pipefail

REPO_DIR="$(cd "$(dirname "$0")" && pwd)"

link_item() {
  local source="$1"
  local target="$2"

  if [ ! -e "$source" ]; then
    echo "SKIP: $source does not exist"
    return
  fi

  # If target exists and is not a symlink, back it up
  if [ -e "$target" ] && [ ! -L "$target" ]; then
    backup="$target.backup.$(date +%Y%m%d%H%M%S)"
    echo "BACKUP: $target -> $backup"
    mv "$target" "$backup"
  fi

  # If target is an existing symlink, remove it
  if [ -L "$target" ]; then
    rm "$target"
  fi

  ln -s "$source" "$target"
  echo "LINKED: $target -> $source"
}

# --- Claude Code ---
CLAUDE_HOME="$REPO_DIR/claude-home"
CLAUDE_TARGET="$HOME/.claude"

echo "Setting up Claude Code dotfiles..."

for item in settings.json CLAUDE.md rules skills hooks; do
  link_item "$CLAUDE_HOME/$item" "$CLAUDE_TARGET/$item"
done

# --- VS Code (macOS) ---
VSCODE_SOURCE="$REPO_DIR/vscode"
VSCODE_TARGET="$HOME/Library/Application Support/Code/User"

echo "Setting up VS Code dotfiles..."

for item in settings.json keybindings.json; do
  link_item "$VSCODE_SOURCE/$item" "$VSCODE_TARGET/$item"
done

# --- tmux ---
link_item "$REPO_DIR/tmux/.tmux.conf" "$HOME/.tmux.conf"

# --- Ghostty ---
mkdir -p "$HOME/.config/ghostty"
link_item "$REPO_DIR/ghostty/config" "$HOME/.config/ghostty/config"

# --- Starship ---
mkdir -p "$HOME/.config"
link_item "$REPO_DIR/starship/starship.toml" "$HOME/.config/starship.toml"

echo ""
echo "Done. Verify with:"
echo "  ls -la ~/.claude/settings.json ~/.claude/CLAUDE.md ~/.claude/rules"
echo "  ls -la ~/.tmux.conf ~/.config/ghostty/config ~/.config/starship.toml"

Make it executable and run it:

chmod +x setup.sh
./setup.sh

The script is safe to re-run. It backs up any existing non-symlink files with a timestamp before replacing them.

Step 4: Set Up .gitignore

Keep secrets and local-only files out of the repo:

# Claude Code local files (per-session, not portable)
.claude/settings.local.json
.claude/todos.local.json

# Secrets
.env
*.pem
*.key
credentials.json

# macOS
.DS_Store

Note that .claude/settings.local.json is where Claude Code stores per-session permission grants. This file is machine-specific and should not be versioned.

What to Version Control

Claude Code:

FilePurposeVersion control?
settings.jsonPermissions, MCP servers, hooks, env varsYes
CLAUDE.mdGlobal instructions for all projectsYes
rules/Modular global rulesYes
skills/Custom slash commandsYes
hooks/Hook scripts (e.g., context reload)Yes
settings.local.jsonPer-session permission grantsNo
todos.local.jsonSession-local task stateNo
projects/Auto-memory per projectNo (machine-specific)

Terminal tools:

FilePurposeVersion control?
.tmux.conftmux settings, agent teams focus hooksYes
ghostty/configGhostty theme and fontYes
starship.tomlMinimal prompt for agent team panesYes
scripts/Launcher and retry scriptsYes

VS Code:

FilePurposeVersion control?
settings.jsonEditor, extension, theme prefsYes
keybindings.jsonCustom keyboard shortcutsYes

The terminal tools matter for Claude Code because tmux focus protection prevents corrupted teammate spawns, Ghostty is the host terminal, and Starship keeps prompts minimal in agent team panes. See Agent Teams Setup for details on each.

Verification

After running setup.sh, verify the symlinks:

ls -la ~/.claude/settings.json
# lrwxr-xr-x  .../settings.json -> /path/to/dotfiles-claude/claude-home/settings.json

Edit a file in the repo and confirm Claude Code picks up the change immediately (symlinks mean there's no copy step).

Syncing Across Machines

Once the repo is on GitHub (or any remote):

# On a new machine
git clone [email protected]:you/dotfiles-claude.git
cd dotfiles-claude
./setup.sh

The setup script handles everything: backs up existing config, creates symlinks, and you're running with the same configuration.

Next Steps

Sources

On this page