Give Each Worker a Minimal Identity
Different prompts don't create isolation. Separating trust requires separate credentials, scopes, tool allowlists, and server-side authorization. A worker for documentation search must not have a deploy credential; a reviewer must not edit the artifact it checks; a planner may propose work items but not widen its own scopes. These rules are checked by the host application and external services.
Role · Read · Write · Forbidden
- Planner - Task and metadata; Plan namespace; Production effects
- Research worker - Allowed sources; Finding namespace; Other workers' credentials
- Executor - Approved plan; Declared resources; Widening its own scope
- Reviewer - Artifacts and evidence; Review report; Editing the result it checks
In the companion project this is expressed by different write prefixes right in the contracts.
{
id: "planner",
accepts: ["plan"],
allowedWritePrefixes: ["plan/"],
allowedHandoffs: ["tester", "security", "docs"]
},
{
id: "tester",
accepts: ["test"],
allowedWritePrefixes: ["evidence/tests/"],
allowedHandoffs: ["reviewer"]
},
{
id: "security",
accepts: ["security"],
allowedWritePrefixes: ["evidence/security/"],
allowedHandoffs: ["reviewer"]
},
{
id: "docs",
accepts: ["docs"],
allowedWritePrefixes: ["release-notes/"],
allowedHandoffs: ["reviewer"]
},
{
id: "reviewer",
accepts: ["review"],
allowedWritePrefixes: ["report/"],
allowedHandoffs: ["supervisor"]
}
];
const USAGE: Readonly<Record<Exclude<AgentId, "supervisor">, Usage>> = {
planner: { calls: 1, tokens: 900, costUnits: 2, simulatedLatencyMs: 850 },
tester: { calls: 1, tokens: 1_200, costUnits: 3, simulatedLatencyMs: 1_600 },
security: { calls: 1, tokens: 1_300, costUnits: 3, simulatedLatencyMs: 1_850 },
docs: { calls: 1, tokens: 700, costUnits: 1, simulatedLatencyMs: 900 },
reviewer: { calls: 1, tokens: 1_100, costUnits: 2, simulatedLatencyMs: 1_000 }
};
function artifactExists(context: AgentContext, key: string): boolean {
return context.inputArtifacts.some((artifact) => artifact.key === key);The OpenAI Agents SDK supports human-in-the-loop approval, where a run can stop at a tool call and continue from RunState, and guardrails can check input and output. The mechanisms are useful, but authorization must still be performed on the tool or service side.
Approval doesn't cure an excessive right. If a credential lets you delete the whole database, confirming one tool call doesn't limit the provider-side blast radius. Use scoped identity, resource policy, and reversible operations where possible.
Rights are granted minimally. But the topology itself widens the attack surface - so trust must not be raised when crossing between agents.
What actually isolates workers from each other?