Rebuilds files that were lost from Claude Code's session scratchpad, by replaying the file-writing steps recorded in the session transcripts.
If a restart wiped files that Claude wrote into its scratchpad, and the session transcripts are still on disk, this tool can usually get most of the text files back.
Claude Code gives each session a scratchpad folder for temporary files:
/tmp/claude-<uid>/<project>/<session-id>/scratchpad/ (on macOS: /private/tmp/...)
/tmp is temporary storage. macOS empties it when the machine restarts, and many Linux
systems do the same. Anything kept only in the scratchpad (scripts, drafts, whole working
copies of a project) is deleted at the next restart.
The transcripts survive the restart. Each session is saved as JSON lines under
~/.claude/projects/<project>/<session-id>.jsonl, with subagents under
<session-id>/subagents/. They record every tool call: Write calls with the full file
content, Edit calls with the old and new text, and Bash commands with their output. Replaying
those steps in order rebuilds the files.
The transcripts do not last forever either. Claude Code deletes transcripts older than
cleanupPeriodDays (30 days by default). Once they are gone, so is any chance of recovery.
For background, see the feature request anthropics/claude-code#21248, "Scratchpad should persist beyond session and be user-accessible by default".
-
If you have not restarted yet, the scratchpad still exists. Copy it; a copy is better than any rebuild:
cp -R /private/tmp/claude-$(id -u) ~/scratchpad-backup-$(date +%Y%m%d) # macOS cp -R /tmp/claude-$(id -u) ~/scratchpad-backup-$(date +%Y%m%d) # Linux
-
Back up your transcripts before anything else deletes them:
cp -R ~/.claude/projects ~/claude-transcripts-backup-$(date +%Y%m%d)
-
Stop Claude Code deleting transcripts after 30 days. In
~/.claude/settings.json, setcleanupPeriodDaysto a large number (merge it into the file if you already have settings):{ "cleanupPeriodDays": 3650 }Do not set it to 0: that does not mean "never delete".
Transcripts contain everything from your sessions, including file contents and command output. Keep the backups private.
You need Python 3.10 or newer. There are no other dependencies.
git clone https://github.com/MsFixer101/claude-code-temp-file-recovery.git
cd claude-code-temp-file-recovery
python3 -m cc_recover --helpOr install the cc-recover command with pipx install . (or pip install .).
The examples below use cc-recover. Without installing, use
python3 -m cc_recover from the repository folder instead.
Find the sessions that used a scratchpad:
cc-recover list
cc-recover list --since 2026-10-01This prints each session's id, project, first and last activity, an approximate count of files it wrote to its scratchpad, and whether that scratchpad still exists on disk. If it does, copy it instead.
See what a rescue would do, without writing anything:
cc-recover --session 1a2b3c4d --dry-runRebuild one or more sessions (an id prefix is enough if it is unique):
cc-recover --session 1a2b3c4d --out ~/rescued
cc-recover --session 1a2b3c4d --session 5e6f7a8b --out ~/rescuedOr every session active in a date range:
cc-recover --since 2026-10-10 --until 2026-10-17 --out ~/rescued
cc-recover --since 2026-10-10 --project my-app --out ~/rescued--out must be a new or empty folder, and not under /tmp (it would be wiped too).
A scratchpad often outlives the session that made it: a later session (a resumed one, or
one you pointed at the same folder) may keep editing it. With --session, the tool also
finds every other session, in any project, whose tool calls touched that scratchpad, and
replays them all together in time order. RECOVERY.md lists them under "Also replayed". Use
--no-related to replay only the sessions you named. With --since/--until, make the date
range cover all of those sessions.
Other options:
| option | effect |
|---|---|
--projects-dir DIR |
where transcripts are (default ~/.claude/projects, or $CLAUDE_CONFIG_DIR/projects) |
--project TEXT |
only project folders whose name contains TEXT. Folder names start with - (for example -home-me-my-app), so write --project=-home-me-my-app or use a part without the leading dash. |
--copy-outside |
let steps copy or read files from outside the scratchpad. They get today's version of those files, not the one from back then, so the result is marked partial. |
--allow-unsandboxed |
on systems without sandbox-exec (anything but macOS), run sed -i, python edit steps and text filters anyway. See Safety. |
rescued/
RECOVERY.md the report: every file, its status, what failed, what is lost
replay-log.tsv every decision the replay made, one per line
<session-id>/... the rebuilt files, at their paths inside that scratchpad
_previews/... images the model looked at, if any (see below)
Every rebuilt file gets one of three statuses:
- checkpoint-verified: after its last change, the file matched a full printout of it in
the transcript (the Read tool, or a Bash
cat,cat -norsed -nof the whole file). It is what the file held at that moment. - replayed-unverified: every step that built it replayed cleanly, but the transcript never printed the whole file after its last change. Usually right; check it.
- partial: something was missed. An edit's anchor text was not found, a step could not be replayed, or content came from outside the scratchpad. The notes in RECOVERY.md say what happened. Treat it as a draft.
When the rebuilt file and a full printout disagree, the printout wins: it is a record of what the file actually held.
The tool reads the tool calls that mention a scratchpad, from the main transcript and its
subagents, and replays them in time order into --out. Scratchpad paths are rewritten to point
there. It replays only steps that create or change files:
Write,EditandMultiEditcalls (skipping any that failed in the session)- Bash heredocs and redirects (
cat > file <<'EOF',echo ... >> file,tee), including paths built from simple shell variables (D=...; cat > "$D/x") python3 - <<EOFandpython3 -cscripts that only read and write filessed -icp,mv,rm,mkdirandtouchinside the scratchpad
It never runs any other command from a transcript. node, npm, ffmpeg, git, curl,
script files (python3 build.py), loops over command output and so on are logged as "not
replayed". Their effects are lost, and the report says so.
Bash commands are parsed by a small built-in parser, and the replay itself happens in Python:
assignments, cd, echo, printf, cat, tests and file operations are done directly,
without a shell. A command it cannot parse is skipped and listed in the report.
The only programs the replay starts are sed (for sed -i), Python (for edit scripts that
pass the checks below) and read-only text tools such as grep or sort when their output
goes into a rebuilt file.
- A python script is replayed only if it imports nothing outside a short list of standard modules, writes at least one file, and uses none of a list of names that can start processes, send signals, create links or reach Python's builtins. Anything else (numpy, PIL, subprocess, requests...) is skipped. This check is a filter, not a guarantee.
- On macOS every subprocess runs under
sandbox-exec: file writes are allowed only inside--out, there is no network access, and it cannot start other programs or signal other processes. Each one is limited to 30 seconds and 20 seconds of CPU. - cc-recover itself only writes inside
--out, and refuses to write through links. Steps that wrote elsewhere are logged and skipped. - On other systems there is no sandbox, so
sed -i, python steps and text filters are skipped unless you pass--allow-unsandboxed. With that flag, python scripts that mention a path outside the scratchpad, or build paths (os.path.join,.., the home folder, environment variables), are still refused, and GNU sed runs with--sandbox. Beyond that, nothing stops a step writing elsewhere, so read the scripts in your transcript first if you are unsure.
Replay on the same kind of system the session ran on, because sed -i syntax differs between
macOS and Linux.
- Anything a program produced. Renders, builds, downloads, generated data, and the output of any command that was not replayed. The transcript has the command, not its result. These are listed in RECOVERY.md.
- Media and binary files (video, audio, images, model weights, archives). One partial
exception: when the model looked at an image with the Read tool, the transcript kept a copy.
Those are saved under
_previews/, but they are usually re-encoded and scaled down. - Files changed by skipped steps. If a skipped script or command edited a file, later
steps may not apply cleanly. Those files are marked
partial. - Sessions whose transcripts were deleted, by
cleanupPeriodDaysor by hand. - Files that only existed outside the scratchpad. This tool only rebuilds the scratchpad.
-
Keep real work in a project folder, under git, and commit often. The scratchpad is for throwaway files. If something matters, ask Claude to put it in the project, or move it there yourself before the session ends.
-
Keep
cleanupPeriodDayshigh and back up~/.claude/projectsnow and then, with whatever backs up the rest of your home folder. -
Optionally, block code files in the scratchpad with a hook.
examples/block-scratchpad-code.pyis a shortPreToolUsehook that refusesWrite/Editcalls, and Bash redirects that spell out the path, when they would put a code file (.py,.js,.sh, ...) in the scratchpad. Claude sees the message and writes the file somewhere else. Copy it to~/.claude/hooks/and add this to~/.claude/settings.json:{ "hooks": { "PreToolUse": [ { "matcher": "Write|Edit|MultiEdit|NotebookEdit|Bash", "hooks": [ { "type": "command", "command": "python3 ~/.claude/hooks/block-scratchpad-code.py" } ] } ] } }It does not catch everything (a Bash command that builds the path in a variable gets through), so it is a guard rail, not a guarantee. Git is the real fix.
python3 -m unittest discover -s tests -t .The tests build a made-up session (random id, fake paths) that writes, edits and copies files with every supported kind of step, replay it, and compare the rebuilt files byte for byte.
MIT. See LICENSE.