---
description: Use when an agent shows compaction rot / context rot — lost the plot after a compact/summarize, forgot the session goal, repeating done work, ignoring standing user instructions, drifting from methodology, confused about what's next. Triggers on /fix-rot, "you've lost context", "refresh your context", "you forgot what we're doing", "re-read the conversation", "recover the session", "you're rotting", "reorient yourself". Reconstructs session goals, methodology, philosophy, user intent/directions/instructions, active/deferred/remaining tasks, what's gated on the user, and a prioritized immediate TODO — WITHOUT re-polluting the main thread. Emits the recovered context as a resumable harness-native JSONL (`docs/plans/`, keyed by a session slug) so `[[handoff]]` / `[[run-plan]]` continue it in another session.
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent
---


# fix-rot

Audience: AI coding agents first.

Recover a rotted main thread by rebuilding lost session context **out-of-context**, then ingesting only a small distilled harness-native JSONL.

## Core constraint (why this skill exists)

Compaction rot = main thread's live window got summarized; goals/intent/standing-instructions degraded or dropped. The durable ground truth is the **session transcript JSONL on disk** (full, un-summarized) — NOT the rotted window.

**NEVER read the transcript into the main thread.** It is large (often MBs). Loading it triggers immediate re-compaction → deeper rot. That is the exact failure this skill prevents.

Therefore: a **disposable /ask-codex gpt-5.6-luna/low subagent** absorbs all heavy reading in ITS OWN context, writes two compact files (the durable harness-native JSONL + an ephemeral prose briefing), returns only their paths. Main thread native-Reads both small files. The subagent's context is thrown away — its pollution dies with it.

## Procedure (main thread — keep it tiny)

1. **Spawn ONE /ask-codex agent**, (cheap; the work is extraction, not reasoning). Pass the prompt in the template below verbatim. Do NOT do any transcript reading yourself.
2. **Receive only the two file paths** the subagent returns (JSONL first, then briefing `.md`). If it returned record content or prose instead of paths, discard it and re-spawn — ingesting content defeats the skill.

