Your ~/.claude folder quietly accumulates two very different things: configuration you'd hate to lose, and private data you must never publish. Here's how to put the first under git without ever committing the second.
This reflects Claude Code's directory layout as of mid-2026. The tool evolves quickly — check the current documentation before trusting any file list, including this one.
Three kinds of files live in ~/.claude
Claude Code — Anthropic's command-line interface (CLI) coding agent — keeps all of its user-level state in one folder in your home directory. Everything in ~/.claude falls into one of three buckets: hand-crafted configuration, regenerable machine state, and private conversation data — and only the first bucket belongs in git.
- Hand-crafted configuration — files you wrote: your global
CLAUDE.mdinstructions,settings.json, custom skills, agents, and rules. Small, valuable, and painful to reconstruct from memory. - Regenerable machine state — caches, installed plugins, session bookkeeping. Losing it costs nothing; Claude Code rebuilds it on the next run.
- Private conversation data — full transcripts of every session, your complete prompt history, snapshots of your shell environment. This is the sensitive bucket: transcripts routinely contain pasted code, file contents, and the occasional secret that went through the chat.
The sorting rule fits in one decision tree:
The trouble is proportions. On a machine that's been running Claude Code for a year, the config bucket is a handful of small text files, while the other two buckets easily run to hundreds of megabytes. A naive git add . would drown the valuable 1% in the radioactive 99% — which is why the setup below inverts the usual gitignore logic.
Why put it under version control
The case for versioning the config bucket is the same as for any dotfiles:
- You can't un-break what you can't diff. Claude Code itself edits
settings.json(permission grants, plugin toggles), and a behavior change is much easier to trace withgit diffthan by staring at a JavaScript Object Notation (JSON) file trying to remember what it looked like last week. - Skills and agents are code you wrote. A custom skill is a small program; losing it to a disk failure or an overzealous cleanup hurts exactly like losing any other uncommitted code.
- History doubles as documentation. Commit messages on your
CLAUDE.mdrecord why you added an instruction, which the file alone never tells you. - Migration becomes trivial. A new laptop gets your whole Claude Code personality from one
git clone.
The mistake is not versioning too little of ~/.claude — it's versioning too much of it. The value is concentrated in a few kilobytes of text; everything else is either noise or a liability.
What's worth tracking
Here is the folder's inventory, sorted by verdict. Paths marked Optional are worth committing if you use those features; the call is yours.
| Path | What it is | Version it? |
|---|---|---|
CLAUDE.md | Your global instructions, loaded into every session | |
settings.json | Permissions, status line, model, plugins — user settings for all projects | |
skills/ | Custom skills you authored | |
agents/ | Custom subagent definitions | |
rules/ | User-level rules applied to every project | |
keybindings.json | Custom keyboard shortcuts | |
plans/ | Plan-mode documents from past sessions | |
projects/*/memory/ | Auto-memory notes Claude keeps per project | |
projects/*/*.jsonl | Full conversation transcripts, per session | |
history.jsonl | Every prompt you have ever typed | |
shell-snapshots/, session-env/ | Captured shell state, including environment variables | |
file-history/, paste-cache/, tasks/ | Edit backups and clipboard/session bookkeeping | |
cache/, plugins/, backups/, stats-cache.json | Regenerable machine state; plugins reinstall themselves |
The whole "yes" column together is usually smaller than a single screenshot — a few dozen kilobytes of markdown and JSON. That's the entire payload worth protecting.
What must never be committed
The "Never" rows deserve more than a table cell, because the failure mode isn't clutter — it's disclosure.
Transcripts (projects/*/*.jsonl) are verbatim records of your sessions: every file Claude read, every diff it wrote, every error message, and everything you pasted in — which, sooner or later, includes an access token, a customer email, or proprietary code from work. history.jsonl is a searchable log of every prompt you've typed across all projects. shell-snapshots/ captures your shell environment, and environment variables are where secrets traditionally live. Committing any of these turns a private working directory into a permanent, distributed record — and git's whole design makes that record very hard to truly delete later.
Two more traps sit just outside the obvious list:
~/.claude.json— a sibling file, not inside the folder — holds your OAuth session (the token-based login standard) and Model Context Protocol (MCP) server configuration. It's outside a repo rooted at~/.claude, so a repo there can't accidentally include it — but don't be tempted to symlink or copy it in.- Future files. Claude Code adds new state directories over time. A conventional blocklist gitignore silently starts committing whatever appears next; the allowlist below fails safe instead.
The allowlist .gitignore
The safe pattern is default-deny: ignore everything, then explicitly re-include the handful of files you actually want. Anything Claude Code invents in a future release is ignored until you deliberately opt it in.
Create ~/.claude/.gitignore:
# Ignore everything by default…
/*
# …then allowlist the hand-crafted config
!/.gitignore
!/CLAUDE.md
!/settings.json
!/skills/
!/agents/
!/rules/
!/keybindings.json
!/plans/
# Optional: keep per-project auto-memory, without the transcripts
!/projects/
/projects/*/*
!/projects/*/memory/
The projects/ block is the only subtle part, and it exists because of a documented gitignore rule: it is not possible to re-include a file if a parent directory of that file is excluded. You can't just write !/projects/*/memory/ on its own — while projects/ is excluded by /*, git never looks inside it, so the negation would match nothing. The three lines work as a chain: re-include projects/ itself, exclude everything two levels down, then re-include just the memory/ directories. Drop the block entirely (and the !/plans/ line) if you'd rather keep the repo to pure config.
Then initialize and verify — the verification step is the one that matters:
cd ~/.claude
git init
git add -A
git status
Before committing, confirm the staging area contains only small text files: no .jsonl, nothing from cache/ or shell-snapshots/. Two quick checks make it certain:
git ls-files # should list only your allowlisted files
git status --ignored --short | head # transcripts and caches show as ignored (!!)
If the list looks right, commit. From then on it's an ordinary repo: change a setting, commit it; write a skill, commit it.
If you push it anywhere, keep it private
A local repo already delivers most of the value — diffs, history, recoverability. If you also want off-machine backup, push it to a private remote only. Even the "safe" files reveal more than you'd guess: settings.json exposes your tooling and permission choices, plans and memory files reference internal project names, and your CLAUDE.md describes how you work. None of it is a secret in the credential sense, but none of it is a public artifact either — treat the repo like a diary with an index, not like open-source code.
With that one rule respected, the payoff is a config folder that behaves like the rest of your codebase: every change reviewed, every experiment reversible, and a year of accumulated Claude Code tuning safe in a handful of kilobytes.
