feat(cli): a record names the skill its own prompt invoked - #783
Merged
Conversation
`prompt-matched` read one source: a `step_start` the run journal wrote with the prompt's own identifier. A session that ran before the hook was installed has no such line, so 9 records of 31,225 were named that way. The transcript holds the same fact. Every `Skill` call sits in a prompt, and the reader already resolves each record's prompt by walking `parentUuid`. It now also remembers, per prompt, the skill a `Skill` call started there, and stores it as `prompt_skill`. Measured on the real sink, 30 days, before and after: prompt-matched 9 -> 4,322 by_step named 11.5% -> 25.3% An observation, never a judgement. Which step a record belongs to is derived fresh on every report, from this and from the journal together; the journal wins where both name a skill for the same prompt, since it was written by a hook the host fired while this is read back afterwards. It does not duplicate `step`. That one reads `attributionSkill`, which Claude Code writes per message: exact where it appears and sparse where it does not. Measured inside the window `aidd-dev:01-plan` demonstrably ran on 2026-09-04, 142 lines carry counters and 20 carry that field — so its absence is not the tool saying no skill ran, and this contradicts nothing it states. The doc comment claiming otherwise is corrected. Scoped to the transcript the record sits in, which is what the reader accumulates. Claude Code writes a session's subagents to their own files, and 1,038 of 5,564 prompts on this machine appear in more than one. A subagent that invoked its own skill did that work under that skill; merging files first would have to pick one answer for both, and neither is true of both. Verified against an independent recomputation over every transcript, main files and subagent trees alike: of 6,215 stamped records, 6,136 match. The 79 that do not are prompts spanning two files, where the check merged what the reader keeps separate — the looser reading is the check's, not the code's. Four cases written before the code, two red at the start. Mutations run, three killed: the last skill of a prompt winning instead of the first, every `tool_use` counting rather than only `Skill`, and the record outranking the journal. 3,477 CLI tests, 371 repository script tests, typecheck, biome, knip, jscpd, layering, bundle 596.6 / 598 KB, 0 broken links in 798 files. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp AIDD-Session-Id: 2c21d903-3a7e-47ac-83f8-d8b7ae3aa579
blafourcade
force-pushed
the
feat/a-prompt-that-invoked-a-skill-names-it
branch
from
September 6, 2026 03:08
5710000 to
7684ec9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
prompt-matchedis the strongest attribution the report has — an identifier two sources agree on, wherejournal-intervalis an inference from moments. It read one source: astep_startthe run journal wrote carrying the prompt's own id. A session that ran before the hook was installed has no such line.Result: 9 records of 31,225 were named that way.
What changes
The transcript holds the same fact. Every
Skillcall sits in a prompt, and the reader already resolves each record's prompt by walkingparentUuid. It now also remembers, per prompt, the skill aSkillcall started there, and stores it asprompt_skill.Measured on the real sink, 30 days, before and after:
prompt-matchedby_stepnamedAn observation, never a judgement
Which step a record belongs to is derived fresh on every report, from this and from the journal together. The journal wins where both name a skill for the same prompt: it was written by a hook the host itself fired, where this is read back off a transcript afterwards.
Stored rather than recomputed because the report never re-reads a transcript — it reads the sink and the journals beside it, so an observation only a transcript holds has to be written down when it is read or it is gone.
It does not duplicate
stepstepreadsattributionSkill, which Claude Code writes per message: exact where it appears and sparse where it does not. Measured inside the windowaidd-dev:01-plandemonstrably ran on 2026-09-04:So its absence is not the tool saying no skill ran, and naming the skill a prompt invoked contradicts nothing it states. The source comment claiming the field is omitted "when no skill is running" is corrected — that claim was measurably false, and it is the one that made this look like it would contradict an observation.
Scoped to one transcript
Claude Code writes a session's subagents to their own files under
<sessionId>/subagents/, and a prompt is often spread across several — 1,038 of 5,564 prompts on this machine appear in more than one file. A record names the first skill invoked inside its prompt in the file it sits in. A subagent that invoked its own skill did that work under that skill; merging files first would have to pick one answer for both, and neither is true of both.Verified against an independent recomputation
Every transcript on the machine, main files and subagent trees alike, re-derived from scratch and compared to the stamped records:
The 79 are prompts spanning two files, where the check merged what the reader keeps separate. The looser reading there is the check's, not the code's — and finding that out is what produced the paragraph above.
Tests
Four cases written before the code, two red at the start: the skill a prompt invoked; a prompt that invoked none; the first of several; a tool call that is not a
Skillcall. Two more on the report side: a session the journal never saw, and the journal winning where both answer.Mutations run, three killed:
tool_usecounts, not onlySkill3,477 CLI tests, 371 repository script tests, typecheck, biome, knip, jscpd, layering, bundle 596.6 / 598 KB, 0 broken links in 798 files.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VWNxk63AGKkqE8HRqHLjGp