3. **Native Read both files** (small, by design). The JSONL re-injection into the main thread IS the recovery — same mechanism `[[run-plan]]` uses; the briefing supplies the prioritized immediate TODO + narrative. Re-seats your working context.
4. **Emit minimal output** (template at bottom): one status line, the immediate next action (the briefing's top TODO item) with your recommendation, the session **slug**, and both file paths. Do NOT echo the full files back into chat — they are already in your context from the Reads.

Total new bytes into main thread = two small files (JSONL + briefing). Nothing else.

## Subagent prompt (pass verbatim)

```
You are a context-recovery extractor. The main agent suffered compaction rot. Rebuild its lost
session context from the DURABLE transcript and write TWO files: a durable harness-native JSONL and
a prose briefing .md. Return ONLY their paths.

HARD RULES:
- Output to me (the caller) = the two absolute file paths (JSONL first), nothing else. No summary, no preamble, no content.
- NEVER read the raw transcript into your own context wholesale — it may be MBs. Extract
  PROGRAMMATICALLY (jq / exec-file), pulling only what you need.

STEP 1 — Locate the current session transcript:
- cwd slug = current working directory with every "/" and "." replaced by "-".
  Example: /home/user/.claude  ->  -home-user--claude
- Transcript dir: ~/.claude/projects/<slug>/
- Current session = most-recently-modified *.jsonl at the TOP LEVEL of that dir (maxdepth 1).
  Ignore nested subdirs — those are subagent transcripts, not the main session.
  find ~/.claude/projects/<slug> -maxdepth 1 -name '*.jsonl' -printf '%T@ %p\n' | sort -rn | head -1

STEP 2 — Extract signal programmatically (do NOT cat the whole file):
- The transcript is APPEND-ONLY across compactions: original pre-compaction user turns,
  harness compaction summaries, AND post-compaction turns all coexist in this one file.
  That is exactly why it is the ground truth the rotted live window lost.
- HIGHEST signal = real USER turns (intent, directions, standing instructions, corrections)
  PLUS real user DECISIONS made via AskUserQuestion (the questiontool) — these are user choices,
  not tool noise, and are currently dropped by naive tool_result filtering. Do not lose them.
  Start: jq -c 'select(.message.role=="user")' <file>, then EXCLUDE two kinds of non-human turns:
    1. tool_result turns (content blocks whose type is "tool_result") — EXCEPT a tool_result whose
       tool_use_id matches a preceding AskUserQuestion tool_use. THAT is a real user decision
       (the user picked/typed the answer) — KEEP it, same priority as a user prompt. Join it back
       to its AskUserQuestion tool_use (same tool_use_id) to recover the question text; record the
       pair (question -> chosen answer) as one decision.
    2. compaction summaries: turns with .isCompactSummary==true — these are HARNESS-GENERATED
       summaries (the rot itself), NOT user instructions. NEVER quote them as user directions.
       You MAY read them as a hint of what was already summarized away, but treat real user
       turns as authoritative over any compaction summary that contradicts them.
  Real user prompts may be wrapped in <command-name>/<command-args> tags — unwrap them.
  Adapt jq to the actual shape.
- Then assistant decisions/plans and the recent tail (last turns) for current state.

STEP 3 — Re-ground anchor docs:
- From the transcript, detect file paths the session was working AGAINST: plan/spec, CLAUDE.md,
  handoff doc, ADRs, the primary files under edit.
- Re-read the CURRENT contents of those anchors (they are small and authoritative) so methodology
  and philosophy reflect live source, not stale memory. Emit them as `anchor` records (STEP 4).

Emit TWO artifacts (mirrors [[handoff]]'s split): STEP 4 = the durable harness-native JSONL
  (structured intent/state, the resume key); STEP 5 = a prose briefing .md (handoff narrative +
  prioritized immediate TODO — the richer context that has no schema home and is losable to
  compaction without harm). Both small. Return both paths (STEP 6).

STEP 4 — Write the durable harness-native JSONL. Do NOT invent or copy the schema —
  READ it from ~/.claude/skills/brainstorm/SKILL.md "Session File" section and follow it EXACTLY.
  One JSON record per line (this file is JSONL, NEVER markdown, NEVER pretty-printed). Quote the
  user VERBATIM for directions.

  4a — SLUG (the resume key):
    - REUSE + repair an existing docs/plans/*.jsonl in place ONLY on a HARD signal: the transcript
      itself names that file's slug or path (brainstorm/run-plan/handoff actually ran with it THIS
      session). Repair rewrites goal/intent/direction records — a wrong match silently corrupts an
      unrelated plan, so topic/anchor RESEMBLANCE alone is NOT enough. Never touch that file's
      existing `task` lines — the harness engine's own journal at `runstate/<slug>.jsonl` is the
      progress ground truth, not this file.
    - Otherwise MINT a new kebab-case slug from the session goal/topic (e.g. auth-rework). A duplicate
      plan file is cheap to discard; a corrupted real one is not.

  4b — PATH: docs/plans/<YYYY-MM-DD>-<slug>.jsonl  (date = `date +%F`). Create docs/plans/ if absent.
    run-plan globs this EXACT location — writing anywhere else makes the session unresumable.

  4c — RECORDS — map the reconstructed signal onto the schema vocabulary (omit a record only if
    genuinely empty):
    - meta (line 1): `slug`, `base_branch`, `gate0_mode` (default `"strict"`), `preset` — no `schema`
      key. Determine `base_branch` the same way brainstorm does (the branch the amended code already
      lives on), not a guess.
    - goal / methodology / intent — one record each.
    - direction — one per explicit standing user rule, quoted VERBATIM (never paraphrase).
    - AskUserQuestion decisions — same record type as direction (they ARE user directions, just
      given via questiontool instead of prose). Quote as "Q: <question> -> A: <chosen answer text>",
      VERBATIM for both question and chosen option. Do not drop these as if they were tool noise.
    - Blocked-on-USER        -> gated {needs, why} (a real user decision/input), linked from any task
      via `requires_decision`.
    - Deferred / Parked      -> deferred {text, reason}.
    - Anchor Docs            -> anchor {path, what} (the STEP 3 paths; point, never copy prose).
    - task ids: ad-hoc recoveries are usually flat — number tasks t1, t2, … Every task carries
      id / wave / seat ("coder") / tier ("medium" unless the session clearly warrants otherwise) /
      desc / requires_decision. **This schema has NO status/deps/blocker/phase field** — do NOT
      invent one. Encode "already done" work by simply omitting it as a task (it's landed; nothing
      to resume). Encode in-flight/remaining/blocked distinctions as `session_memory` notes AND in
      the STEP 5 prose briefing's Immediate TODO — that is their correct home now, not the task line.
    - WAVE PURITY: mirror the transcript's real structure — do NOT collapse parallel file-disjoint
      tasks into one sequential wave, and do NOT invent dependencies that were not there.
    - SHIP FACTS: if the rotted file / transcript carries a decided land method (push-vs-PR, base
      branch, auto-merge), author it as a `gated` record with `binds_meta` per brainstorm's rule —
      don't drop it silently.

STEP 5 — Write the prose briefing to ${TMPDIR:-/tmp}/fix-rot-<slug>.md (OS temp — ephemeral, like
  handoff's prose doc; losable to compaction without harm). It holds ONLY what the JSONL cannot:
  DO NOT re-list goals/tasks/directions (those live in the JSONL — reference it by path, never
  duplicate, same rule handoff enforces). Sections:

  # Session Recovery Briefing — <slug>
  _Generated by fix-rot from <transcript path>. Structured intent/state: <JSONL path>._

  ## Immediate TODO — prioritized   (ranked next actions + a recommendation for what to do NOW)
  ## Situational narrative          (where things stand, gotchas, why the last approach — prose that
                                     has no schema record; keep tight)
  ## Suggested skills               (which skills the continuing agent should invoke next)

STEP 6 — Return ONLY the two absolute paths, JSONL first, one per line. No other text. (The slug
  lives in meta.slug and the JSONL filename; the main thread reads it from there.)
```

## Main-thread output (after reading both files)

Keep it minimal — both files are already in context. Surface the slug (the user cannot resume a slug they never saw). Template:

```
Context recovered. <one line: the session goal in your own words>.
Immediate next: <the briefing's top TODO item> — <your recommendation>.
Session slug: `<slug>` — hand off / resume anytime with `/run-plan <slug>`.
Durable state: <JSONL path>   |   Briefing: <.md path>
```

## Notes

- One subagent only. Fan-out adds no value here and multiplies cost.
- gpt-5.6-luna/low is deliberate: extraction + structured summarization, not deep reasoning. Do not upgrade the model without a reason.
- If the subagent reports it could not locate the transcript (e.g. cwd slug mismatch), fall back: ask the subagent to search `~/.claude/projects/` for the most-recent top-level *.jsonl across all project dirs whose recent content matches this session, OR ask the user for the session id. Do NOT silently produce a session file from a guessed transcript.

$ARGUMENTS
