arxiv-to-md
Convert arXiv papers to LLM-consumable markdown. Invoke when user provides an arXiv ID or URL, or when syncing academic papers from a PDF folder to a markdown…
Reference documentation for analyzing Claude Code conversation history files
$ npx -y skills add solatis/claude-config --skill cc-history --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/cc-historyContext preview
The summary Claude sees to decide when to auto-load this skill.
Reference documentation for analyzing Claude Code conversation history files
name: cc-history description: Reference documentation for analyzing Claude Code conversation history files
Reference documentation for querying and analyzing Claude Code's conversation history. Use shell commands and jq to extract information from JSONL conversation files.
~/.claude/projects/{encoded-path}/
|-- {session-uuid}.jsonl # Main conversation
|-- {session-uuid}/
|-- subagents/
| |-- agent-{hash}.jsonl # Subagent conversations
|-- tool-results/ # Large tool outputsConvert working directory to project directory:
PROJECT_DIR="~/.claude/projects/$(echo "$PWD" | sed 's|^/|-|; s|/\.|--|g; s|/|-|g')"
Encoding rules:
Examples:
| Type | Description | | ----------------- | --------------------------------------------- | | `user` | User input messages | | `assistant` | Model responses (thinking, tool_use, text) | | `system` | System messages | | `queue-operation` | Background task notifications (subagent done) |
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:
# 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
# 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
# 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.jsonlPattern: `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
# 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# 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# 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.jsonlEach `.jsonl` file contains the **entire conversation tree** (all branches), not separate files per branch. Branching is tracked via `parentUuid`:
# 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.jsonlTo 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 timestaI 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.
Convert arXiv papers to LLM-consumable markdown. Invoke when user provides an arXiv ID or URL, or when syncing academic papers from a PDF folder to a markdown…
Invoke IMMEDIATELY via python script when user requests codebase understanding, architecture comprehension, or repository orientation. Do NOT explore first -…
Invoke IMMEDIATELY via python script to stress-test decisions and reasoning. Do NOT analyze first - the script orchestrates the critique workflow.
Invoke IMMEDIATELY via python script when user requests structured reasoning for open-ended analytical questions. Do NOT explore first - the script…
Detect and resolve incoherence in documentation, code, specs vs implementation.