.claude/skills/recover-session/SKILL.md
Recover context from a crashed or unfinished session by reading the most recent JSONL transcript. Use when the user says "/recover", "recover session", "what was I doing", or when /start detects the last entry isn't a finish.
npx skillsauth add sebjacobs/dotfiles recover-sessionInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Retrospective summary from Claude Code's JSONL session transcript. Use after a crash, unexpected exit, or any session that ended without running /finish — reconstructs what happened and writes a recovery entry to the session log so the next session can pick up cleanly.
Determine the project name and branch:
basename "$(git rev-parse --show-toplevel)"
git rev-parse --abbrev-ref HEAD
Check the last session log entry:
jotter tail --project <project> --branch <branch> --limit 1
If the last entry is a finish, the session ended cleanly — nothing to recover. Tell the user and stop.
If the last entry is start, checkpoint, or break (or there are no entries), the previous session likely crashed or the user forgot /finish.
PROJECT_DIR="$HOME/.claude/projects/$(pwd | sed 's|/|-|g')"
ls -lt "$PROJECT_DIR"/*.jsonl | head -5
Show the user the timestamp and first user message from the most recent transcript so they can confirm it's the right session:
LATEST=$(ls -t "$PROJECT_DIR"/*.jsonl | head -1)
stat -f "%Sm" "$LATEST"
python3 -c "
import json, sys
for line in open('$LATEST'):
msg = json.loads(line)
if msg.get('type') == 'user':
content = msg.get('message', {}).get('content', '')
if isinstance(content, str):
print(content[:200])
elif isinstance(content, list):
for block in content:
if isinstance(block, dict) and block.get('type') == 'text':
print(block['text'][:200])
break
break
"
Ask the user: "Is this the session to recover from, or should I look at an older one?"
Wait for confirmation before proceeding.
Filter the JSONL to only human and assistant text turns — skip tool_use, tool_result, file-history-snapshot, permission-mode, and attachment entries:
python3 -c "
import json, sys
for line in open('$LATEST'):
msg = json.loads(line)
msg_type = msg.get('type')
if msg_type == 'user':
content = msg.get('message', {}).get('content', '')
if isinstance(content, str) and content.strip():
print(f'## User\n{content[:500]}\n')
elif isinstance(content, list):
for block in content:
if isinstance(block, dict) and block.get('type') == 'text':
print(f'## User\n{block[\"text\"][:500]}\n')
break
elif msg_type == 'assistant':
content = msg.get('message', {}).get('content', '')
if isinstance(content, str) and content.strip():
print(f'## Assistant\n{content[:500]}\n')
elif isinstance(content, list):
texts = [b.get('text','') for b in content if isinstance(b, dict) and b.get('type') == 'text']
combined = ' '.join(texts).strip()
if combined:
print(f'## Assistant\n{combined[:500]}\n')
" > /tmp/recovered-session.md
wc -l /tmp/recovered-session.md
Read the extracted conversation to understand what happened.
From the extracted conversation, synthesise a recovery entry:
jotter write \
--project <project> \
--branch <branch> \
--type finish \
--content "<what was built/fixed, key decisions, where things stopped>" \
--next "<priorities inferred from the session trajectory>"
Use --type finish so the log correctly marks the session as closed.
"Recovered session from [date/time]. Key context: [1-2 sentence summary]. Ready to continue with
/start."
Flag anything that couldn't be recovered (very short session, mostly tool output with little conversation).
development
Run the session start routine — ask about available time and hard stops, read recent session logs and ROADMAP.md priorities, propose a realistic goal. Use when the user says "/start", "/start-session", "let's start", "start session", "begin session", or at the start of any longer session. Skip for quick focused tasks where the goal is already clear.
development
Mid-session checkpoint — snapshot current decisions and progress without archiving or cleaning up. Use when the user says "/save", "checkpoint", "save progress", or before risky operations like schema migrations, large refactors, or long-running tasks.
testing
TDD ping-pong pairing mode — collaborative spec, alternating test-write and implement roles
testing
Run the end-of-session checklist — write session summary to session log, move completed items to DONE.md, add new items to ROADMAP.md, check CLAUDE.md is current, review dirty git state and propose commits. Use when the user says "/finish", "/finish-session", "/end", "let's wrap up", "wrap up", "let's finish", "end this session", "let's call it", "that's enough for today", or similar.