Subagent audit trail: a practical guide

A subagent is the actor your audit trail usually misses. A parent spawns it, hands it the parent's credentials to save time, and its calls disappear into the parent's identity in every log. A real subagent audit trail starts by treating the spawned agent as its own actor and recording it as one. Here is the setup, step by step.

Step 1: give the subagent its own identity

Stop handing down the parent's credential. The subagent gets a scoped identity of its own at spawn time, tied to the run that created it. Without this, every later step is recording the wrong actor.

Step 2: scope it to its slice of the task

A subagent built to summarize one customer's tickets should reach that customer's tickets, not the whole table. Scope the identity to the slice it owns, so the subagent audit trail is short and its boundaries are obvious.

Step 3: record every call at the boundary

Capture each call the subagent makes, its target, arguments, and result, on the path the calls travel rather than inside the subagent. Keep denied calls; a subagent reaching past its slice is your earliest signal.

Step 4: mask sensitive output inline

Redact sensitive fields before they reach the subagent and before they land in the record, so neither the subagent nor its log becomes a copy of data it should not hold.

Why steps 1 to 4 are one thing

These steps only hold if they run somewhere the subagent cannot reconfigure. The architectural requirement is a scoped identity, a policy check before each call, and a tamper-proof record, all at a boundary outside the subagent. hoop.dev is built to that boundary: the subagent reaches data through it under a scoped identity, every read lands in a command-level audit, and sensitive fields return redacted. In practice you put the data a subagent reads behind hoop.dev and stop sharing the parent's keys. The getting-started guide walks through the first connection, and hoop.dev/learn covers scoped identity in depth.

Step 5: watch volume and destination

Once the subagent has its own identity and its calls are recorded, the last step is to actually read what you captured. Two signals catch most problems. Volume: a subagent pulling ten thousand rows when its task needed ten is reaching past its slice, whether by a bug or by manipulation. Destination: a subagent reaching toward a system its task never mentioned is the clearest sign something has gone wrong. Both only become visible because the subagent audit trail records its reads against its own identity rather than blurring them into the parent's.

Verify the setup

Confirm the four steps actually hold before you trust them. Spawn a subagent and have it attempt a read outside its assigned slice. The read should fail because the scoped identity cannot reach it, the attempt should appear in the record attributed to the subagent, and any sensitive field it did legitimately read should come back masked. If the read succeeds, the scope is too broad. If the attempt is missing from the trail, you are still recording inside the subagent rather than at the boundary. If a secret shows up unmasked, the masking is not applied where it needs to be. A subagent audit trail that passes this check is one you can rely on during an actual investigation.

Try it on one subagent

hoop.dev is open source. From the GitHub repository, give one subagent its own identity behind it and confirm the trail names it, not the parent.

FAQ

Why not just trust internal subagents?

Internal does not mean low-risk. A subagent with the parent's broad access and no record of its own is a quiet path for data to leave.

Does masking break its task?

It redacts only where the task does not justify raw data. If the subagent needs the real value, policy allows it and the read is logged.

How is a subagent different from a service account?

A service account is static and shared. A subagent is spawned on demand and acts on a run's behalf, so it needs an identity tied to that run, not a standing key. The subagent audit trail records what it did under that per-run identity, which a shared service account can never give you.