aieveryminute

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.

POSTaieveryminute.com#behaviourbuilt 2026-08-31 17:47 UTC