Manav.id
Agents ยท 19 min read

When one person runs three hundred agents, who did what?

An audit log that names a person is correct and useless once that person runs nine agents. Identity fan-out is the gap between one accountable human and the many actors working in their name. The fix is not more logging. It is a tree.

The incident review starts at nine on a Thursday. Someone changed a production feature flag at 02:14, a checkout path went to ten percent of traffic for eleven minutes, and revenue for those eleven minutes is a hole in the dashboard. The room wants to know who did it.

The audit log is unambiguous. It says sarah.chen@. It has a timestamp, a source IP that resolves to the company VPN, a valid session identifier, and a clean chain of custody from the identity provider. Everything about the record is well formed. Nothing about it is disputed.

Sarah was asleep at 02:14. She is also, it turns out, running nine agents. There is a coding agent with repository write access, a deployment agent that watches for merged pull requests, an on call triage agent she set up in March that has permission to toggle flags during an incident, a browser agent, an email agent, two research agents, a calendar agent, and something she describes to the room as "an old script that got upgraded." Each of them holds a token minted under her account. Each of them, from the perspective of every system it touches, is Sarah.

Somebody asks the obvious question: can we tell which one? And the answer, after forty minutes of pulling logs from four systems, is no. Not because the logging is bad. The logging is excellent. It is because the log has one field for who, that field holds a user identifier, and a user identifier can no longer answer the question it was designed to answer.

Short answer. Identity fan-out is the ratio of acting agents to one accountable human. Once that ratio passes one, a user identifier stops being an answer to "who did this" and becomes a category. The fix is to model identity as a tree: one human root key, one delegated key per agent carrying scope and depth, and a receipt on every action naming the delegation it acted under. Attribution then becomes a walk from the action back to the human, verifiable by any service, instead of an investigation.

What is identity fan-out?

Identity fan-out is the number of distinct actors taking consequential actions in the name of a single accountable human. For most of computing history that number was one, and an enormous amount of infrastructure quietly assumes it still is.

The assumption is everywhere once you start looking. Rate limits are calibrated to the speed a person can click. Audit schemas have a single actor column. Session models assume one intent per session because a person can only want one thing at a time. Access reviews ask a manager to confirm that a person should still have a permission, which presumes the person is the one exercising it. Anomaly rules flag a login from two countries in an hour because a body cannot be in two places at once. All of that is reasonable. None of it survives a person who has delegated their working hours to a fleet.

We have been here before, in smaller ways, and the history is instructive because it shows the pattern of the fix. When multiple administrators shared a root account, the answer was sudo, which kept the privilege but recorded which human invoked it. When applications needed to act for users, the answer was per application OAuth grants, which kept the delegation but scoped it and made it revocable. When machines needed to talk to machines, the answer was service accounts, which gave the machine its own principal instead of borrowing a person's.

Each of those was a real advance and each solved a smaller version of the current problem. What is different now is scale and initiative. A service account does one thing on a schedule. An agent decides what to do, calls other systems, and sometimes calls other agents. And where an organisation used to have a handful of service accounts per team, it now has a fleet per person.

The account was designed for someone who types

It is worth being precise about what breaks, because "the account model is outdated" is the kind of sentence that feels true and changes nothing.

An account is a bundle of four things that used to travel together: an identifier that says who you are, a credential that proves it, a set of permissions that says what you may do, and an implicit assumption that the entity holding the credential is the entity forming the intent. Agents break the fourth one. The credential is genuinely Sarah's, issued to Sarah, held on Sarah's behalf. The permissions are genuinely Sarah's. The intent belongs to a process that Sarah started at some point in the past, under conditions she may no longer remember, and which is now reasoning about a situation she has never seen.

That gap between "whose credential" and "whose intent" is the whole problem, and it does not get smaller by adding fields to a log. Manav's earlier writing on the hundred to one ratio covers the enterprise version of this, where non-human identities outnumber human ones by two orders of magnitude, and the Agent Density Index tracks how it varies by industry. Personal fan-out sits on top of that. The organisation has its fleet, and every person inside the organisation now has their own.

Why doesn't giving every agent its own identity fix it?

The first instinct of any competent platform team is right: stop letting agents borrow a human's credential, and give each agent its own. Do that. It is strictly better than the alternative, it makes rotation possible, and it means a compromised agent does not hand over the person's full authority.

