session-investigator
Investigate fast-agent session and history files to diagnose issues. Use when a session ended unexpectedly, when debugging tool loops, when correlating sub-agent traces with main sessions, or when analyzing conversation flow and timing. Covers session.json metadata, history JSON format, message structure, tool call/result correlation, and common failure patterns.
Install
mkdir -p .claude/skills/session-investigator && curl -L -o skill.zip "https://mcp.directory/api/skills/download/2311" && unzip -o skill.zip -d .claude/skills/session-investigator && rm skill.zipInstalls to .claude/skills/session-investigator
About this skill
Session Investigator
Diagnose fast-agent session issues by examining session and history files.
Session Directory Structure
Sessions are stored in .fast-agent/sessions/<session-id>/:
2601181023-Kob2h3/
├── session.json # Session metadata
├── history_<agent>.json # Current agent history
└── history_<agent>_previous.json # Previous save (rotation backup)
Session IDs encode creation time: YYMMDDHHMM-<random> (e.g., 2601181023 = 2026-01-18 10:23).
Key Files
session.json
{
"name": "2601181023-Kob2h3",
"created_at": "2026-01-18T10:23:24.116526",
"last_activity": "2026-01-18T10:39:42.873467",
"history_files": ["history_dev_previous.json", "history_dev.json"],
"metadata": {
"agent_name": "dev",
"first_user_preview": "is it possible to override..."
}
}
history_<agent>.json
{
"messages": [
{
"role": "user|assistant",
"content": [{"type": "text", "text": "..."}],
"tool_calls": {"<id>": {"method": "tools/call", "params": {"name": "...", "arguments": {}}}},
"tool_results": {"<id>": {"content": [...], "isError": false}},
"channels": {
"fast-agent-timing": [{"type": "text", "text": "{\"start_time\": ..., \"end_time\": ..., \"duration_ms\": ...}"}],
"fast-agent-tool-timing": [{"type": "text", "text": "{\"<tool_id>\": {\"timing_ms\": ..., \"transport_channel\": ...}}"}],
"reasoning": [{"type": "text", "text": "..."}]
},
"stop_reason": "endTurn|toolUse|error",
"is_template": false
}
]
}
Investigation Commands
Basic inspection
# Message count
jq '.messages | length' history_dev.json
# Last N messages overview
jq '.messages[-5:] | .[] | {role, stop_reason, has_tool_calls: (.tool_calls != null), has_tool_results: (.tool_results != null)}' history_dev.json
# View specific message
jq '.messages[227]' history_dev.json
Tool call correlation
Tool calls and results are linked by correlation ID. Valid pattern: assistant with tool_calls → user with matching tool_results.
# Check tool call/result pairing
jq '.messages[-10:] | to_entries | .[] | {
index: .key,
role: .value.role,
tool_calls: (if .value.tool_calls then (.value.tool_calls | keys) else [] end),
tool_results: (if .value.tool_results then (.value.tool_results | keys) else [] end)
}' history_dev.json
Find specific tool calls
# Find all calls to a specific tool
jq '.messages | to_entries | .[] |
select(.value.tool_calls != null) |
select(.value.tool_calls | to_entries | .[0].value.params.name == "agent__ripgrep_search") |
{index: .key, timing: (.value.channels."fast-agent-timing"[0].text)}' history_dev.json
Session Statistics
LLM Call Stats
# Total LLM time and call count
jq '[.messages[] | select(.role == "assistant") |
select(.channels."fast-agent-timing") |
.channels."fast-agent-timing"[0].text | fromjson | .duration_ms] |
{count: length, total_ms: add, avg_ms: (add/length), max_ms: max, min_ms: min}' history_dev.json
# LLM calls sorted by duration (slowest first)
jq '[.messages | to_entries | .[] |
select(.value.role == "assistant") |
select(.value.channels."fast-agent-timing") |
{index: .key, duration_ms: (.value.channels."fast-agent-timing"[0].text | fromjson | .duration_ms)}] |
sort_by(-.duration_ms) | .[0:10]' history_dev.json
Tool Execution Stats
# All tool timings aggregated
jq '[.messages[] | select(.channels."fast-agent-tool-timing") |
.channels."fast-agent-tool-timing"[0].text | fromjson | to_entries | .[].value.timing_ms] |
{count: length, total_ms: add, avg_ms: (add/length), max_ms: max, min_ms: min}' history_dev.json
# Tool calls by name with timing
jq '[.messages | to_entries | .[] |
select(.value.tool_calls) |
(.value.tool_calls | to_entries | .[0]) as $tc |
{index: .key, tool: $tc.value.params.name,
llm_ms: (.value.channels."fast-agent-timing"[0].text | fromjson | .duration_ms)}] |
group_by(.tool) |
map({tool: .[0].tool, count: length, total_llm_ms: (map(.llm_ms) | add)}) |
sort_by(-.count)' history_dev.json
Session Timeline
# Session duration from first to last timing
jq '.messages | [
(map(select(.channels."fast-agent-timing")) | first | .channels."fast-agent-timing"[0].text | fromjson | .start_time),
(map(select(.channels."fast-agent-timing")) | last | .channels."fast-agent-timing"[0].text | fromjson | .end_time)
] | {start: .[0], end: .[1], duration_sec: ((.[1] - .[0]) | round)}' history_dev.json
# Message rate over time (messages per minute estimate)
jq '{
messages: (.messages | length),
llm_calls: [.messages[] | select(.role == "assistant" and .channels."fast-agent-timing")] | length,
total_llm_ms: [.messages[] | select(.channels."fast-agent-timing") | .channels."fast-agent-timing"[0].text | fromjson | .duration_ms] | add,
total_tool_ms: [.messages[] | select(.channels."fast-agent-tool-timing") | .channels."fast-agent-tool-timing"[0].text | fromjson | to_entries | .[].value.timing_ms] | add
} | . + {llm_sec: (.total_llm_ms/1000), tool_sec: ((.total_tool_ms//0)/1000)}' history_dev.json
Sub-agent Stats
# Sub-agent calls (tools starting with "agent__")
jq '[.messages | to_entries | .[] |
select(.value.tool_calls) |
(.value.tool_calls | to_entries | .[0]) as $tc |
select($tc.value.params.name | startswith("agent__")) |
{index: .key, agent: $tc.value.params.name,
llm_ms: (.value.channels."fast-agent-timing"[0].text | fromjson | .duration_ms)}] |
group_by(.agent) |
map({agent: .[0].agent, calls: length, total_ms: (map(.llm_ms) | add), avg_ms: ((map(.llm_ms) | add) / length)})' history_dev.json
Common Failure Patterns
Unanswered Tool Call
Symptom: API error "No tool output found for function call"
Pattern: History ends with assistant message having tool_calls and stop_reason: "toolUse", followed by user message WITHOUT matching tool_results.
# Check last message for pending tool call
jq '.messages[-1] | {role, has_tool_calls: (.tool_calls != null), stop_reason}' history_dev.json
Cause: Session interrupted mid-tool-loop, then resumed with new user input before tool completed.
Fix: Truncate history to last valid tool result:
# Find last user message with tool_results
jq '.messages | to_entries | map(select(.value.role == "user" and .value.tool_results != null)) | last | .key' history_dev.json
# Truncate (keep messages 0 to N inclusive, so use N+1)
jq '.messages = .messages[0:227]' history_dev.json > /tmp/fixed.json && mv /tmp/fixed.json history_dev.json
Duplicate User Messages
Pattern: Two consecutive user messages before assistant response.
Cause: Often from before_llm_call hooks appending instructions. Check agent card's tool_hooks configuration.
Sub-agent Trace Correlation
Sub-agent traces are saved as <agent_name>-<timestamp>.json in the working directory.
# List traces around session time
ls -la ripgrep_search*2026-01-18-10-3*.json
# Correlate via timing - match monotonic clock values
jq '.messages[-1].channels."fast-agent-timing"[0].text' ripgrep_search*.json
Compare start_time/end_time values between main session and sub-agent traces to correlate which sub-agent call corresponds to which main session tool call.
Log File
Check fastagent.jsonl for errors during the session timeframe:
# Filter by timestamp range
cat fastagent.jsonl | while read line; do
ts=$(echo "$line" | jq -r '.timestamp // empty' 2>/dev/null)
if [[ "$ts" > "2026-01-18T10:20" && "$ts" < "2026-01-18T10:45" ]]; then
echo "$line" | jq -c '{timestamp, level, message}'
fi
done
More by evalstate
View all skills by evalstate →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversClaude Historian: AI-powered search for Claude Code conversations—find files, errors, context, and sessions via JSONL pa
LLMS.txt Documentation: Easily fetch and parse llms.txt files to provide instant AI-driven documentation lookup during c
Claude Historian is a free AI search engine offering advanced search, file context, and solution discovery in Claude Cod
Memory Bank offers persistent project context with structured markdown files, workflow guidance, and automatic timestamp
Securely manage your Mac OS X clipboard history with encrypted storage, cut, copy, paste, undo, and access controls for
Prompt Library saves and organizes prompts as local markdown files, creating a personal prompt library across sessions f
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.