How to Back Up Your AI Coding History
Every AI coding tool stores its history somewhere different, in a different format, under different rules — and two of them delete it after 30 days. Here is the complete map, one script that backs all of it up, and an honest account of what a backup does not solve.
Nothing backs up your AI coding history by default. Not your editor, not your operating system's usual backup selection, and not the tools themselves. Two of the most widely used ones actively delete it on a 30-day timer, and most people discover this by looking for something from six weeks ago and finding nothing.
This is the complete map: where each tool keeps its history, what stops it from surviving, and one script that copies all of it. If you only do one thing, run the script at the end.
The two that delete on a timer
These are urgent in a way the others are not, because with them a backup schedule is not enough — you have to turn the deletion off first, and anything already past the horizon is gone.
Claude Code stores conversations as JSONL under ~/.claude/projects/, one directory per project. Retention is cleanupPeriodDays in ~/.claude/settings.json, and that key is absent on a normal install, so the 30-day default applies. Set it explicitly:
// ~/.claude/settings.json
{ "cleanupPeriodDays": 3650 }Gemini CLI stores sessions under ~/.gemini/tmp/<project_hash>/chats/ with checkpoints alongside. Retention lives in settings.json under general.sessionRetention, where maxAge defaults to "30d" and cleanup is enabled. Turn it off:
// ~/.gemini/settings.json
{ "general": { "sessionRetention": { "enabled": false } } }Do both today, on every machine you use. It costs two lines and removes a deadline nobody told you about. Check what survived before you assume you were in time: if nothing in either directory is older than thirty days and you have been using the tools for longer, the cleanup has already run.
Where every tool keeps its history
Paths are macOS/Linux; on Windows substitute %APPDATA% or %USERPROFILE% as appropriate.
- Claude Code — ~/.claude/projects/<encoded-path>/*.jsonl. Plain text, one file per session, deleted after 30 days by default.
- Cursor — ~/Library/Application Support/Cursor/User/globalStorage/state.vscdb. One SQLite file for every conversation, plus a state.vscdb.backup Cursor writes itself, plus per-project state under workspaceStorage/<hash>/.
- GitHub Copilot — ~/Library/Application Support/Code/User/workspaceStorage/<hash>/chatSessions/. JSONL per session, one directory per workspace, where the hash is derived from the project path.
- Codex CLI — ~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl, with session_index.jsonl and a state_N.sqlite thread index beside it. The most complete plain-text record of the group.
- Gemini CLI — ~/.gemini/tmp/<project_hash>/chats/ and checkpoints, plus a shadow git repository at ~/.gemini/history/<project_hash>.
- OpenCode — ~/.local/share/opencode/opencode.db (SQLite, sessions/messages/parts) with a storage/ directory holding session diffs.
- Windsurf — ~/.codeium/cascade/<uuid>.pb and ~/.codeium/chat_state/. Binary protobuf: you can copy it, but you cannot read it outside Windsurf.
- Aider — .aider.chat.history.md inside each project directory. This one is not in your home directory at all, which has a consequence worth spelling out below.
Eight tools, seven locations, five formats, two deletion timers, and one thing in common: none of them puts a copy anywhere else.
Aider deserves the extra sentence. Because its history file lives in the repository rather than your home directory, it is usually in .gitignore — which means it is not committed, not pushed, and not covered by the backup you get for free from having a remote. Deleting the working copy of a repo deletes that history with it.
The script
This copies everything that exists and skips what does not. Two details matter: SQLite databases are copied with sqlite3's own .backup so a live file cannot produce a torn snapshot, and the Cursor index is skipped in favour of the database that actually holds the conversations.
#!/usr/bin/env bash
set -u
DEST="$HOME/Backups/ai-history-$(date +%Y-%m-%d)"
mkdir -p "$DEST"
copy_dir() { [ -e "$1" ] && rsync -a "$1" "$DEST/$2/" 2>/dev/null && echo " saved $2"; }
copy_db() { [ -f "$1" ] && mkdir -p "$DEST/$2" &&
sqlite3 "$1" ".backup '$DEST/$2/$(basename "$1")'" 2>/dev/null &&
echo " saved $2"; }
echo "backing up AI coding history → $DEST"
# plain-text transcripts
copy_dir "$HOME/.claude/projects" claude-code
copy_dir "$HOME/.codex/sessions" codex
copy_dir "$HOME/.gemini/tmp" gemini
copy_dir "$HOME/.codeium/cascade" windsurf
copy_dir "$HOME/.codeium/chat_state" windsurf
# VS Code / Copilot: chat sessions only, not the whole storage tree
rsync -a --prune-empty-dirs \
--include='*/' --include='chatSessions/***' --exclude='*' \
"$HOME/Library/Application Support/Code/User/workspaceStorage/" \
"$DEST/copilot/" 2>/dev/null && echo " saved copilot"
# SQLite databases: consistent copies
copy_db "$HOME/Library/Application Support/Cursor/User/globalStorage/state.vscdb" cursor
copy_db "$HOME/.local/share/opencode/opencode.db" opencode
copy_dir "$HOME/.local/share/opencode/storage" opencode
# Aider lives in the repos themselves
find "$HOME" -maxdepth 4 -name '.aider.chat.history.md' 2>/dev/null |
while read -r f; do
mkdir -p "$DEST/aider"
cp "$f" "$DEST/aider/$(basename "$(dirname "$f")").md"
done
du -sh "$DEST"Save it as backup-ai-history.sh, make it executable, and run it. Then verify what you got — an unverified backup is a hypothesis:
find "$HOME/Backups/ai-history-$(date +%Y-%m-%d)" -type f | wc -l
sqlite3 -readonly "$HOME/Backups/ai-history-$(date +%Y-%m-%d)/cursor/state.vscdb" \
"PRAGMA integrity_check;"Put it on a schedule — cron, launchd, Task Scheduler, whatever you already use — and point the destination at storage that is itself backed up. If you want to know what is currently at risk before you start, promptwake doctor scans for AI coding history across tools and reports what each holds and what falls inside a deletion window. It runs through npx, needs no account, writes nothing and sends nothing anywhere.
What the backup does not solve
Run that script on a schedule and your own history is safe. It is worth being precise about what remains unsolved, because the gap is not one more script.
The copy is on the machine that made it. A failed disk or a developer leaving takes it along with the original, and the offboarding checklist that covers repository access does not cover ~/.claude. Nobody else can read it: a directory of JSONL and SQLite in one person's home folder is not something a colleague will ever open, so there is no shared view of what the team asked the model to build. It is fragmented by design — seven locations and five formats do not become one searchable history because they are in the same tarball. And it is not evidence: a backup on a personal laptop cannot be shown to a customer's security questionnaire asking how AI-generated code is retained and reviewed.
Backing up your AI history is the same move as keeping your code in a folder called src-final-v2. It works, for exactly one person, until it doesn't.
What to do this week
Set the two retention keys today; they are the only part with a deadline. Run the script once by hand to find out how much you actually have — the number is usually larger than people expect, and it is the number that makes the case for treating this as a record rather than a cache.
If the conclusion is that the record belongs to the team, that is what PromptWake does: it reads what these tools already write to disk, keeps prompt, response and the resulting diff locally by default, and on the paid tiers syncs them into one timeline the whole team can search and audit. Set up the script regardless — it costs nothing and the deletion timers do not wait.
