agentsclimarketplace

Claude session rescue

Skill tsaijamey/claude-session-rescue/skills/claude-session-rescue

Rescue a stuck Claude Code session by trimming the broken tail of its JSONL transcript and resuming cleanly

Install
npx -y skills add tsaijamey/claude-session-rescue --skill claude-session-rescue

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

This skill should be used when a Claude Code session becomes permanently stuck and cannot continue because the model returned a malformed response that the client cannot parse. It explains how to repair the session by editing its raw JSONL transcript file and then resuming. Trigger phrases: "The model's tool call could not be parsed (retry also failed)", "tool call could not be parsed", "Your tool call was malformed and could not be parsed", "session stuck and won't resume", "claude code session frozen", "rescue a broken claude code session", "fix corrupted session jsonl", "resume a dead claude session", "empty thinking block stop_reason tool_use".

The file declares its own license as AGPL-3.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.1 KB, 992 tokens by cl100k_base, as published. Nobody here has run it

Overview

A Claude Code session can freeze permanently when the model streams back a structurally broken assistant message: a single thinking block whose text is an empty string (signature still present), stop_reason set to tool_use, but no tool_use block anywhere in the content array. The client parser assumes stop_reason=tool_use guarantees a tool_use block, fails to find one, and errors. The automatic retry replays the same broken response, so it fails again — surfacing as "The model's tool call could not be parsed (retry also failed)." This pattern spikes with high-reasoning model variants on long sessions.

The broken records always sit at the TAIL of the session transcript: once the bug fires, the session dies and never branches further. Because the bad records have no child nodes and create no dangling tool_use/tool_result pairings, truncating the JSONL file back to the last healthy state makes the entire history self-consistent again, and --resume rebuilds a legal context.

Steps

  1. Locate the transcript. Sessions live at ~/.claude/projects/<escaped-project-path>/<session-id>.jsonl. The escaped path replaces / with -. Confirm the file by matching the session id, or sort by modification time to find the most recently touched session.

  2. Back up before any edit. Copy the file to a .broken-backup sibling (and optionally a second copy elsewhere). This preserves evidence and guarantees a clean restore path. Never mutate the original without a backup.

  3. Inspect the tail records. Parse the last 10–15 records as JSON. Print for each: line number, type, role, uuid, parentUuid, requestId, message.id, stop_reason, and the list of content block types. This reveals turn boundaries.

  4. Identify turn boundaries correctly — do not over-delete. Claude Code splits ONE assistant turn across several JSONL records (a thinking record, a text record, a tool_use record) that all share the same requestId / message.id. A record with stop_reason=tool_use is normal as long as a sibling record in the same turn carries the actual tool_use block. Only flag a turn as broken when its records contain an empty thinking and stop_reason=tool_use yet NO tool_use block exists in the whole turn.

  5. Find the healthy anchor. Walking backward from the tail, skip: (a) broken assistant turns (empty thinking + stop_reason=tool_use, no tool_use block); (b) client-injected user records reading "Your tool call was malformed and could not be parsed. Please retry."; (c) the synthesized final error record (typically requestId=None) showing "retry also failed"; (d) trailing system housekeeping records. Stop at the last fully-paired record — usually a tool_result that matches an earlier tool_use, or a normal assistant record with stop_reason=end_turn.

  6. Truncate to the anchor. Rewrite the file containing only lines up to and including the anchor record. Preserve the original filename and a trailing newline.

  7. Self-check the result. Verify three invariants: every remaining line parses as JSON; no tool_use block lacks a matching downstream tool_result (no dangling tool calls); and the parentUuid chain is unbroken (the anchor becomes a clean leaf, so no parent pointers need patching).

  8. Resume. Run claude --resume <session-id>. For a non-destructive smoke test first, resume with a constrained prompt (forbid continuing the prior task, forbid tool calls) and ask the model to confirm it can see prior history and restate the last action. A clean exit with an accurate history recap confirms the rescue; the resume appends fresh records ending in a normal stop_reason=end_turn.

Boundary conditions

This clean truncate-and-resume works when the bad data is at the chain tail — the overwhelming majority of these failures. If a broken record is buried mid-history with a valid subtree still hanging off it, deletion is not enough: surviving child records must have their parentUuid re-pointed to the deleted record's parent, which is materially more complex and out of scope for the simple flow. This skill repairs the session transcript; it does not patch the underlying model/streaming bug.


About

Generated by frago — An Agent OS that turns ad-hoc agent runs into reusable recipes.

Install: uv tool install frago-cli Homepage: https://frago.ai · Docs: https://docs.frago.ai

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 326,984. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.