It is also not sufficient, and the reason is worth slowing down for, because it is the crux of the entire post.

A crowd, or a tree

Picture a building with a thousand employees and no key register. Everyone has keys. The keys work. Every lock, when it opens, opens legitimately. Now something goes missing from a room on the fourth floor and you want to know who could have opened that door.

Your only method is observation. You put cameras in the corridors, you log every badge tap, you build a model of normal movement, and you flag anomalies. This works, in the sense that you will eventually catch someone. It also costs a fortune, it scales with the number of people rather than the number of doors, it generates false accusations, and it requires you to watch everybody all the time in order to know anything about anybody. That is a crowd. In a crowd, attribution is an investigation.

Now picture the same building where every key was cut from a parent key, and every parent key was cut from the master, and each cut is recorded on the key itself. Something goes missing. You look at the key that opened the door and read the lineage stamped into it. Two seconds, one lookup, no cameras. That is a tree. In a tree, attribution is a walk.

The difference is not a matter of degree. In a crowd, the cost of attribution grows with the population of actors. In a tree, it grows with the depth of the delegation, which is small and which you control. A thousand agents in a crowd is a surveillance problem. A thousand agents in a tree is a three step lookup that happens to run a thousand times.

This matters for a reason beyond efficiency. The crowd solution requires building exactly the thing that most organisations should not build and that most workers will not accept: continuous behavioural observation of everything that acts in their name. The tree solution requires no observation at all. It requires structure.

A thousand well formed strangers

Give each agent its own identity and no human anchor, and what you have built is a crowd with better paperwork. Every principal is well formed. Every token validates. Every action is legitimate at the point of use. And when you ask "which human stands behind agent 447", the honest answer is that a naming convention says one thing, a spreadsheet says another, and neither is evidence.

Self asserted labels are the specific trap here. Putting agent=triage-bot-v2 in a user agent string, or naming the service account svc-sarah-triage, feels like attribution. It is a claim made by the thing being attributed. A compromised agent will happily keep claiming to be svc-sarah-triage, and a well behaved one that gets its config copied will claim it too. The agent's own logs have the same problem. They are the defendant's diary.

What an identity provider can and cannot express

Ask your identity provider to express the sentence "this is agent fourteen of human H, acting under scope S, at delegation depth one, until Friday, revocable by H alone, and a third party who has never heard of us can check that." It cannot. Not because the vendors are behind, but because the data model has one principal per token and no notion of a chain.

You can approximate parts of it. OAuth 2.0 Token Exchange (RFC 8693) gives you an act claim that expresses "A acting for B", which is genuinely the right shape and is underused. Rich Authorization Requests (RFC 9396) let you express fine grained scope instead of a coarse string. Both help. Neither gives you an object that a service in another company can verify without calling your identity provider, and neither anchors the chain to a key the human actually holds. You are still asking every relying party to trust your tenant.

What actually breaks when attribution collapses onto a person?

Four things break, and they break in different departments, which is part of why the problem is hard to see whole. The security team sees one symptom, finance sees another, legal sees a third, and nobody puts them together.

Fan-out patternWhat it looks likeThe attribution question it breaks
Single assistantOne person, one general agent with broad accessWas this action the human or the assistant, and did the human see it?
Orchestrator with workersA planner agent spawning task agents on demandWhich worker acted, and was the orchestrator entitled to ask for that?
Organisational fleetCompany-run agents acting in a named employee's authorityWas this the person's intent or the fleet's policy, and who owns the outcome?
Agent to agent, cross-companyOur agent calls a partner's agent, which acts on its own sideWhose human is at the root, and do we accept a root we cannot see?
Inherited agentAn agent configured by someone who has since leftWho is accountable now, and what revoked when they were offboarded?

Blame lands on a name, not an actor

Return to Sarah. The incident record will say a human changed a flag at 02:14, because that is the only thing the record can say. Every downstream artifact inherits that: the postmortem, the access review that follows it, the risk register, and the quiet conversation with her manager. She will spend her credibility explaining a system's data model. Multiply that across an organisation and you get a specific, corrosive outcome: people stop delegating to agents in ways they would otherwise want to, not because it is unsafe but because they will personally absorb every ambiguity.

Rate limits punish the person for the fleet

