Fix Claude Code's Incorrect Skill Tool Agent IDs
Hey everyone, let's dive into a pretty specific but important bug that's been popping up with the Claude Code CLI, specifically affecting Skill tools when they fire a PostToolUse hook event. If you're building custom tooling or integrations around Claude Code, this is something you'll want to be aware of. We're talking about a situation where the agentId you get back in the PostToolUse response just doesn't match the actual agent transcript file created on disk. It’s a bit of a head-scratcher, but don't worry, we'll break down what's happening, why it matters, and how to potentially navigate it.
The Core Issue: Mismatched agentId in PostToolUse Events
So, the main headache here is pretty straightforward: when a Skill tool finishes its job and triggers a PostToolUse hook, the agentId included in that response is incorrect. To clarify, a Skill tool is essentially a more complex operation, often involving a sequence of steps or a more involved process compared to a simpler Task tool. When these Skill tools run, they might create their own sub-processes or agents to handle their execution. The PostToolUse hook is supposed to give you a heads-up about this and provide an identifier, the agentId, that links you back to the specific transcript file for that subagent. The problem is, the agentId in the PostToolUse response is not matching the filename of the actual transcript file that gets created in your ~/.config/claude/projects/<project>/<session_id>/subagents/ directory. This makes it super difficult, if not impossible, to programmatically link the event data you receive with the actual logged output of the subagent.
For example, let's say the PostToolUse event comes back with agentId: "ae2fbc4". You'd expect to find a file named something like agent-ae2fbc4.jsonl in your subagents directory. But, in this bug scenario, you'd actually find a file like agent-a674f5e.jsonl. See the disconnect? The IDs are completely different. This isn't just a minor cosmetic issue; it has real-world consequences for anyone trying to build automation or analyze the behavior of these tools. It breaks the chain of traceability that the agentId is intended to provide. We've seen this specifically with the committing-changes skill, but it could potentially affect other Skill tools as well. It's crucial for debugging, auditing, and building robust integrations that these identifiers are accurate and reliable.
How to Spot the Bug: Step-by-Step
To really get a handle on this bug, you need to trigger it and then compare the information you get from the hook event with what's actually on your filesystem. It’s a pretty direct process:
- Invoke a Skill Tool: The first step is to get a Skill tool to run. The example provided uses the
committing-changesskill, which is a good one to test with if you're familiar with it. You'd typically run this from your Claude Code CLI. - Capture the
PostToolUseHook Event: As the Skill tool executes, it will eventually fire aPostToolUsehook. You need to capture the data payload that this hook event sends. This is usually done by setting up listeners or hooks in your custom scripts or monitoring tools that interact with the Claude Code CLI. The event data will contain fields likehook_event_name,tool_name,tool_use_id,tool_input, and importantly,tool_response. - Examine the
tool_response.agentId: Within the capturedPostToolUseevent data, focus on thetool_responseobject. You'll find anagentIdfield here. This is the ID that the system thinks corresponds to the subagent transcript. - Locate the Actual Transcript File: Now, you need to check your local filesystem. Navigate to the directory where Claude Code stores its session data. This is typically located at
~/.config/claude/projects/<project>/<session_id>/subagents/. Inside this directory, you'll find files named likeagent-<some-id>.jsonl. These are the actual transcript files for the subagents that were created during the session. - Compare the IDs: This is the moment of truth. Compare the
agentIdyou found in thetool_responsefrom the hook event with the ID part of the filename of theagent-*.jsonlfiles in the subagents directory. If they don't match, you've encountered the bug.
It's worth noting that Task tools, which are generally simpler than Skill tools, seem to be working correctly. The agentId returned for Task tool invocations does match the corresponding transcript file. This contrast highlights that the issue is specifically tied to the way Skill tools handle their agentId reporting during the PostToolUse event.
What's Expected vs. What's Happening
Let's lay out the ideal scenario versus the reality of this bug. Understanding the expected behavior is key to appreciating why this issue is problematic.
Expected Behavior: A Perfect Match
In a perfect world, when a Skill tool finishes its execution and fires a PostToolUse hook, the agentId provided in the tool_response should be a direct, unambiguous pointer to the specific subagent transcript file generated for that particular operation. So, if the PostToolUse response tells you agentId: "ae2fbc4", you should be able to go straight to your subagents directory (~/.config/claude/projects/<project>/<session_id>/subagents/) and find a file named precisely agent-ae2fbc4.jsonl. This direct correlation is crucial because it allows developers and automated systems to reliably:
- Trace Execution: Easily link an event notification (like a tool use) to its detailed execution log.
- Debug Issues: Quickly find the logs for a specific subagent if something went wrong during a Skill tool's execution.
- Build Integrations: Create tools that can react to or process the output of specific subagents based on event data.
- Audit Operations: Maintain a clear record of which tool use corresponds to which logged sub-process.
This consistency ensures that the agentId acts as a reliable key, forming a solid bridge between the event system and the persistent storage of execution data. It’s the intended design, and it’s how things should work to make the system predictable and manageable.
Actual Behavior: A Tangled ID
The reality, as described in the bug report, is quite different. When the PostToolUse event fires for a Skill tool, the agentId included in the tool_response is, well, wrong. Let's revisit the example: the PostToolUse response might state agentId: "ae2fbc4". However, if you dutifully navigate to the subagents directory and look for that ID, you won't find it. Instead, you might discover a file named agent-a674f5e.jsonl. The discrepancy is clear: the ID reported in the event (ae2fbc4) does not match the ID used for the actual transcript file (a674f5e).
This mismatch breaks the expected linkage. You receive an event notification pointing to one identifier, but the corresponding log file uses a completely different one. This makes it impossible to use the agentId from the PostToolUse event as a reliable way to locate the relevant subagent transcript. It introduces ambiguity and frustration for anyone relying on this data for automation, debugging, or analysis. It’s like getting a return address on an envelope, but the letter inside is addressed to someone else entirely. This is a significant deviation from the expected behavior and directly impacts the usability of the hook events for tracking Skill tool sub-processes.
Why This Matters: The Impact on Your Workflow
Okay, so we've established that the agentId in the PostToolUse event for Skill tools isn't matching the actual transcript filenames. But why should you, as a user or developer, really care? The impact, while perhaps subtle at first glance, can be quite significant, especially if you're building anything that relies on the output or traceability of these tools. Let's break down the consequences:
- Broken Correlation: The most direct impact is that any tooling, scripts, or monitoring systems you've built to correlate
PostToolUseevents with their corresponding subagent transcripts will simply fail. TheagentIdis supposed to be the golden key, the unique identifier that links the notification you receive (the event) to the detailed record of what happened (the transcript file). When this link is broken, your systems can't find the right information. Imagine trying to look up a customer in a database using their name, but the database only has their phone number, and the name you have is misspelled. You're stuck! - Debugging Nightmares: When a Skill tool fails or behaves unexpectedly, your first step is often to examine the logs. If you're relying on hook events to tell you which subagent's logs to look at, this bug makes that process incredibly difficult. You might see an event indicating a tool use, but you won't be able to reliably find the specific
*.jsonlfile associated with that invocation. This significantly increases the time and effort required to diagnose and fix problems within your Claude Code workflow. - Hindered Automation: Many advanced use cases involve automating responses or actions based on the completion of specific tool steps. For example, you might want to trigger a notification or a further processing step once a
committing-changesskill has successfully completed and logged its output. If you can't reliably identify the specific subagent log associated with that skill invocation via theagentId, your automation becomes unreliable or impossible to implement correctly. - Reduced Auditability and Traceability: In professional or complex project environments, maintaining a clear audit trail is essential. You need to be able to track exactly what happened, when, and how. This bug undermines that traceability. If the
agentIdreported doesn't match the actual log file, it becomes harder to confidently reconstruct the sequence of operations and verify the integrity of the process.
It's important to note the contrast provided in the bug report: Task tools work correctly. The agentId returned for Task tool use does match the transcript file. This suggests the issue is specific to the implementation details of how Skill tools generate or report their agentId during the PostToolUse phase. This distinction is valuable because it helps narrow down the potential source of the bug and indicates that not all tool types are affected equally. However, for anyone heavily utilizing Skill tools, this bug represents a significant roadblock to building robust and observable systems on top of the Claude Code CLI.
Evidence: Seeing is Believing
Sometimes, words aren't enough. To really drive home the point about this Skill tool agentId discrepancy, the bug report includes a neat table that clearly illustrates the problem. This isn't just a theoretical issue; it's a demonstrable one. Let's break down what this evidence tells us:
| Tool | Response agentId |
Transcript File | Match |
|---|---|---|---|
| Task | aa94c92 |
agent-aa94c92.jsonl |
✅ |
| Task | abbcbfa |
agent-abbcbfa.jsonl |
✅ |
| Skill | ae2fbc4 |
agent-a674f5e.jsonl |
❌ |
As you can see, the first two rows show the expected behavior with Task tools. When a Task tool runs, the agentId you receive in the response (e.g., aa94c92) perfectly matches the identifier in the corresponding transcript filename (agent-aa94c92.jsonl). This is exactly what we want – a clear, direct link. The checkmark (✅) signifies that everything is working as intended for these standard Task operations.
Now, look at the third row, which highlights the problem with Skill tools. The PostToolUse response reports an agentId of ae2fbc4. However, the actual transcript file created on disk is named agent-a674f5e.jsonl. The agentId from the response (ae2fbc4) and the ID in the filename (a674f5e) are completely different. The cross mark (❌) unmistakably shows that there's a failure in matching. This contrast is crucial. It demonstrates that the bug isn't a system-wide failure of agentId reporting but is specifically related to how Skill tools handle this reporting mechanism during the PostToolUse event.
Furthermore, the bug report provides a concrete example of the PostToolUse Event Data for a Skill invocation. Let's look at that snippet:
{
"hook_event_name": "PostToolUse",
"tool_name": "Skill",
"tool_use_id": "toolu_01SKyuBnaNn9aN23NuuTXC8p",
"tool_input": {
"skill": "committing-changes"
},
"tool_response": {
"status": "forked",
"agentId": "ae2fbc4",
"commandName": "committing-changes"
}
}
This JSON payload clearly shows the agentId: "ae2fbc4" within the tool_response. This is the ID that should, ideally, correspond to the filename. However, as the table and the description indicate, the actual file created will have a different ID. This specific piece of evidence is invaluable for developers trying to debug the issue, as it provides the exact structure and content of the problematic event.
Environment and Context
This bug has been observed within a specific environment, which is important context for anyone trying to reproduce or fix it. The issue appears primarily when using the Claude Code CLI on macOS. This suggests that the problem might be related to how file paths, process management, or environment variables are handled on macOS, or perhaps it's specific to the CLI implementation itself. While it's possible the underlying issue could exist on other operating systems, the reported instances are tied to this setup. Understanding the environment helps in pinpointing potential causes, such as differences in file system behavior, process IDs, or asynchronous operations that might be handled differently across operating systems. If you're encountering similar issues on other platforms, it might be worth investigating if they share underlying components or dependencies that could be affected by this bug. For now, the focus is on the macOS Claude Code CLI environment.