Investigate unexpected chat agent behavior by analyzing direct debug logs in JSONL files. Use when users ask why something happened, why a request was slow, why tools or subagents were used or skipped, or why instructions/skills/agents did not load.
This skill investigates and explains unexpected chat agent behavior using direct log files.
Use this skill for questions like:
Base conclusions on evidence from logs. Do not guess.
{{VSCODE_TARGET_SESSION_LOG}}Use direct debug log files written by Copilot Chat:
debug-logs/<sessionId>/
main.jsonl — always start here; primary conversation log
models.json — (optional) snapshot of available models at session start
system_prompt_0.json — (optional) full system prompt sent to the model (untruncated)
system_prompt_1.json — (optional) written when the model changes mid-session
tools_0.json — (optional) tool definitions sent to the model
tools_1.json — (optional) written when the model changes mid-session
runSubagent-<agentName>-<uuid>.jsonl — (optional) subagent's tool calls & LLM requests
searchSubagent-<uuid>.jsonl — (optional) search subagent work
title-<uuid>.jsonl — (optional, UI-only) title generation
categorization-<uuid>.jsonl — (optional, UI-only) prompt categorization
summarize-<uuid>.jsonl — (optional, UI-only) conversation summarization
Always read main.jsonl first — it has the full conversation flow. Child files only appear when those operations occurred. main.jsonl contains child_session_ref entries that link to each child file by name. Title, categorization, and summarize files are UI housekeeping and rarely relevant to troubleshooting. When investigating model availability or selection issues, read models.json — it contains the full list of models (with capabilities, billing, and limits) that were available when the session started.
When investigating what the model was told (system prompt, instructions), read the system_prompt_*.json file referenced by a system_prompt_ref entry in main.jsonl. The file contains the full untruncated system prompt as { "content": "..." }. When investigating which tools were available, read the tools_*.json file similarly. If the model changed mid-session, multiple numbered files exist — each llm_request entry has a systemPromptFile attr indicating which file was active for that request.
Each line is a JSON object. Common fields: ts (epoch ms), dur (duration ms), sid (session ID), type, name, spanId, parentSpanId, status (ok|error), attrs (type-specific details).
{"ts":1773200251309,"dur":0,"sid":"62f52dec","type":"discovery","name":"Load Instructions","spanId":"2cb1f2f4","status":"ok","attrs":{"details":"Resolved 0 instructions in 0.0ms | folders: [/c:/Users/user/.copilot/instructions, /workspace/.github/instructions]","category":"discovery","source":"core"}}
{"ts":1773200251415,"dur":0,"sid":"62f52dec","type":"discovery","name":"Load Agents","spanId":"38a897d8","status":"ok","attrs":{"details":"Resolved 3 agents in 0.0ms | loaded: [Plan, Ask, Explore] | folders: [/workspace/.github/agents]","category":"discovery","source":"core"}}
{"ts":1773200251431,"dur":0,"sid":"62f52dec","type":"discovery","name":"Load Skills","spanId":"472eb225","status":"ok","attrs":{"details":"Resolved 6 skills in 0.0ms | loaded: [agent-customization, troubleshoot, ...]","category":"discovery","source":"core"}}
Key attrs: details (human-readable summary with folder paths, loaded items, skip reasons), category (always "discovery"), source ("core").
{"ts":1773200222647,"dur":4,"sid":"62f52dec","type":"tool_call","name":"manage_todo_list","spanId":"000000000000000b","parentSpanId":"0000000000000003","status":"ok","attrs":{"args":"{\"operation\":\"read\"}","result":"No todo list found."}}
{"ts":1773200234047,"dur":8937,"sid":"62f52dec","type":"tool_call","name":"run_in_terminal","spanId":"000000000000000d","parentSpanId":"0000000000000003","status":"error","attrs":{"args":"{\"command\":\"echo rama\"}","result":"ERROR: conpty.node missing","error":"A native exception occurred during launch"}}
Key attrs: args (JSON string of tool input), result (tool output or error text), error (present when status:"error").
{"ts":1773200231010,"dur":3001,"sid":"62f52dec","type":"llm_request","name":"chat:gpt-4o","spanId":"000000000000000c","parentSpanId":"0000000000000003","status":"ok","attrs":{"model":"gpt-4o","inputTokens":15025,"outputTokens":126,"ttft":1987,"maxTokens":32000,"systemPromptFile":"system_prompt_0.json","userRequest":"echo hello","inputMessages":"[{...}]"}}
Key attrs: model, inputTokens, outputTokens, ttft (time to first token in ms), maxTokens, temperature, topP, systemPromptFile (references a system prompt file in the session directory), toolsFile (references a tools file in the session directory), userRequest (the full user message content, untruncated), inputMessages (full messages array as JSON, pre-truncated at 64KB), error (when failed).
{"ts":1773200234011,"dur":0,"sid":"62f52dec","type":"agent_response","name":"agent_response","spanId":"agent-msg-000000000000000c","parentSpanId":"0000000000000003","status":"ok","attrs":{"response":"[{\"role\":\"assistant\",...}]","reasoning":"The user wants me to run a command."}}
Key attrs: response (JSON-encoded array of message parts; may be truncated), reasoning (optional — the model's chain-of-thought/thinking text when thinking mode is active; may be truncated).
{"ts":1773200251345,"dur":0,"sid":"62f52dec","type":"user_message","name":"user_message","spanId":"000000000000000f","status":"ok","attrs":{"content":"using subagent count .md"}}
Key attrs: content (the user's message text).
{"ts":1773200254954,"dur":7921,"sid":"62f52dec","type":"subagent","name":"Explore","spanId":"0000000000000014","parentSpanId":"0000000000000013","status":"ok","attrs":{"agentName":"Explore"}}
Key attrs: agentName, description (optional), error (when failed).
{"ts":1773200260000,"dur":0,"sid":"62f52dec","type":"generic","name":"some-event","spanId":"abc123","status":"ok","attrs":{"details":"Additional context","category":"some-category"}}
Special generic entries:
system_prompt_ref — references a system_prompt_*.json file in the session directory. attrs.file is the filename, attrs.model is the model it was written for. Read this file to see the full system prompt.tools_ref — references a tools_*.json file. attrs.file is the filename, attrs.model is the model.{"ts":1773200251300,"dur":0,"sid":"62f52dec","type":"session_start","name":"session_start","spanId":"session-start-62f52dec","status":"ok","attrs":{"copilotVersion":"0.43.2026033104","vscodeVersion":"1.99.0"}}
Key attrs: copilotVersion, vscodeVersion. Useful for identifying which build produced the logs.
{"ts":1773200251400,"dur":0,"sid":"62f52dec","type":"turn_start","name":"turn_start:0","spanId":"turn-start-X-0","status":"ok","attrs":{"turnId":"0"}}
{"ts":1773200255000,"dur":0,"sid":"62f52dec","type":"turn_end","name":"turn_end:0","spanId":"turn-end-X-0","status":"ok","attrs":{"turnId":"0"}}
Key attrs: turnId (iteration number within a single user request's tool-calling loop). Use these to identify which iteration events belong to and to count total loop iterations.
Events form a tree via spanId/parentSpanId. A typical chain:
user_message (spanId: X) — the user's turnllm_request (parentSpanId: X) — model call for that turnagent_response (parentSpanId: X) — what the model returnedtool_call (parentSpanId: X) — tool executed from the responsellm_request (parentSpanId: X) — next model call after tool resultSubagent calls create nested hierarchies: the tool_call for runSubagent (spanId: Y) becomes the parent for a child subagent span, which in turn parents its own llm_request/tool_call events.
Debug log files live outside the workspace (in user storage), so workspace-scoped search tools like grep_search cannot access them. Use the terminal instead.
Do not use grep_search for log files — it only works on workspace files.
Use run_in_terminal with grep or jq:
grep '"status":"error"' <logPath>grep '"type":"discovery"' <logPath>jq -c 'select(.dur > 5000)' <logPath>grep '"type":"tool_call"' <logPath>grep 'search_term' <logPath>tail -n 50 <logPath>jq -r '.type' <logPath> | sort | uniq -c | sort -rnjq -c '{type, name, status, dur}' <logPath>jq -c 'select(.type == "discovery")' <logPath>jq -c 'select(.type == "user_message") | .attrs.content' <logPath>Use run_in_terminal with PowerShell commands:
Select-String '"status":"error"' <logPath>Select-String '"type":"discovery"' <logPath>Select-String '"type":"tool_call"' <logPath>Select-String 'search_term' <logPath>Get-Content <logPath> -Tail 50node -e "require('fs').readFileSync('<logPath>','utf8').split('\n').filter(Boolean).map(JSON.parse).filter(e => e.dur > 5000).forEach(e => console.log(JSON.stringify(e)))"node -e "const lines=require('fs').readFileSync('<logPath>','utf8').split('\n').filter(Boolean).map(JSON.parse);const c={};lines.forEach(e=>c[e.type]=(c[e.type]||0)+1);Object.entries(c).sort((a,b)=>b[1]-a[1]).forEach(([t,n])=>console.log(n,t))"ls -lh <logPath> (or (Get-Item <logPath>).Length on Windows). If the file is large, avoid commands that load the entire file into memory (e.g. node -e with readFileSync). Prefer streaming tools like grep, jq, Select-String, tail, or head.read_file only for small targeted ranges (a few lines) once you know the line numbers. Never read entire log files.run_in_terminal with ls -lh (or dir on Windows) to locate candidate .jsonl files and check their sizes.grep/jq are not available, fall back to Select-String or node -e one-liners (only for smaller files).main.jsonl in each directory.run_in_terminal (use grep/jq on macOS/Linux, Select-String/node -e on Windows)"status":"error"dur values (> 5000)"type":"discovery""type":"tool_call""type":"llm_request"spanId / parentSpanId when needed.If you suspect network connectivity or authentication problems (e.g., repeated request timeouts, 401/403 errors, or model endpoint failures in the logs), run the VS Code command github.copilot.debug.collectDiagnostics using the run_vscode_command tool. The command returns the full diagnostics report as a string, so you can read the result directly from the tool output. The report includes:
The command also opens the report in an editor for the user to see. Use the returned string to diagnose the network issue.
When investigating issues related to a specific type of customization file (instructions, prompt files, agents, etc.) and you need more details about the expected format or behavior, load the relevant documentation page:
https://code.visualstudio.com/docs/copilot/customization/custom-instructionshttps://code.visualstudio.com/docs/copilot/customization/prompt-fileshttps://code.visualstudio.com/docs/copilot/customization/custom-agentshttps://code.visualstudio.com/docs/copilot/customization/language-modelshttps://code.visualstudio.com/docs/copilot/customization/mcp-servershttps://code.visualstudio.com/docs/copilot/customization/hookshttps://code.visualstudio.com/docs/copilot/customization/agent-pluginsUse these when you need to verify file format expectations, confirm supported fields, or help the user fix a customization file.
When your investigation yields no clear root cause or you have no specific remediation suggestions:
https://github.com/microsoft/vscode/wiki/Copilot-Issues.Your response should cover:
You do not need separate headers for each of these. For straightforward issues, a short combined explanation with a "How to fix" section is fine. Use more structure (headers, multiple sections) only when the issue is complex or involves multiple contributing factors.
main.jsonl or runSubagent-Explore-abc123.jsonl.Bad (narrates investigation, uses internal terms, pastes raw log):
I'm investigating the session debug log to confirm whether a testing skill was discovered. In the skills discovery summary, the loader reports:
skipped: testing2 (name-mismatch). The frontmatter name in SKILL.md doesn't match the folder identity.
Good (concise, user-friendly, actionable):
The "testing" skill was found but not loaded because there's a name mismatch between the folder and the skill file:
Value Folder name testingName in SKILL.md testing2These must match for the skill to load.
How to fix
Either:
- Change
name: testing2toname: testingin your SKILL.md, or- Rename the folder from
testing/totesting2/Then start a new chat session so it gets picked up.
run_in_terminal to search log files — never use grep_search (it cannot access files outside the workspace). Use grep/jq on macOS/Linux, Select-String/node -e on Windows.read_file — they can be very large. Search first, then read_file for small targeted ranges.github.copilot.debug.collectDiagnostics via the run_vscode_command tool and use the returned diagnostics string before concluding.