Platforms see a burst of traffic under one identifier and do the only sensible thing available to them, which is to throttle that identifier. The human is now rate limited because their agents were busy. There have been reports through 2026 of large developer platforms straining under agent-generated load, including widely discussed figures for agent-opened pull requests, though the precise numbers vary by source and should be treated as directional rather than settled. The structural point does not depend on the number: when the platform can only see the account, the account is the only thing it can limit.

Audit answers the wrong question

An audit trail exists to let someone reconstruct, after the fact, who did what and under what authority. Our earlier piece on audit trail design goes deep on the tamper evidence side. Fan-out attacks the semantics rather than the integrity. You can have a perfectly tamper evident log that is nonetheless unable to distinguish nine actors, which means your evidence is cryptographically sound and practically mute.

Liability was already decided, and it points at the human

This is the part that surprises engineers. The legal question of who is responsible when an automated process acts has largely been answered, and it was answered against the operator. The Uniform Electronic Transactions Act treats an electronic agent's actions as attributable to the person who deployed it, and the federal ESIGN Act takes a compatible position on automated transactions. The doctrine long predates language models and was written for order-entry systems, but the words apply.

Practically, that means the person is on the hook for everything their agents do, while having no artifact that distinguishes what each agent did. That is the worst possible combination: full liability, zero attribution. Under Article 14 of the EU AI Act, organisations deploying high risk systems also have human oversight and record keeping duties, which are difficult to discharge honestly when your records cannot name the actor.

How does a delegation tree turn attribution into a walk?

Here is the structure, built from the bottom up, with the actual fields.

At the root is the human's key. Not an account, not a session, a key that lives on a device the person controls and that signs things. This is the anchor, and everything else in the tree is reachable from it. When Sarah authorises her triage agent, she is not ticking a box in a console. She is signing a small object that says what that agent may do.

That object is a delegation. It names the key the agent will use, the actions it is allowed to take, the constraints on those actions, the window of time in which it is valid, how many further hops of delegation it may pass on, and an identifier that can be used to revoke it. Here is a real shape of one, for an on call triage agent.

{
  "iss": "manav:human:sarah.chen",        // root: the human's key
  "delegateKey": "ed25519:9f3c...a71b",   // the agent's own key
  "scope": {
    "actions": ["flag.toggle", "incident.comment"],
    "resources": ["service:checkout/flags/*"]
  },
  "constraints": {
    "requiresIncident": true,
    "maxTrafficPercent": 5,
    "environment": ["staging", "production"]
  },
  "notBefore": "2026-09-01T00:00:00Z",
  "notAfter":  "2026-09-30T00:00:00Z",
  "maxChainDepth": 1,
  "revocationId": "rev:8c21f0e4",
  "sig": "ed25519:5b90...c3f2"            // signed by the human root key
}

Read that as a sentence and it says something no user identifier can say. Sarah, holding this key, permits this specific agent key to toggle flags on checkout and comment on incidents, only during an incident, only up to five percent of traffic, only during September, may not pass this authority to anyone else, and any of this can be revoked by referencing rev:8c21f0e4.

Now the agent acts. It toggles the flag. The action produces a receipt: a signed record of what was done, by which key, under which delegation. The receipt carries the delegation identifier, which is the thread back up the tree. When the incident review pulls that record on Thursday morning, the question "which agent" is answered by reading a field, and the question "was it allowed to" is answered by verifying signatures.

The walk, in code

Attribution becomes a loop that terminates at a human key. This is deliberately unexciting, which is the point.

function attribute(receipt) {
  let node = receipt.delegation;      // the grant the action ran under
  const path = [receipt.actorKey];
  let depth = 0;

  while (node) {
    assert(verifySignature(node), "broken link in chain");
    assert(now() >= node.notBefore && now() <= node.notAfter, "expired grant");
    assert(!isRevoked(node.revocationId), "revoked grant");
    assert(depth <= node.maxChainDepth, "delegation deeper than permitted");
    assert(covers(node.scope, receipt.action), "action outside granted scope");

    path.push(node.delegateKey);
    if (node.iss.startsWith("manav:human:")) return { human: node.iss, path };
    node = node.parent;               // one hop up the tree
    depth++;
  }
  throw new Error("no human root: unattributable action");
}

