Files
claudetools/.claude/RECOVERY.md
Mike Swanson eed3ece2c7 feat: session recovery toolset (orphan detector + /recover)
Reconstructs session logs from Claude Code transcripts when a session
crashes or is closed before /save. Two entry points:

- /recover <uuid|latest> : manual, Claude-reviewed reconstruction
- detect_orphaned_sessions.py : scheduled scan that auto-builds logs for
  substantive, unsaved, not-yet-recovered transcripts (banner-marked
  RECOVERED-UNVERIFIED), commits them, and posts a #bot-alerts FYI.

recover_session.py is the shared engine: Python extracts the verbatim
command/config/reference timeline; Ollama drafts prose-only narrative.
Machine-local ledger (.claude/state/) prevents reprocessing. Reviewed:
git add scoped to own files, ledger written only after successful push,
per-uuid idempotency, --max cap for unattended runs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 18:33:07 -07:00

4.6 KiB

Session Recovery

Never lose work again when a Claude Code session crashes or is closed before /save.

Claude Code writes every session live to a transcript JSONL. This toolset distills those transcripts back into normal session logs in the .claude/commands/save.md format.


The three pieces

Piece File Role
Engine .claude/scripts/recover_session.py Parses one transcript, classifies it, and reconstructs a full session log. CLI: --uuid / --latest / --path with --print (default), --auto, or --json.
Detector .claude/scripts/detect_orphaned_sessions.py Scans all idle transcripts, auto-recovers the orphans (substantive + unsaved), updates the ledger, commits + pushes, and posts an FYI to #bot-alerts. CLI: --dry-run, --idle-min N, --no-commit, --no-alert.
Command .claude/commands/recover.md /recover <uuid> / /recover latest / /recover --list — the manual, reviewed path where Claude edits the draft before writing.

The scheduled-task registration script .claude/scripts/register-orphan-detector.ps1 wires the detector into the Windows Task Scheduler (Windows only).


Where things live

  • Transcripts: ~/.claude/projects/<slug>/<uuid>.jsonl, where <slug> is the claudetools repo root with /, \, and : each replaced by -. On a D:\claudetools machine the slug is D--claudetools, so C:\Users\<you>\.claude\projects\D--claudetools\*.jsonl. The slug is computed portably from claudetools_root in .claude/identity.json. Sibling <uuid>/ dirs hold subagent transcripts and are ignored for the main narrative.
  • Ledger: .claude/state/recovered-sessions.json (machine-local, gitignored). Records every processed uuid with its verdict (recovered / skipped-saved / skipped-trivial / error) so it is never re-scanned. Transcripts are per-machine, so the ledger is too.

How to run

# See candidate orphans without writing anything:
py .claude/scripts/detect_orphaned_sessions.py --dry-run

# Inspect one transcript's verdict as JSON (writes nothing):
py .claude/scripts/recover_session.py --json --uuid <uuid>

# Print a reconstructed log to stdout (writes nothing):
py .claude/scripts/recover_session.py --uuid <uuid> --print

# Full unattended run (writes logs, updates ledger, commits, pushes, alerts):
py .claude/scripts/detect_orphaned_sessions.py

Register the scheduled task (Windows)

powershell -ExecutionPolicy Bypass -File D:\claudetools\.claude\scripts\register-orphan-detector.ps1

Registers ClaudeTools - Orphaned Session Detector: runs at logon and every 4 hours. The 4-hour cadence pairs with the detector's 90-minute idle gate so an active session is never grabbed mid-flight.


Accuracy split: Ollama prose vs Python verbatim

This is the core design principle.

  • Ollama drafts prose only — Session Summary, Key Decisions, Problems Encountered, Pending / Incomplete Tasks. It never sees and never emits commands, IPs, credentials, file paths, commit SHAs, or ticket IDs. If Ollama is unreachable the log is still produced with a placeholder note in the prose sections.
  • Python extracts the verbatim evidence — Configuration Changes (Write/Edit/NotebookEdit targets), Commands & Outputs (mutating Bash/PowerShell with truncated results), Reference Information (regex-extracted SHAs, URLs, IPs, ticket numbers, coord message ids), and Infrastructure & Servers. This is the high-value, accuracy-critical part and it comes straight from the transcript.

Trust the verbatim sections for facts; treat the prose as a draft.


Classification

  • substantive — the session did real work: a Write/Edit/NotebookEdit, a mutating Bash/PowerShell command (git commit/push/add, ssh, schtasks, New-Item, Set-Content, Remove-Item, Out-File, a POST/PUT/DELETE/PATCH curl, an /api/ call, vault.sh, a mutating Invoke-RestMethod), or a mutating Skill (syncro, rmm, remediation-tool, mailbox, forum-post, syncro-emergency-billing).
  • saved — the session was already saved: a save/scc/checkpoint Skill, or a Write/Edit into a session-logs/ path.
  • orphan = substantive AND not saved. Only orphans are auto-recovered.
  • scope — client / project / general, decided by Python from the transcript text, cwd, and gitBranch against the known client and project slugs. Conservative: ambiguous resolves to general.

Banner discipline

Auto-recovered logs are written with a [RECOVERED -- UNVERIFIED] banner. The banner stays until a human reviews the log and removes it. The manual /recover path lets Claude review and correct the draft before writing, and drops the banner once verified.