Agent SkillsAlfredvc/claude-metadata › extract-conversations

extract-conversations

GitHub

从 Claude Code 日志中提取结构化对话元数据,用于分析协作模式、发现失败模式、审查技能使用情况或优化工作流。

skills/extract-conversations/SKILL.md Alfredvc/claude-metadata

Trigger Scenarios

分析协作模式 查找失败模式 审查技能使用 改进工作流

Install

npx skills add Alfredvc/claude-metadata --skill extract-conversations -g -y
More Options

Use without installing

npx skills use Alfredvc/claude-metadata@extract-conversations

指定 Agent (Claude Code)

npx skills add Alfredvc/claude-metadata --skill extract-conversations -a claude-code -g -y

安装 repo 全部 skill

npx skills add Alfredvc/claude-metadata --all -g -y

预览 repo 内 skill

npx skills add Alfredvc/claude-metadata --list

SKILL.md

Frontmatter
{
    "name": "extract-conversations",
    "description": "Extract structured conversation metadata from Claude Code logs for process improvement analysis. Use when the user wants to analyze collaboration patterns, find failure modes, review skill usage, or improve their workflow with Claude.",
    "allowed-tools": "Bash(python3 *), Bash(jq *), Read, Grep, Glob",
    "argument-hint": [
        "project_dir"
    ],
    "user-invocable": true
}

Extract conversation data and save to a temporary file for analysis:

python3 scripts/extract_session_data.py [project_dir] > /tmp/conversations.json

Output Schema

{
  "project": "string — project path, or \"ALL\" when --all is used",
  "generated_at": "string — ISO 8601 UTC timestamp",
  "conversation_count": "number",
  "session_count": "number",
  "conversations": [
    {
      "slug": "string | null — conversation topic, used to group sessions. null for ungrouped sessions",
      "sessions": [
        {
          "session_id": "string — unique session identifier",
          "file": "string — absolute path to the source JSONL file",
          "is_continuation": "boolean — true if this session continues a previous one (compaction restart)",
          "version": "string | null — Claude Code version",
          "git_branch": "string | null — active git branch during the session",
          "start": "string | null — ISO 8601 timestamp of first entry",
          "end": "string | null — ISO 8601 timestamp of last entry",
          "turns": [
            {
              "index": "number — zero-based turn index within the session",
              "uuid": "string | null — unique turn identifier from the log entry",
              "timestamp": "string | null — ISO 8601 timestamp of the user message",
              "duration_seconds": "number | null — wall-clock seconds from user message to end of Claude's response",
              "user_text": "string — the user's message text",
              "interrupted": "boolean — true if the user interrupted Claude's response",
              "post_interrupt_text": "string — (only present if interrupted) the user's message after interrupting",
              "estimated_input_tokens": "number — (only present for interrupted turns with no API response) estimated from nearest turn with token data",
              "model": "string | null — primary model used (e.g. \"claude-sonnet-4-6\")",
              "api_calls": "number — deduplicated API call count for this turn",
              "tokens": {
                "input": "number — uncached input tokens",
                "cache_read": "number — tokens read from cache",
                "cache_write": "number — tokens written to cache",
                "output": "number — output tokens generated"
              },
              "tools": "object — {ToolName: count} map, e.g. {\"Edit\": 3, \"Bash\": 1}. Empty object if no tools used",
              "skills": [
                {
                  "name": "string — skill name",
                  "source": "string — \"cli\" (user typed /skill) or \"model\" (Claude invoked via Skill tool)"
                }
              ],
              "errors": ["string — error messages from bash failures and tool errors"],
              "subagents": [
                {
                  "agent_id": "string | null — agent identifier",
                  "description": "string — short description from the Agent tool call",
                  "completed_in_turn": "number | null — turn index where the agent completed, null if same turn",
                  "file": "string | null — absolute path to the subagent's JSONL log file",
                  "model": "string | null — primary model used by the subagent",
                  "api_calls": "number — subagent's API call count",
                  "duration_seconds": "number | null — subagent wall-clock duration",
                  "tokens": {
                    "input": "number",
                    "cache_read": "number",
                    "cache_write": "number",
                    "output": "number"
                  },
                  "tools": "object — {ToolName: count} map",
                  "skills": [{"name": "string", "source": "string"}],
                  "errors": ["string"]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Conditional fields: post_interrupt_text is only present on interrupted turns. estimated_input_tokens is only present on turns interrupted before any API response. subagents is only present on turns that launched agents. All other fields are always present.

Useful flags:

  • --from YYYY-MM-DD / --to YYYY-MM-DD — filter by date range
  • --no-subdirs — exclude worktrees
  • --all — scan all projects
  • --session ID — filter to a specific session

After extracting, use jq to query the data. Examples:

# All interrupted turns with post-interrupt text
jq '[.conversations[].sessions[].turns[] | select(.interrupted) | {user_text, post_interrupt_text, duration_seconds}]' /tmp/conversations.json

# Skill usage frequency
jq '[.conversations[].sessions[].turns[].skills[].name] | group_by(.) | map({skill: .[0], count: length}) | sort_by(-.count)' /tmp/conversations.json

# Turns with errors
jq '[.conversations[].sessions[].turns[] | select(.errors | length > 0) | {user_text: .user_text[:80], errors}]' /tmp/conversations.json

# Subagent summary
jq '[.conversations[].sessions[].turns[].subagents[]? | {description, duration_seconds, api_calls, model}]' /tmp/conversations.json

To dig deeper into a specific turn, use the turn's uuid and the session's file:

# Find the full exchange starting from a turn's UUID
jq -c 'select(.uuid == "TARGET_UUID" or .parentUuid == "TARGET_UUID")' SESSION_FILE.jsonl

Version History

  • 8de4631 Current 2026-07-25 07:25

Same Skill Collection

skills/api-usage/SKILL.md

Metadata

Files
0
Version
8de4631
Hash
29945b24
Indexed
2026-07-25 07:25

inicio - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-22 00:39
浙ICP备14020137号-1 $mapa de visitantes$