Two properties of that loop are worth naming explicitly. First, it terminates at a human or it throws. There is no third outcome where you get a plausible-looking answer that is really a guess. An action either has a path to an accountable person or it is flagged as unattributable, which is itself extremely useful information that most systems cannot currently produce.

Second, none of it requires calling us. The signatures verify against published keys. A partner company receiving a request from your agent can run this walk without an account, without a network call to your identity provider, and without trusting your tenant. That is what makes it work across organisational boundaries, which is where the agent to agent pattern lives.

Why maxChainDepth is the field that matters most

Of all the fields, the one that does the least obvious work is depth, and it is the one that will save you.

Agents spawn agents. An orchestrator decides a task needs three sub-tasks and creates three workers. Each worker might decide it needs a helper. Without a limit, authority granted once propagates outward indefinitely, and each hop is individually reasonable while the aggregate is something no human agreed to. Depth limiting is how you say "you may act, and you may ask one layer of helpers, and that is where this stops."

It is also the field that makes the honest conversation possible with a security team, because it converts an unbounded worry into a number they can set. Depth zero means the agent acts alone. Depth one covers the common orchestrator pattern. Depth two is where most organisations should stop and require a fresh human signature rather than another hop. Our piece on how delegation tokens work walks the token mechanics in more detail.

What does a platform team actually have to decide?

The architecture is the easy half. These are the questions that come up in week two, and they have real answers.

How do you name three hundred agents?

Badly, if you do not decide early. The naming scheme that survives contact with a fleet is purpose plus owner plus generation, not cleverness. triage.oncall/sarah.chen/v3 tells an incident responder what it does, who is accountable, and that there were two earlier versions which may still hold grants. Avoid names that encode current permissions, because permissions change and the name becomes a lie. The delegation object holds the truth about scope, so the name only needs to hold identity.

How long should a delegation live?

Shorter than feels comfortable. The instinct is to issue year-long grants because re-signing is friction, and the result is a fleet nobody has reviewed since onboarding. A useful default is to match the delegation window to the work: an incident triage agent gets grants measured in weeks, a deployment agent in days, a one-off migration agent in hours. The tree makes this cheap because renewing a grant is signing one small object, not re-provisioning an account.

The related decision is what happens on expiry. Silent failure is the wrong answer, since it will happen at 02:14 during an actual incident. The agent should be able to request a fresh signature and route that request to the human, which is what an authorisation inbox is for. The agent authorization inbox queues exactly these requests for a human to sign.

What happens when the operator leaves the company?

This is where fan-out and offboarding collide, and it is the single most common way that an agent fleet turns into an orphaned one. When a person departs, their account is disabled. If their agents hold independently issued tokens, those tokens keep working, because nothing connected them to the person except a spreadsheet. One 2025 vendor analysis reported that the large majority of former-employee machine credentials remain active after offboarding, and while such vendor figures should be read as directional, the direction is not really in dispute among people who have run an access review.

In a tree, this is structurally different. Revoking the root revokes every grant beneath it, because every grant's validity depends on the chain above it. Offboarding becomes one operation with a defined blast radius that you can state in advance. That is not a small thing to be able to say to an auditor.

Be honest about the boundary: this holds for authority that flowed through delegations. If someone handed an agent a raw API key from a cloud console, that key is outside the tree, and revoking the root will not touch it. The tree makes the governed path clean; it does not magically find ungoverned credentials. Finding those is a different job, and our kill switch design piece covers the revocation mechanics.

How do you report fan-out to an auditor?

Auditors ask three questions about any delegated authority: who granted it, what does it permit, and how would you take it away. A tree answers all three from the same artifact, which is why this is worth doing before someone asks. The report is: here is the set of live delegations, grouped by human root, showing scope, expiry, and depth; here are the receipts for actions taken under each; here is the revocation identifier for each grant. That is a query, not a project.

The uncomfortable version of the same report, in an organisation without a tree, is a list of service accounts and a best effort mapping to owners, assembled by hand, accurate on the day it was made.

Honest limits

This approach has real edges, and pretending otherwise would be the wrong kind of writing.

