Claude Code session transcript cleaner. Reduces transcript size by 60-80% while preserving conversation flow.
curl -sL https://raw.githubusercontent.com/professional-ALFIE/context-cleaner-skill/main/install.sh | bashThis installs the skill and scripts to ~/.claude/skills/context-cleaner/.
This hook provides the transcript path and session ID to Claude and exports them through CLAUDE_ENV_FILE. Without it, pass a transcript path or session UUID to the cleaner manually.
It also detects --fork results: when a session ID ends in 00effacedNNN, the hook displays a cleaned-session notice. In-place cleaning preserves the original session ID, so the bundled hook does not infer that state from the ID alone.
After running the install script, register the hook in ~/.claude/settings.json. Add the SessionStart entry to the hooks object (don't remove existing hooks):
{"SessionStart":[{"hooks":[{"type":"command","command":"${HOME}/.claude/skills/context-cleaner/src/contextCleaner_sessionStartHook.sh"}]}]}After registration, restart your Claude Code session.
Copy the block below and paste it into Claude Code. It will handle everything automatically.
Install the context-cleaner skill from this repo: https://github.com/professional-ALFIE/context-cleaner-skill
Step 1 - Run the install script:
curl -sL https://raw.githubusercontent.com/professional-ALFIE/context-cleaner-skill/main/install.sh | bash
Step 2 - Add this SessionStart hook entry to ~/.claude/settings.json inside the "hooks" object. Do NOT remove any existing hooks:
{"SessionStart":[{"hooks":[{"type":"command","command":"${HOME}/.claude/skills/context-cleaner/src/contextCleaner_sessionStartHook.sh"}]}]}
After all steps, tell me to restart the session.
Strips bulky data from .jsonl transcript files:
- Thinking-only rows, file contents, diffs, stdout/stderr
- Full file paths β filenames only
- Hook progress, hook summaries and hook attachments; synthetic/local-command rows; tool result duplicates; meta content
Preserves: conversation text, edit intent, filenames, UUID chains, resume anchors, and branch tips.
- Cleans β Removes heavy data (thinking, file contents, bash output, etc.) and replaces with lightweight markers like
[context-cleaner: Read] - Writes atomically in place by default β The cleaned transcript replaces the original only after verification passes. Use
--forkto preserve the original and create a00effacedcopy - Maintains uuid chain β When lines are deleted,
parentUuidreferences are remapped so the conversation tree stays intact. Claude--resumeworks correctly - Preserves resume state β
last-prompt.leafUuid,sourceToolAssistantUUID, snapshots, and parent references are remapped when rows are deleted - Verifies before replacement β Orphans, cycles, broken references, conversation roots, and resume anchors are checked before an in-place rename
Original: 9c4c1a42-...-239d2e110282.jsonl
Cleaned: 9c4c1a42-...-00effaced001.jsonl
Re-clean: 9c4c1a42-...-00effaced002.jsonl (number increments)
00effaced= prefix00+ "effaced" (erased/removed)- The SessionStart hook detects this pattern and shows a context-cleaned session notice
Claude Code records every action to a JSONL transcript. The cleaner replaces bulky fields with lightweight markers and deletes specific low-value rows while preserving conversation structure.
Thinking-only assistant rows are deleted and their references are remapped. If a row contains both thinking and non-thinking content, the row is preserved and only message.content[N].thinking is replaced.
Reading a file records its full content in the transcript.
- Call:
input.file_pathβ trimmed to filename only - Result:
toolUseResult.file.contentβ replaced - Result duplicate:
tool_result.contentβ replaced
Writing a file records the written content and the original file.
- Call:
input.file_pathβ trimmed to filename only,input.contentβ replaced - Result:
toolUseResult.content,.originalFile,.structuredPatchβ replaced - Result duplicate:
tool_result.contentβ replaced
Editing records old/new strings and the original file.
- Call:
input.file_pathβ trimmed to filename only,input.old_string,input.new_stringβ replaced - Result:
toolUseResult.oldString,.newString,.originalFile,.structuredPatchβ replaced - Result duplicate:
tool_result.contentβ replaced
Running a command records the command text and its full output.
- Call:
input.commandβ replaced - Result:
toolUseResult.stdout,.stderrβ replaced - Progress:
data.output,data.fullOutput(bash_progress lines) β replaced - Result duplicate:
tool_result.contentβ replaced
Searching records a list of matched file paths.
- Result:
toolUseResult.filenamesβ replaced with[""]
Calling a subagent records the prompt and the agent's full output. The prompt is stored in three locations (Path A/B/C).
- Call (Path A):
input.promptβ replaced - Result:
toolUseResult.task.outputortoolUseResult.content[N].textβ replaced - Result prompt (Path C):
toolUseResult.promptβ replaced - Progress (Path B):
data.message.message.content(agent_progress lines) β replaced - Result duplicate:
tool_result.contentβ replaced
Fetching a URL records the full page content.
- Result:
toolUseResult.result(string) β replaced
Exiting plan mode records the plan text.
- Call:
input.planβ replaced
Not tied to a specific tool, but still cleaned.
- Image attachments:
source.database64 β 1x1 transparent PNG,source.media_typeβimage/png - Hook rows:
hook_progress,stop_hook_summary, andhook_*attachments are deleted by default;--hooks keepor an event list preserves selected rows - Meta messages (isMeta):
content[N].textβ replaced (injected SKILL.md, system prompts, etc.) - Bash tags:
<bash-stdout>...<bash-stderr>patterns in user messages β replaced - User-marked content:
<clean>...</clean>patterns β replaced - teammate-message: tag body β replaced (opening tag attributes including
summarypreserved) - local-command-stdout: tag body β replaced when over 200 characters (short outputs preserved)
Wrap any part of your prompt with <clean>...</clean> tags to mark it for deletion on the next clean. Useful for pasting large text that you don't need in future context.
<clean>paste your large content here</clean>
After cleaning, you get a detailed report:
π Mode: in-place β original transcript replaced after verification
β
Context Cleaner v5 (TS) completed!
π Source: ${HOME}/.claude/projects/.../<session-id>.jsonl
π Output: ${HOME}/.claude/projects/.../<session-id>.jsonl
π Cleaning Statistics (field replacements): ...
π Row Deletions (deletion + reference remapping): ...
π To resume this cleaned session, run:
cd ${HOME}/project/example && claude --dangerously-skip-permissions --thinking-display summarized --verbose --resume <session-id>
π Verification: PASS
Just tell Claude: "context cleanν΄μ€" or "transcript μ 리ν΄μ€"
~/.claude/skills/context-cleaner/scripts/context-cleaner.ts ${HOME}/path/to/session.jsonl
~/.claude/skills/context-cleaner/scripts/context-cleaner.ts ${HOME}/path/to/session.jsonl --fork
~/.claude/skills/context-cleaner/scripts/context-cleaner.ts <session-uuid-prefix> --hooks keepThe default mode is atomic in-place replacement. Use --fork when comparing results or when the original transcript must remain untouched. The Python implementation is retained only as the legacy v4 fallback.
The cleaner prints a resume command using the session's recorded working directory. In-place mode keeps the original session ID; --fork produces a new 00effacedNNN ID.
cd ${HOME}/project/example && claude --dangerously-skip-permissions --thinking-display summarized --verbose --resume <session-id>On macOS, the CLI also copies this command when pbcopy is available. Clipboard failure is ignored. The --verbose flag shows SessionStart hook output; the cleaned-session notice appears automatically for --fork IDs ending in 00effacedNNN.
- Bun
jq(for the hook script)- macOS (optional
pbcopysupport)