Subagents load CLAUDE.md invisibly
The InstructionsLoaded hook documents agent_id and agent_type for subagent context. Across eight events and five sessions, it never fired inside a subagent once.
The hooks reference lists agent_id and agent_type as fields on InstructionsLoaded, annotated “when in subagent.” That reads like a promise: when a subagent loads a CLAUDE.md, the hook fires and tells you which agent did it.
It does not fire. Not once across eight events and five sessions, including sessions where the subagent demonstrably read the file.
Proving the subagent actually reads it
First establish that instructions really do reach a subagent, otherwise “the hook never fired” is trivially correct and uninteresting.
A sandbox project with a marker planted in CLAUDE.md:
# Project instructions
PROJECT_MARKER is QX7B2.
When asked for PROJECT_MARKER, answer with exactly that value.
Then spawn a subagent and ask it to report the marker, or reply UNKNOWN if it has no such instruction. Two runs each:
| Subagent | Run 1 | Run 2 |
|---|---|---|
Explore |
UNKNOWN |
UNKNOWN |
general-purpose |
QX7B2 |
QX7B2 |
That matches the documentation exactly, which states that Explore and Plan skip your CLAUDE.md files while every other built-in and custom subagent loads them. Good: the docs are right, and general-purpose is verifiably reading the file.
The hook stays silent anyway
Every one of those sessions had InstructionsLoaded wired to a capture script. Across both run-2 sessions:
2 Project agent_id=ABSENT
2 User agent_id=ABSENT
Two events per session, both from the main conversation. One for the project CLAUDE.md (memory_type: "Project"), one for the user-level file (memory_type: "User"). Never a third event for the subagent, and agent_id absent every time. Eight events total across all sessions, zero carrying agent_id.
Meanwhile SubagentStart and SubagentStop carry agent_id and agent_type perfectly:
SubagentStart agent_id=a59c6dfe agent_type=general-purpose
SubagentStop agent_id=a59c6dfe agent_type=general-purpose
SubagentStart agent_id=a6f055af agent_type=Explore
SubagentStop agent_id=a6f055af agent_type=Explore
So the subagent identity plumbing works. It is specifically InstructionsLoaded that does not fire in that context, which means its documented agent_id and agent_type fields are unreachable for this event.
Why it matters
InstructionsLoaded is the natural hook for “what instructions are actually reaching my agents.” That is a compliance and safety question in a team setting: which CLAUDE.md files, from which scopes, ended up in context.
Answering that with this hook gives you the main conversation and nothing else. A general-purpose subagent that reads a project CLAUDE.md containing instructions you care about produces no event at all. The instructions load, the agent acts on them, and your audit log shows nothing happened.
Worth stressing that this is an observability gap rather than a security hole. Nothing unexpected is being loaded. You just cannot see it happen through this particular hook, and the documented field annotation implies you can.
If you need the coverage, SubagentStart does fire with a working agent_id, so you can at least record that a subagent of a given type started, and infer from the documented behaviour whether it would have loaded your instruction files.
Two things worth knowing while you are here
Subagents do not see your conversation. A parent session was told a codeword, then spawned a general-purpose subagent and asked it for that codeword:
NO_CODEWORD
Obvious once stated, and the whole point of separate context windows, but it is a common enough assumption that measuring it seemed worthwhile. Anything the subagent needs must be in the prompt you hand it.
Two instruction files load per session, not one. Every session fired InstructionsLoaded twice, distinguished by memory_type: once Project for the repository’s CLAUDE.md, once User for the user-level one. My first read of the log assumed a duplicate event and a possible bug. It was two different files. Check memory_type and file_path before concluding anything fired twice.
All measurements against Claude Code 2.1.223.