What to do this week

  1. Count your fan-out. Pick ten people across engineering, support, and finance and ask each how many agents act in their name. Write down the number. It is almost always higher than the platform team's estimate.
  2. Grep your audit schema for the actor field. If it holds a single user identifier with no space for an agent or a grant, you have found the constraint that will shape your next two quarters.
  3. Pick your consequential action classes. Not everything needs a chain. Flag toggles, payments, permission grants, data exports, deletes, and outbound messages usually do. Ordinary reads usually do not.
  4. Add an act or delegation identifier to one service's logs. Even without full chains, recording which grant an action ran under converts one system from crowd to tree and proves the value internally.
  5. Set a default delegation lifetime and a maximum depth. Write them down as policy before you have three hundred grants. Depth one and thirty days are defensible starting points.
  6. Run the offboarding test. Take a departed employee from the last six months and try to enumerate the agents that acted for them and whether those agents still work. Time how long it takes.
  7. Try the walk on one action. The agent delegation demo shows a full chain and verification, and the developer docs cover the API. An hour is enough to know whether the shape fits your stack.

The unit of identity has changed

The account was a good abstraction for forty years because it matched reality: one person, one credential, one intent at a time. That match has broken, quietly, in a way that leaves every log technically correct and practically unable to answer the first question anyone asks after an incident.

The replacement is not more surveillance and not more fields. It is a change of shape. One human root that signs. Many delegated keys that act. Every action carrying the identifier of the grant it ran under, so that attribution is a walk that ends at a person or fails loudly. Sarah should be able to say, in the first two minutes of that Thursday review, that it was the triage agent, acting under a grant she signed in August, within its scope, and here is the receipt. That is not a better log. It is a different data model, and the sooner it goes in, the fewer of these Thursdays there are.

Frequently asked questions

What is identity fan-out? Identity fan-out is the ratio of acting agents to one accountable human. When a person runs nine agents that all hold credentials minted under their account, every system sees one principal taking many actions and cannot separate them. The user identifier stops being an answer to who acted and becomes a category containing several actors.

How should identity work when one person operates hundreds of AI agents? Use one human root key, one delegated key per agent carrying explicit scope and a depth limit, and a receipt on every action that names the delegation it ran under. Attribution then becomes a walk from the action back to the human root, which any service can verify offline, rather than an investigation across logs.

Who is liable when one of my agents acts? Generally the person who deployed it. The Uniform Electronic Transactions Act treats an electronic agent's actions as attributable to its operator, and the ESIGN Act takes a compatible position on automated transactions. That is why unattributed agent actions are the worst case: you carry full responsibility with no artifact separating what each agent did.

Isn't giving each agent its own service account enough? It is necessary and not sufficient. Per-agent identities stop credential borrowing and make rotation possible, but a thousand principals with no human anchor is a crowd. Names and user agent strings are self-asserted claims, and an agent's own logs are not independent evidence of who stood behind it.

Does this require monitoring what my agents do? No, and that is the point of the design. Attribution in a crowd requires observing everyone continuously. Attribution in a tree requires only that each action carries the grant it acted under. There is no behavioural profiling, no continuous capture, and no scoring involved in reading a chain.

What happens to an agent fleet when its operator leaves the company? In a tree, revoking the human root invalidates every grant beneath it, so offboarding has a defined blast radius you can state in advance. The important caveat is that this covers authority that flowed through delegations. An agent handed a raw API key from a cloud console sits outside the chain and needs separate discovery.

How deep should agent to agent delegation be allowed to go? Most organisations should cap it at one hop, which covers the common orchestrator and worker pattern, and require a fresh human signature beyond that. The maxChainDepth field turns an unbounded worry about agents spawning agents into a number a security team can set and an auditor can review.

Sources

  1. OAuth 2.0 Token Exchange, RFC 8693, IETF (the act claim for delegated action). https://www.rfc-editor.org/rfc/rfc8693
  2. OAuth 2.0 Rich Authorization Requests, RFC 9396, IETF. https://www.rfc-editor.org/rfc/rfc9396
  3. Uniform Electronic Transactions Act, Uniform Law Commission (attribution of electronic agents). https://www.uniformlaws.org/acts/ueta
  4. Electronic Signatures in Global and National Commerce Act (ESIGN), S.761, 106th Congress. https://www.congress.gov/bill/106th-congress/senate-bill/761
  5. EU AI Act, Article 14, human oversight obligations. https://artificialintelligenceact.eu/article/14/
  6. NIST Special Publication 800-63, Digital Identity Guidelines. https://pages.nist.gov/800-63-3/
An audit log that names a person is not attribution once that person runs nine agents. It is a category label with a timestamp.