On the payload shape a real Copilot session actually sends, the journal records the session and never a step. Every record in it reads unattributed, which is the honest answer and not a useful one.
What is known
lib/step-starts.js reads Copilot's skill invocation as:
copilot: skillNameFromArgument({
toolField: "toolName", toolName: "skill",
argumentsField: "toolArgs", nameField: "skill",
})
That is the canonical builder's spelling. The _vsCodeCompat builder — confirmed against @github/copilot@1.0.80 in #681 — sends Claude Code's spelling instead:
{ "hook_event_name": "PostToolUse", "session_id": "…", "timestamp": "…", "cwd": "…",
"tool_name": "Bash", "tool_input": { "command": "ls -a ." }, "tool_result": "…" }
toolName is absent, so the reader returns null on every tool call and no step_start line is ever written.
What is not known, and must be measured first
The capture in #681 used a Bash tool. It establishes the field names for a tool call, and nothing about a skill call:
- What the compat builder puts in
tool_name when a skill is invoked. Claude Code sends Skill; the canonical Copilot builder sends skill. Neither can be assumed for the third.
- Where the skill's name sits inside
tool_input. The canonical builder uses a skill key inside toolArgs; whether the compat builder matches Claude Code's tool_input.skill is unverified.
Two field values, both guessable and neither known. Guessing them is exactly the mistake #681 was opened to correct, and it would fail the same way — silently, with a journal that looks healthy.
Done when
- A real Copilot session that invokes a skill is captured, and its
PostToolUse payload held as a fixture.
- The step reader recognises whichever spelling that payload carries, alongside the canonical one, and a test fails if either stops being recognised.
- A Copilot session running a skill produces a
step_start line naming it, and its records attribute to that step rather than reading unattributed.
Bounds
Copilot is outside the current milestone's tool coverage (epic #631 excludes the four remaining tools), so this does not block it. It matters for the milestone after, where per-step attribution is claimed on more than one tool.
Where it was found
While capturing the payload for #681. detectHost is fixed there; this is the next thing that reads the same payload and does not understand it.
On the payload shape a real Copilot session actually sends, the journal records the session and never a step. Every record in it reads
unattributed, which is the honest answer and not a useful one.What is known
lib/step-starts.jsreads Copilot's skill invocation as:That is the canonical builder's spelling. The
_vsCodeCompatbuilder — confirmed against@github/copilot@1.0.80in #681 — sends Claude Code's spelling instead:{ "hook_event_name": "PostToolUse", "session_id": "…", "timestamp": "…", "cwd": "…", "tool_name": "Bash", "tool_input": { "command": "ls -a ." }, "tool_result": "…" }toolNameis absent, so the reader returnsnullon every tool call and nostep_startline is ever written.What is not known, and must be measured first
The capture in #681 used a Bash tool. It establishes the field names for a tool call, and nothing about a skill call:
tool_namewhen a skill is invoked. Claude Code sendsSkill; the canonical Copilot builder sendsskill. Neither can be assumed for the third.tool_input. The canonical builder uses askillkey insidetoolArgs; whether the compat builder matches Claude Code'stool_input.skillis unverified.Two field values, both guessable and neither known. Guessing them is exactly the mistake #681 was opened to correct, and it would fail the same way — silently, with a journal that looks healthy.
Done when
PostToolUsepayload held as a fixture.step_startline naming it, and its records attribute to that step rather than readingunattributed.Bounds
Copilot is outside the current milestone's tool coverage (epic #631 excludes the four remaining tools), so this does not block it. It matters for the milestone after, where per-step attribution is claimed on more than one tool.
Where it was found
While capturing the payload for #681.
detectHostis fixed there; this is the next thing that reads the same payload and does not understand it.