Summary
For OpenCode sessions, the skills and subagents report sections are always empty, even when skills and subagents are heavily used. The tools table correctly shows aggregate Skill and Agent call counts, so the tool invocations are being read — but the per-call name (which skill / which subagent) is never extracted, so the dedicated breakdowns stay empty.
This is not the same as #336 (Claude CLI / Gemini subagent tool-call tracking) or #308 (OpenCode MCP attribution). This is specifically the OpenCode skill / task tool argument extraction for the skills and subagents sections.
Environment
- CodeBurn:
0.9.12 (global npm install)
- OpenCode:
1.17.9
- macOS 26.5.1 (arm64)
- OpenCode storage:
~/.local/share/opencode/storage/
Evidence
codeburn report --period 30days --format json returns:
{
"skills": [],
"subagents": [],
"tools": [
{ "name": "Skill", "calls": 203 },
{ "name": "Agent", "calls": 339 },
...
]
}
So 203 skill calls and 339 subagent (Agent) calls are counted, but skills and subagents are both [].
Root cause
In OpenCode's on-disk format, each tool call is a separate JSON file under ~/.local/share/opencode/storage/part/<messageID>/<partID>.json. The skill/subagent name lives in state.input, not in the tool name. The parser appears to count the tool by name (skill/task) but never joins state.input to recover the name.
Skill call part (tool: "skill"):
{
"type": "tool",
"tool": "skill",
"callID": "...",
"state": { "input": { "name": "plan-spec" } }
}
Subagent call part (tool: "task"):
{
"type": "tool",
"tool": "task",
"callID": "...",
"state": {
"input": {
"description": "Find service connection code",
"prompt": "...",
"subagent_type": "explore"
}
}
}
Note: in the part files the tool names are lowercase (skill, task), while the tools report displays them capitalised (Skill, Agent) — so there is name normalisation happening for the count path but not the breakdown path.
Expected behaviour
skills[] populated, grouped by state.input.name from skill tool parts (e.g. plan-spec), with call counts and token/cost.
subagents[] populated, grouped by state.input.subagent_type from task tool parts (e.g. explore), with call counts and token/cost.
Suggested fix
When parsing OpenCode part files, for tool === "skill" read state.input.name, and for tool === "task" read state.input.subagent_type (fall back to description), then attribute those to the skills / subagents aggregations the same way the tools count is already attributed.
Summary
For OpenCode sessions, the
skillsandsubagentsreport sections are always empty, even when skills and subagents are heavily used. Thetoolstable correctly shows aggregateSkillandAgentcall counts, so the tool invocations are being read — but the per-call name (which skill / which subagent) is never extracted, so the dedicated breakdowns stay empty.This is not the same as #336 (Claude CLI / Gemini subagent tool-call tracking) or #308 (OpenCode MCP attribution). This is specifically the OpenCode
skill/tasktool argument extraction for theskillsandsubagentssections.Environment
0.9.12(global npm install)1.17.9~/.local/share/opencode/storage/Evidence
codeburn report --period 30days --format jsonreturns:{ "skills": [], "subagents": [], "tools": [ { "name": "Skill", "calls": 203 }, { "name": "Agent", "calls": 339 }, ... ] }So 203 skill calls and 339 subagent (Agent) calls are counted, but
skillsandsubagentsare both[].Root cause
In OpenCode's on-disk format, each tool call is a separate JSON file under
~/.local/share/opencode/storage/part/<messageID>/<partID>.json. The skill/subagent name lives instate.input, not in the tool name. The parser appears to count the tool by name (skill/task) but never joinsstate.inputto recover the name.Skill call part (
tool: "skill"):{ "type": "tool", "tool": "skill", "callID": "...", "state": { "input": { "name": "plan-spec" } } }Subagent call part (
tool: "task"):{ "type": "tool", "tool": "task", "callID": "...", "state": { "input": { "description": "Find service connection code", "prompt": "...", "subagent_type": "explore" } } }Note: in the
partfiles the tool names are lowercase (skill,task), while thetoolsreport displays them capitalised (Skill,Agent) — so there is name normalisation happening for the count path but not the breakdown path.Expected behaviour
skills[]populated, grouped bystate.input.namefromskilltool parts (e.g.plan-spec), with call counts and token/cost.subagents[]populated, grouped bystate.input.subagent_typefromtasktool parts (e.g.explore), with call counts and token/cost.Suggested fix
When parsing OpenCode
partfiles, fortool === "skill"readstate.input.name, and fortool === "task"readstate.input.subagent_type(fall back todescription), then attribute those to theskills/subagentsaggregations the same way thetoolscount is already attributed.