Skip to content

feat(cli): a record names the skill its own prompt invoked - #783

Merged
blafourcade merged 1 commit into
nextfrom
feat/a-prompt-that-invoked-a-skill-names-it
Sep 6, 2026
Merged

feat(cli): a record names the skill its own prompt invoked#783
blafourcade merged 1 commit into
nextfrom
feat/a-prompt-that-invoked-a-skill-names-it

Conversation

@blafourcade

Copy link
Copy Markdown
Contributor

Why

prompt-matched is the strongest attribution the report has — an identifier two sources agree on, where journal-interval is an inference from moments. It read one source: a step_start the 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 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:

before 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: 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 step

step 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 billed lines | 20 carry attributionSkill

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:

6,215 stamped | 6,136 match | 79 differ | 0 unknown

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 Skill call. Two more on the report side: a session the journal never saw, and the journal winning where both answer.

Mutations run, three killed:

Mutation Red
the last skill of a prompt wins instead of the first 1
every tool_use counts, not only Skill 1
the record outranks the journal 1

3,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

@blafourcade
blafourcade requested a review from a team as a code owner September 5, 2026 21:11
`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
blafourcade force-pushed the feat/a-prompt-that-invoked-a-skill-names-it branch from 5710000 to 7684ec9 Compare September 6, 2026 03:08
@blafourcade
blafourcade merged commit 7fbe889 into next Sep 6, 2026
17 checks passed
@blafourcade
blafourcade deleted the feat/a-prompt-that-invoked-a-skill-names-it branch September 6, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant