Skip to content
Development
Skill

/cc-history

Reference documentation for analyzing Claude Code conversation history files

From plugin
claude-config
91511 skills5 agents

Claude Code

$ npx -y skills add solatis/claude-config --skill cc-history --agent claude-code

SKILL.md

cc-history.SKILL.md
name: cc-history
description: Reference documentation for analyzing Claude Code conversation history files

Claude Code History Analysis

Reference documentation for querying and analyzing Claude Code's conversation history. Use shell commands and jq to extract information from JSONL conversation files.

Directory Structure

~/.claude/projects/{encoded-path}/
  |-- {session-uuid}.jsonl          # Main conversation
  |-- {session-uuid}/
      |-- subagents/
      |   |-- agent-{hash}.jsonl    # Subagent conversations
      |-- tool-results/             # Large tool outputs

Project Path Resolution

Convert working directory to project directory:

PROJECT_DIR="~/.claude/projects/$(echo "$PWD" | sed 's|^/|-|; s|/\.|--|g; s|/|-|g')"

Encoding rules:

  • Leading `/` becomes `-`
  • Regular `/` becomes `-`
  • `/.` (hidden directory) becomes `--`

Examples:

  • `/Users/bill/.claude` -> `-Users-bill--claude`
  • `/Users/bill/git/myproject` -> `-Users-bill-git-myproject`

Message Types

| Type | Description | | ----------------- | --------------------------------------------- | | `user` | User input messages | | `assistant` | Model responses (thinking, tool_use, text) | | `system` | System messages | | `queue-operation` | Background task notifications (subagent done) |

Message Structure

Each line in a JSONL file is a message object:

{
  "type": "assistant",
  "uuid": "abc123",
  "parentUuid": "xyz789",
  "timestamp": "2025-01-15T19:39:16.000Z",
  "sessionId": "session-uuid",
  "message": {
    "role": "assistant",
    "content": [...],
    "usage": {
      "input_tokens": 20000,
      "output_tokens": 500,
      "cache_read_input_tokens": 15000,
      "cache_creation_input_tokens": 5000
    }
  }
}

Assistant message content blocks:

  • `type: "thinking"` - Model thinking (has `thinking` field)
  • `type: "tool_use"` - Tool invocation (has `name`, `input` fields)
  • `type: "text"` - Text response (has `text` field)

Common Queries

Find Conversations

# List by modification time (most recent first)
ls -lt "$PROJECT_DIR"/*.jsonl

# Find by date
ls -la "$PROJECT_DIR"/*.jsonl | grep "Jan 15"

# Find by content
grep -l "search term" "$PROJECT_DIR"/*.jsonl

Extract Messages

# Get message by line number (1-indexed)
sed -n '42p' file.jsonl | jq .

# Get message by uuid
jq -c 'select(.uuid=="abc123")' file.jsonl

# All user messages
jq -c 'select(.type=="user")' file.jsonl

# All assistant messages
jq -c 'select(.type=="assistant")' file.jsonl

Tool Call Analysis

# List all tool calls
jq -c 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use") | {name, input}' file.jsonl

# Count tool calls by name
jq -c 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use") | .name' file.jsonl | sort | uniq -c | sort -rn

# Find specific tool calls
jq -c 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use" and .name=="Bash")' file.jsonl

Skill Invocation Detection

Pattern: `python3 -m skills\.([a-z_]+)\.`

# Find all skill invocations
grep -oE "python3 -m skills\.[a-z_]+" file.jsonl | sort -u

# Find conversations using a specific skill
grep -l "python3 -m skills\.planner\." "$PROJECT_DIR"/*.jsonl

Token Usage

# Total tokens in conversation
jq -s '[.[].message.usage? | select(.) | .input_tokens + .output_tokens] | add' file.jsonl

# Token breakdown
jq -s '[.[].message.usage? | select(.)] | {
  input: (map(.input_tokens) | add),
  output: (map(.output_tokens) | add),
  cached: (map(.cache_read_input_tokens // 0) | add)
}' file.jsonl

# Token progression over time
jq -c 'select(.type=="assistant") | {ts: .timestamp[11:19], inp: .message.usage.input_tokens, out: .message.usage.output_tokens}' file.jsonl

Taxonomy Aggregation

# Count messages by type
jq -s 'group_by(.type) | map({type: .[0].type, count: length})' file.jsonl

# Character count in user messages
jq -s '[.[] | select(.type=="user") | .message.content | length] | add' file.jsonl

# Thinking block character count
jq -s '[.[] | select(.type=="assistant") | .message.content[]? | select(.type=="thinking") | .thinking | length] | add' file.jsonl

Subagent Analysis

# List subagents for a session
ls "${SESSION_DIR}/subagents/"

# Get subagent task description (first user message)
jq -c 'select(.type=="user") | .message.content' agent-*.jsonl | head -1

# Find Task tool calls in parent (these spawn subagents)
jq -c 'select(.type=="assistant") | .message.content[]? | select(.type=="tool_use" and .name=="Task") | .input' file.jsonl

Conversation Branching

Each `.jsonl` file contains the **entire conversation tree** (all branches), not separate files per branch. Branching is tracked via `parentUuid`:

  • When user goes back in history and issues a new command, the new message gets the same `parentUuid` as where they branched from
  • Multiple messages sharing the same `parentUuid` = sibling branches (fork point)

Detecting Branch Points

# Find all fork points (messages with multiple children)
jq -s 'group_by(.parentUuid) | map(select(length > 1)) | .[] | {
  parentUuid: .[0].parentUuid,
  branches: length,
  timestamps: [.[].timestamp]
}' file.jsonl

# Show siblings at a known fork point
FORK_POINT="parent-uuid-here"
jq -c --arg fp "$FORK_POINT" 'select(.parentUuid==$fp) | {uuid, ts: .timestamp, preview: (.message.content | tostring)[:100]}' file.jsonl

Extracting a Single Branch

To filter for exactly one branch, find a unique identifier in that branch, then walk the ancestor chain back to root.

**Step 1: Find target message uuid**

# By unique content
TARGET=$(jq -r 'select(.message.content | tostring | contains("unique-identifier")) | .uuid' file.jsonl | tail -1)

# By timesta
Read more
@solatis
Ships withclaude-config

I use Claude Code for most of my work. After months of iteration, I noticed a pattern: LLM-assisted code rots faster than hand-written code.

91511 skills5 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
915
Star history of solatis/claude-config on GitHub, a chart by star-history.com

Other skills on claude-config.

arxiv-to-md

arxiv-to-md

Convert arXiv papers to LLM-consumable markdown. Invoke when user provides an arXiv ID or URL, or when syncing academic papers…

codebase-analysis

codebase-analysis

Invoke IMMEDIATELY via python script when user requests codebase understanding, architecture comprehension, or repository…

decision-critic

decision-critic

Invoke IMMEDIATELY via python script to stress-test decisions and reasoning. Do NOT analyze first - the script orchestrates the…

deepthink

deepthink

Invoke IMMEDIATELY via python script when user requests structured reasoning for open-ended analytical questions. Do NOT explore…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills10d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc12d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react1d252k
@facebook@facebookInstall Skill

Questions about cc-history.

Which coding agents can use cc-history?
cc-history installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.