Skip to content

About

Rebuild files Claude Code's /tmp scratchpad lost at reboot, by replaying the session transcripts

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

7 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

claude-code-temp-file-recovery

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.

What happened

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".

Do this now

  1. 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
  2. Back up your transcripts before anything else deletes them:

    cp -R ~/.claude/projects ~/claude-transcripts-backup-$(date +%Y%m%d)
  3. Stop Claude Code deleting transcripts after 30 days. In ~/.claude/settings.json, set cleanupPeriodDays to 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.

Install

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 --help

Or 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.

Usage

Find the sessions that used a scratchpad:

cc-recover list
cc-recover list --since 2026-10-01

This 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-run

Rebuild 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 ~/rescued

Or 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.

What you get

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 -n or sed -n of 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.

How it works

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, Edit and MultiEdit calls (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 - <<EOF and python3 -c scripts that only read and write files
  • sed -i
  • cp, mv, rm, mkdir and touch inside 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.

Safety

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.

What it cannot recover

  • 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 cleanupPeriodDays or by hand.
  • Files that only existed outside the scratchpad. This tool only rebuilds the scratchpad.

Stop it happening again

  • 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 cleanupPeriodDays high and back up ~/.claude/projects now 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.py is a short PreToolUse hook that refuses Write/Edit calls, 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.

Tests

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.

License

MIT. See LICENSE.

About

Rebuild files Claude Code's /tmp scratchpad lost at reboot, by replaying the session transcripts

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages