## New Skill: continue-claude-work (v1.1.0) - Recover actionable context from local `.claude` session artifacts - Compact-boundary-aware extraction (reads Claude's own compaction summaries) - Subagent workflow recovery (reports completed vs interrupted subagents) - Session end reason detection (clean exit, interrupted, error cascade, abandoned) - Size-adaptive strategy for small/large sessions - Noise filtering (skips 37-53% of session lines) - Self-session exclusion, stale index fallback, MEMORY.md integration - Bundled Python script (no external dependencies) - Security scan passed, argument-hint added ## Skill Updates - **skill-creator** (v1.5.0): Complete rewrite with evaluation framework - Added agents/ (analyzer, comparator, grader) - Added eval-viewer/ (generate_review.py, viewer.html) - Added scripts/ (run_eval, aggregate_benchmark, improve_description, run_loop) - Added references/schemas.md (eval/benchmark schemas) - Expanded SKILL.md with inline vs fork guidance, progressive disclosure patterns - Enhanced package_skill.py and quick_validate.py - **transcript-fixer** (v1.2.0): CLI improvements and test coverage - Enhanced argument_parser.py and commands.py - Added correction_service.py improvements - Added test_correction_service.py - **tunnel-doctor** (v1.4.0): Quick diagnostic script - Added scripts/quick_diagnose.py - Enhanced SKILL.md with 5-layer conflict model - **pdf-creator** (v1.1.0): Auto DYLD_LIBRARY_PATH + rendering fixes - Auto-detect and set DYLD_LIBRARY_PATH for weasyprint - Fixed list rendering and CSS improvements - **github-contributor** (v1.0.3): Enhanced project evaluation - Added evidence-loop, redaction, and merge-ready PR guidance ## Documentation - Updated marketplace.json (v1.38.0, 42 skills) - Updated CHANGELOG.md with v1.38.0 entry - Updated CLAUDE.md (skill count, marketplace version, #42 description) - Updated README.md (badges, skill section #42, use case, requirements) - Updated README.zh-CN.md (badges, skill section #42, use case, requirements) - Fixed absolute paths in continue-claude-work/references/file_structure.md ## Validation - All skills passed quick_validate.py - continue-claude-work passed security_scan.py - marketplace.json validated (valid JSON) - Cross-checked version consistency across all docs
7.5 KiB
Claude Code Local File Structure
Ground-truth reference for ~/.claude/ directory layout and JSONL session format.
Directory Layout
~/.claude/
projects/ # Per-project session storage (primary)
<normalized-path>/
sessions-index.json # Master index of all sessions
<session-id>.jsonl # Session transcript
<session-id>/ # Session subdirectory (optional)
subagents/
agent-<agent-id>.meta.json # Agent metadata
agent-<agent-id>.jsonl # Agent transcript
tool-results/
toolu_<tool-id>.txt # Large tool outputs
memory/ # Persistent memory files (MEMORY.md, etc.)
history.jsonl # Global prompt history (no session IDs)
tasks/ # Task tracking (per-session lock/highwatermark)
plans/ # Plan documents (random-name.md)
debug/ # Per-session debug logs (<session-id>.txt)
transcripts/ # Global tool operation logs (ses_<id>.jsonl)
file-history/ # File modification backups
todos/ # Todo items
Path Normalization
Project paths are encoded by replacing / with -:
| Original | Normalized |
|---|---|
/path/to/project |
-path-to-project |
/another/workspace/app |
-another-workspace-app |
sessions-index.json Schema
{
"version": 1,
"entries": [
{
"sessionId": "20089b2a-e3dd-48b8-809c-0647128bf3b8",
"fullPath": "~/.claude/projects/-path-to-project/20089b2a-....jsonl",
"fileMtime": 1741327503477,
"firstPrompt": "fix the login bug",
"summary": "Fixed authentication redirect...",
"messageCount": 42,
"created": "2026-03-07T03:25:03.477Z",
"modified": "2026-03-07T12:21:43.806Z",
"gitBranch": "main",
"projectPath": "/path/to/project",
"isSidechain": false
}
],
"originalPath": "/path/to/project"
}
Key fields for session identification:
sessionId— UUID v4 formatfirstPrompt— first user message (best for topic matching)summary— auto-generated summary of the sessionmodified— last activity timestamp (ISO 8601)gitBranch— git branch at session timeisSidechain—falsefor main conversations
Compaction in Session Files
Claude Code uses server-side compaction. When context fills up, two consecutive lines appear:
Line 1: compact_boundary marker
{
"type": "system",
"subtype": "compact_boundary",
"parentUuid": null,
"logicalParentUuid": "prev-uuid",
"compactMetadata": {
"trigger": "input_tokens",
"preTokens": 180000
}
}
Line 2: Compact summary (special user message)
{
"type": "user",
"isCompactSummary": true,
"isVisibleInTranscriptOnly": true,
"message": {
"role": "user",
"content": "This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.\n\nAnalysis:\n1. **Initial Request**: User asked to...\n2. **Progress**: Completed X, Y, Z...\n3. **Current state**: Working on..."
}
}
Key properties:
isCompactSummary: true— most reliable way to identify compact summariesisVisibleInTranscriptOnly: true— not sent to the API, only stored in the transcript- Summary is always a plain string in
.message.content(not an array) - Typically 12K-31K characters (high-density information)
- A long session may have multiple compact boundaries (4+ is common for 10MB+ sessions)
- The last compact boundary's summary reflects the most recent state
- Messages after the last boundary are the "hot zone" — they were in Claude's live context
Default compaction prompt (from API docs)
"You have written a partial transcript for the initial task above. Please write a summary of the transcript. The purpose of this summary is to provide continuity so you can continue to make progress towards solving the task in a future context, where the raw history above may not be accessible and will be replaced with this summary."
Session JSONL Message Types
Each .jsonl file has one JSON object per line. Common types:
file-history-snapshot (always first line)
{
"type": "file-history-snapshot",
"messageId": "uuid",
"snapshot": { "trackedFileBackups": {}, "timestamp": "..." },
"isSnapshotUpdate": false
}
User message
{
"parentUuid": "prev-uuid or null",
"isSidechain": false,
"cwd": "/path/to/project",
"sessionId": "session-uuid",
"version": "2.1.71",
"gitBranch": "main",
"type": "user",
"message": {
"role": "user",
"content": "fix the login bug"
},
"uuid": "msg-uuid",
"timestamp": "2026-03-07T03:25:03.477Z"
}
Important: .message.content can be:
- A string for plain text user messages
- An array of content blocks for tool results and multi-part messages:
"content": [ { "type": "tool_result", "tool_use_id": "toolu_...", "content": "..." }, { "type": "text", "text": "now do X" } ]
Assistant message
{
"type": "assistant",
"message": {
"role": "assistant",
"model": "claude-opus-4-6",
"content": [
{ "type": "thinking", "thinking": "internal reasoning..." },
{ "type": "text", "text": "visible response text" },
{ "type": "tool_use", "id": "toolu_...", "name": "Bash", "input": { "command": "..." } }
]
}
}
Content block types in assistant messages:
thinking— internal reasoning (skip when extracting actionable context)text— visible response to user (extract this)tool_use— tool invocations (useful for understanding what was done)
Tool result (user message with tool output)
{
"type": "user",
"message": {
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_...", "content": "command output..." }
]
}
}
history.jsonl Schema
Global prompt log. Does NOT contain session IDs — only useful for finding when a prompt was issued and in which project:
{
"display": "/init ",
"pastedContents": {},
"timestamp": 1758996122446,
"project": "/path/to/project"
}
Extraction Patterns
List recent sessions for current project
cat ~/.claude/projects/<normalized-path>/sessions-index.json \
| jq '.entries | sort_by(.modified) | reverse | .[:5] | .[] | {sessionId, firstPrompt, summary, messageCount, modified, gitBranch}'
Extract user text from session tail
Handles both string and array content formats:
tail -n 200 <session-file>.jsonl \
| jq -r 'select(.type == "user" and .message.role == "user")
| .message.content
| if type == "string" then .
elif type == "array" then map(select(.type == "text") | .text) | join("\n")
else empty end' \
| tail -n 80
Extract assistant text (excluding thinking/tool_use)
tail -n 200 <session-file>.jsonl \
| jq -r 'select(.message.role == "assistant")
| .message.content
| if type == "array" then map(select(.type == "text") | .text) | join("\n")
else empty end' \
| tail -n 120
Find sessions by keyword in firstPrompt
cat ~/.claude/projects/<normalized-path>/sessions-index.json \
| jq -r '.entries[] | select(.firstPrompt | test("keyword"; "i")) | "\(.modified) \(.sessionId) \(.firstPrompt)"'