# Claude session introspect > Use when token counts or compaction details are needed from a Claude Code session. Inspect Claude Code session JSONL files at ~/.claude/projects/ to extract real conversation telemetry: token counts (input/output/cache reads/cache writes), assistant turn counts, human prompt counts, tool-use counts, compaction boundaries, and the contents of compaction summaries. Use this skill when the user asks "how many tokens did this session use", "how many prompts have I sent", "show me the stats for this conversation", "what got compacted", "where are the compaction boundaries", "introspect the session", "do brain surgery on the JSONL", or wants any data point that lives inside the on-disk session log rather than the live context window. Inspired by Tal Raviv's "I wanted to know how compaction works" article. ## Facts - Type: Agent skill - Discipline: Engineering - Author: Shawn Wang (https://github.com/swyxio) - Upstream: https://github.com/swyxio/skills/tree/main/claude-session-introspect - Source file: https://raw.githubusercontent.com/swyxio/skills/main/claude-session-introspect/SKILL.md (8204 bytes, sha256:8082a4af11e3db2d296642bc28a37542991754ed3fdcf4d6a904ead58b82407b) - Licence: MIT - Upstream copy last changed: 2026-09-17 - Status: listed, not yet ruled on by the curator ## Use it I want to use the Claude session introspect skill by Shawn Wang. This is what it does, in the author's own words: Inspect Claude Code session JSONL files at ~/.claude/projects/ to extract real conversation telemetry: token counts (input/output/cache reads/cache writes), assistant turn counts, human prompt counts, tool-use counts, compaction boundaries, and the contents of compaction summaries. Use this skill when the user asks "how many tokens did this session use", "how many prompts have I sent", "show me the stats for this conversation", "what got compacted", "where are the compaction boundaries", "introspect the session", "do brain surgery on the JSONL", or wants any data point that lives inside the on-disk session log rather than the live context window. Inspired by Tal Raviv's "I wanted to know how compaction works" article. Download the whole folder at https://github.com/swyxio/skills/tree/main/claude-session-introspect, SKILL.md and every file beside it, into your skills directory: ~/.claude/skills/claude-session-introspect/ for Claude Code, ~/.agents/skills/claude-session-introspect/ for Codex, ~/.cursor/skills/claude-session-introspect/ for Cursor. Get it from the author's repo, not from startupskills.dev. Then tell me the path you installed it to and how to invoke it. Nothing here is vendored: install from the author's repo, not from this site. A verbatim copy of the author's file follows for reading, under the licence reproduced after it; the current file is in the author's repo. ## Links - Page: https://startupskills.dev/swyxio/claude-session-introspect - Author: https://startupskills.dev/swyxio - Index: https://startupskills.dev/llms.txt ## The file itself --- name: claude-session-introspect description: | Inspect Claude Code session JSONL files at ~/.claude/projects/ to extract real conversation telemetry: token counts (input/output/cache reads/cache writes), assistant turn counts, human prompt counts, tool-use counts, compaction boundaries, and the contents of compaction summaries. Use this skill when the user asks "how many tokens did this session use", "how many prompts have I sent", "show me the stats for this conversation", "what got compacted", "where are the compaction boundaries", "introspect the session", "do brain surgery on the JSONL", or wants any data point that lives inside the on-disk session log rather than the live context window. Inspired by Tal Raviv's "I wanted to know how compaction works" article. license: MIT compatibility: | Requires `jq`. Sessions live at `~/.claude/projects//.jsonl`. The encoded-cwd is the absolute working directory with `/` replaced by `-` and a leading `-`. Each line is a JSON object with `type`, `message`, `toolUseResult`, etc. metadata: author: swyxio version: "1.0" last-updated: "2026-04-08" primary-tools: jq, bash --- # Claude Session Introspect Claude Code persists every conversation as a JSONL file on disk. This skill is the recipe for opening one and pulling out the numbers you actually want — token usage, prompt counts, compaction events, tool calls — without guessing. ## Where sessions live ``` ~/.claude/projects//.jsonl ``` `` is the absolute path of the project's working directory with `/` replaced by `-` and a leading `-`. Example: `/Users/swyx/Work/foo` → `-Users-swyx-Work-foo`. Each line is one event. The interesting `type` values: | type | what it is | |---|---| | `user` | a real user message **OR** a tool result (distinguished by `toolUseResult` being non-null) | | `assistant` | an assistant turn (one model response). `message.usage` has the token counts. | | `system` | system messages (mostly compaction-related) | | `file-history-snapshot` | edited-file snapshots used for undo | | `attachment` | image/file attachments | | `permission-mode` | permission mode toggles | ## Quick locate: find the current session ```bash # 1. encode current working directory ENC="-$(pwd | sed 's,/,-,g' | sed 's/^-//')" # 2. list the project's session files, newest first ls -t "$HOME/.claude/projects/$ENC/" # 3. the most recent .jsonl is usually the live one SESSION="$HOME/.claude/projects/$ENC/$(ls -t "$HOME/.claude/projects/$ENC/" | head -1)" echo "$SESSION" ``` If you know the session UUID (Claude Code shows it, and image-cache paths embed it), you can grep all projects: ```bash find ~/.claude/projects -name '.jsonl' ``` ## The headline stats (one-shot) The `stats.sh` script in this skill folder takes a session path and prints token totals, turn counts, prompt counts, tool-use counts, and any compaction events. ```bash bash stats.sh "$SESSION" ``` If you don't have the script handy, here are the inline jq one-liners. ### Token totals across the whole session ```bash jq -s ' [.[] | select(.message.usage)] | { assistant_turns: length, input_tokens: (map(.message.usage.input_tokens // 0) | add), output_tokens: (map(.message.usage.output_tokens // 0) | add), cache_read_tokens: (map(.message.usage.cache_read_input_tokens // 0) | add), cache_create_tokens: (map(.message.usage.cache_creation_input_tokens // 0)| add) } ' "$SESSION" ``` `input_tokens` is the FRESH (non-cached) input. `cache_read_tokens` is the dominant number on long sessions — it's how much was re-read from prompt cache. `cache_create_tokens` is what got newly written into the cache. Effective total tokens processed = `input + cache_read + cache_create`. ### Counts by event type ```bash jq -r '.type' "$SESSION" | sort | uniq -c ``` ### Real human prompts (excluding tool results and system reminders) A `type:"user"` line is a human message **only if** `toolUseResult` is null. Even then, the content may be a system-injected reminder, not the human's words. ```bash jq -r ' select(.type == "user" and .toolUseResult == null) | (.message.content | if type == "string" then . else (map(select(.type == "text") | .text) | join("\n")) end) ' "$SESSION" > /tmp/prompts.txt # total non-empty user message blocks grep -cv '^$' /tmp/prompts.txt # distinct human messages = blocks not starting with or / && cur !~ /^/ && cur !~ /^` tag.) ### Tool calls — how many and which tools ```bash jq -r ' select(.type == "assistant") | .message.content[]? | select(.type == "tool_use") | .name ' "$SESSION" | sort | uniq -c | sort -rn ``` ### Compaction boundaries — where, why, and what survived Compaction inserts a `system` event with `subtype:"compact_boundary"` (older builds may use `isCompactSummary` on the next user message). The summary itself is the *next* user message, prefixed with "This session is being continued from a previous conversation that ran out of context." ```bash # count compaction events jq -r 'select(.type=="system" and (.subtype // "") == "compact_boundary") | .timestamp' "$SESSION" | wc -l # was each one auto or manual? jq -r ' select(.type == "system" and (.subtype // "") == "compact_boundary") | {ts: .timestamp, trigger: (.compactMetadata.trigger // "unknown"), preTokens: (.compactMetadata.preCompactTokens // null)} ' "$SESSION" # read the compaction summaries (the actual contents that survived) jq -r ' select(.type == "user" and (.isCompactSummary == true or ((.message.content // "") | tostring | test("session is being continued from a previous conversation")))) | (.message.content | if type == "string" then . else (map(select(.type=="text").text)|join("\n")) end) ' "$SESSION" | less ``` ### Per-turn token usage (for spotting blowups) ```bash jq -r ' select(.message.usage) | [.timestamp, (.message.usage.input_tokens // 0), (.message.usage.output_tokens // 0), (.message.usage.cache_read_input_tokens // 0)] | @tsv ' "$SESSION" | column -t ``` This is how you find the one tool result that bloated your context — sort by `cache_read` ascending across the session and watch for the jump. ## Gotchas - **`type:"user"` is overloaded.** Tool results are also `type:"user"`. Always filter on `toolUseResult == null` to get human turns. - **`input_tokens` looks tiny on long sessions.** That's correct — it's the *delta* sent uncached. Almost everything flows through `cache_read_input_tokens`. - **The "live" session file isn't always the newest.** If multiple Claude Code windows are open in the same project, both write to the same project folder. Disambiguate by UUID — the chat header and image-cache paths both expose it. - **JSONL files grow without bound.** A long-running project folder can have hundreds of session files. `ls -t | head` is your friend. - **Don't edit a live JSONL.** Claude Code reads it back on `/resume`. If you want to do "brain surgery" (Tal Raviv's term), copy the file out, edit the copy, and use `claude --resume ` from a clean directory. ## When to reach for this skill - "How many tokens has this session burned?" - "How many prompts have I sent today?" - "Where did compaction kick in and what got summarized?" - "Which tool call blew up the context?" - Building a stats display, leaderboard, or "built with Claude Code" badge that needs real numbers. - Forensics on a session that went sideways — replaying tool calls in order. ## Reference - Tal Raviv, "I wanted to know how compaction works" — https://www.talraviv.co/p/i-wanted-to-know-how-compaction-works - Claude Code docs on session storage — `~/.claude/projects/` ## Licence of the file above The file above is https://raw.githubusercontent.com/swyxio/skills/main/claude-session-introspect/SKILL.md, by Shawn Wang, reproduced without changes. - Source: https://github.com/swyxio/skills/tree/main/claude-session-introspect - Copyright: Copyright (c) 2026 Shawn Wang (swyx) - Licence: MIT, https://raw.githubusercontent.com/swyxio/skills/main/LICENSE The repo's licence file, verbatim from https://raw.githubusercontent.com/swyxio/skills/main/LICENSE: MIT License Copyright (c) 2026 Shawn Wang (swyx) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.