How would you govern which agents may mutate shared state, and what audit trail would you require?
answer
- reads recover, writes may not
- name the action, not the file path
- validation, authority, audit, event
- intersection of rights, never union
- govern by reversibility and reach
basics
~20 sExpose mutation as typed operations rather than raw writes: each one validates its arguments, checks the calling agent's authority, records an audit entry naming agent, inputs and result, and emits an event. Reads can stay wide; writes stay narrow and enumerable.
solid answer
~50 sThe governing asymmetry is that reads are recoverable and writes are not, so the two surfaces get different policies. Reads over the shared store can be broad. Writes should go through a small, enumerated set of typed operations — `submit_rfi(project_id, question)` rather than "write any bytes to any path under `/site/`". A typed operation gives you four things a raw file write cannot: **validation** of the payload shape before anything changes, **authorization** against what that agent is allowed to do, an **audit record** naming the agent identity, run id, inputs and resulting artifact, and an **event** so other agents learn of the change through the normal state channel. It also bounds the blast radius: an injected instruction reaching a subagent can only reach the operations that agent holds. The cost is real — every governed surface is schema work and slows iteration — so spend it where a bad write is expensive to undo, and leave exploratory scratch space ungoverned.
code
python · 17 linesaudit: list[dict] = []
ALLOWED = {"survey-agent": {"submit_rfi"}, "summary-agent": set()}
def submit_rfi(project_id: str, question: str, agent_id: str, run_id: str) -> str:
if "submit_rfi" not in ALLOWED.get(agent_id, set()):
raise PermissionError(f"{agent_id} may not submit RFIs")
if not question.strip():
raise ValueError("question must not be empty")
rfi_id = f"rfi-{len(audit) + 1:04d}"
audit.append({
"agent": agent_id, "run": run_id, "op": "submit_rfi",
"args": {"project_id": project_id}, "result": rfi_id,
})
return rfi_id
print(submit_rfi("site-7", "Dimension conflict on A-201?", "survey-agent", "r-92"))go deeper
Know that agents should not be handed unrestricted write access to shared files, and that a named operation with defined arguments is safer than letting an agent write anything anywhere.
Explain what a typed mutation buys over a raw write — schema validation, an authorization check, an audit record and an event — and why reads and writes deserve different policies.
Show how you scope per-agent write authority in practice, what fields an audit record must carry to support an incident review, and why injection containment is a bounded-blast-radius argument rather than prevention.
Own the allocation: which surfaces earn governance based on reversibility and reach, how authority narrows rather than propagates along the delegation graph, and the delivery cost of over-governing every mutation.
## Why writes get a different policy from reads A wrong read wastes tokens and can usually be corrected in the next step. A wrong write mutates state other agents will act on, and may not be reversible at all — a submitted change order, a closed ticket, a pushed commit. That asymmetry, not general caution, is the reason governance concentrates on the write path. Broad reads with narrow, enumerated writes is a workable default; the inverse never is. ## Raw writes versus typed operations Giving agents a filesystem and telling them to keep it tidy is fast to build and genuinely right for scratch work. It fails as the authoritative surface for three reasons: no validation (an agent can write prose where the next agent expects fields), no authorization (any agent can touch any path), and no record beyond the file's final contents. A typed operation replaces "write bytes" with a named action carrying a schema. `submit_rfi(project_id, question)` is a different object from an open-and-write call: it can reject a blank question, refuse an agent not assigned to that project, allocate an id, write the artifact in the canonical shape, append an audit row, and emit an event — as one unit from the system's point of view. The agent never learns the storage layout, which is also why the layout can change without re-teaching six agents. ## What the audit trail must contain An audit record that only says "a file changed" is not an audit trail. The fields that make one usable after an incident: - **Who** — the agent's own identity, not just "the system". Per-agent identity is what makes attribution possible when four agents can touch the same store. - **On whose behalf** — the human or job that initiated the run. An agent acting for a user should never exceed what that user could do directly. - **Which run** — a correlation id tying the mutation to the trace it came from. - **What** — the operation name and its validated arguments. - **Result** — the artifact path or id produced, and success or rejection, including why a rejected call was rejected. - **When** — a timestamp consistent with the event log's ordering. Write these as append-only records in the same stream as the rest of shared state, so "what happened" and "who was allowed to do it" are not two disconnected stories. ## Authority is an intersection, not a grant The rule worth stating plainly: an agent's effective permission is the intersection of what the initiating principal is entitled to and what that agent is allowed to do at all. A capable model acting for a user with read-only access must remain read-only. This matters more in multi-agent systems than single-agent ones because authority propagates along the delegation graph — an orchestrator that passes its full credentials to every subagent has given each of them the union rather than the intersection, and the least-trusted subagent now defines the system's blast radius. The practical consequence is per-agent scoping: the survey agent can submit RFIs and read drawings; only the schedule agent can write the schedule; the summarizing agent can read everything and write nothing. That scoping does at least as much work as any instruction in a role prompt, because it holds when the prompt is subverted. ## Prompt injection is a write-path problem Agents read untrusted content — documents, web pages, tool output — and an instruction hidden in that content is a plausible way for an agent to be told to mutate something. Governance is what makes the outcome bounded: the injected instruction can only invoke operations the compromised agent already holds, validated against schemas, recorded with attribution. This is a containment argument, not a prevention one, and it is worth saying so rather than claiming typed tools stop injection. ## What it costs, and where not to spend it Every governed surface is design work: a schema, an authorization rule, a migration path when the shape changes. Over-govern and agents spend their turns failing validation on operations that should have been a file write, and the team stops adding capabilities because each one is a project. So spend the budget by reversibility and reach: mutations that are expensive or impossible to undo, or that many agents depend on, get typed operations and audit; scratch directories and drafts stay open. Some irreversible operations should not be reachable by an agent at all without a human in the path — a separate control, but on the same spectrum. ## In an interview This is a judgement question and there is no single correct architecture. What a strong answer shows is the reasoning: reads and writes are different risk classes, typed operations buy validation plus authorization plus audit plus eventing together, authority intersects rather than unions along the delegation chain, and governance is a cost you allocate rather than apply uniformly.
- An orchestrator holds broad credentials and spawns four subagents. What is wrong with passing those credentials down?Each subagent then holds the union of everything the orchestrator can do, so the least-trusted or most-injectable subagent defines the system's blast radius. Scope each agent to the operations its role actually needs, and keep the effective permission the intersection of the initiating principal's rights and that agent's allowed capabilities. Delegation should narrow authority, never preserve it.
- Does routing writes through typed tools prevent prompt injection?No — it contains it. An instruction hidden in a document an agent reads can still cause a call, but only to operations that agent already holds, with validated arguments and an attributed audit record. That turns an open-ended compromise into a bounded, detectable one. Claiming prevention is the wrong answer; the mechanism limits reach and makes the incident reconstructable.
- How do you decide which parts of shared state to leave ungoverned?Weigh reversibility and reach. Scratch directories, drafts and per-run working files are cheap to undo and read by nobody else, so raw writes are fine and cheaper to build. Anything many agents depend on, or that is expensive or impossible to reverse, earns a typed operation with authorization and audit. Uniform governance is a common overcorrection that stalls delivery.
- What makes an audit record actually useful during an incident review?Attribution and correlation. It needs the acting agent's own identity, the human or job on whose behalf it ran, a run id linking it to the trace, the operation and its validated arguments, and the outcome — including the reason for rejected calls. Records that say only that a file changed cannot answer who did it or why it was permitted.
saying these in an interview costs you the question
- Gives every agent the orchestrator's full credentials
- Claims typed write tools prevent prompt injection outright
- Applies the same governance to reads and writes
- Treats a file's last-modified timestamp as an audit trail
- Says role prompts alone will keep agents from writing the wrong thing