What an agent combines
For: plugin authors.
Review an agent's access as a combination. Private data, outside input and functions that send information can expose data when the same agent has all three:
- private data: something the tenant would not publish;
- outside input: text from people or systems outside the tenant, which can carry instructions to the model;
- sending out: a function that writes, posts or sends.
An agent that holds all three can be steered by text from outside into sending what it read somewhere it should not go, in one job. The platform works out what each agent combines and flags an agent that holds all three while at least one of its sending functions runs without anyone asked.
Flags show combinations worth a second look. No flag does not mean an agent is safe.
The three ingredients
The check reads the agent's functions: its own plugin's, and other plugins' that its plugin is granted under uses:.
Once the plugin is installed, another plugin's function that its grant does not reach (never granted, or revoked
since) shows as Refuse, since its agents' calls of it are refused. It also reads what starts the agent, from any
installed plugin: a flow of another plugin that runs the agent counts as much as one of its own.
| Ingredient | What counts |
|---|---|
| Private data | A function whose tool reaches a system through one of its plugin's connections. A function whose tool declares a label source (labels.source), when the tenant's default level ranks above its lowest one, as the built-in levels do. |
| Outside input | A function whose results come from outside the tenant: one that does not say openWorldHint: false, or a remote server's, as taint reads them. A tool that says its results hold outside text (labels.untrusted, such as a mailbox). oz.wait_for_event. A start by a routine's webhook or event trigger, a flow's webhook or event trigger that runs the agent in a step, or a chat channel binding that names it. |
| Sending out | A function of type Write, Sends out, Destructive or Unknown. |
A function the tenant vouches for (oz0 tenant labels <tenant> --trusted) is not outside input, as it does not taint a job. A
schedule is not outside input: it starts the agent with the routine's own task.
The tenant's routines, its channel bindings and other plugins' flows are named only to someone who may read the
tenant (tenant.read). Anyone else, such as a role that may read plugins' settings and nothing more, sees the start
counted as outside input under the name "not visible to you".
A tool result can carry a confidentiality level of its own, and every result the platform has no level for gets the tenant's default level. That default level does not count as private data: every agent would have it. Only a tool that declares where its data comes from does.
Why Unknown counts as sending out
A function that does not say what it does (no annotations, or not read-only and silent on destructiveHint) may do
any of the things the other types say. The check is only as good as the functions' annotations, so it takes the worst
case. An Unknown function asks a person by default, so it closes the flag until someone allows it.
When an agent is flagged
The agent is flagged when it holds all three and a sending function's default is Allow. The default is the one the
install screen shows: the tenant's rule that covers the function, then the plugin's suggested policy, then what the
function declares; a function under the plugin's requires_approval always asks.
Any default but Allow closes it: Ask, Refuse, and a plugin's suggested Judge, which is currently written as Ask and so closes it.
This flag is about what an agent combines; the house rule OZ-S018, which checks that a verified plugin's writes ask, counts only Ask and Refuse, not a suggested Judge.
The flag names:
- the functions or starts behind each ingredient, and why each one counts;
- the sending functions that run without asking: switching each to Ask closes the flag.
The check looks at each function's own default. A job that read outside input also asks before tools that can send data out, through the taint default, while that default is on. The flag still shows: it covers a write that is not outbound, a tenant that turned the default off, and private data that taint does not track.
Where it shows
- The install screen: a line per flagged agent in the May do block, with one action that switches the
closing functions to Ask on the screen before you install. The flag clears as soon as none is left on Allow.
oz0 plugin install,oz0 plugin updateandoz0 plugin previewprint the same, with the command that closes each function. See What the install shows first. - The Configure tab: above the Tools tab's groups, with the same action on the tab's switches, which you then save as usual. See Configure an installed plugin.
- The agent's page: beside its capability card on the Permissions tab, with a way to its plugin's Configure tab. An agent that is not flagged says what it holds of the three.
oz0 catalog: a table of the flagged agents and the functions that send without asking.plugin lint: house rule OZ-S020 runs the same check on the plugin alone.
A flag never refuses
A flag never refuses an install, an update or a job. Whether an agent may hold all three is the admin's decision: a support agent may well need to read a ticket from a customer, look up the customer's record and post a reply. The flag makes the combination visible, so the decision is made on purpose.
Duty pairs beside it
The same places also show the pairs of the tenant's own duty rules an agent holds: two duties, each a set of functions, that the tenant does not want one agent to hold together, such as paying and approving payments. They are worked out from the same functions as the three ingredients. A pair the tenant marks refuse is the tenant's rule, not this check's: it refuses the install, the grant or the policy change that would create it. The combination itself still only flags.
How to close it
Pick one:
- Switch the sending functions to Ask with the flag's action, on the Configure tab, or with
oz0 plugin policy <plugin> --set <function>=ask --reason "...". For another plugin's function, the switch is for your plugin's agents only:oz0 plugin policy <owner> --set <function>=ask --caller <plugin>. - Take an ingredient away: give the outside input to another agent that cannot send, or leave a function the
agent does not need out of its
tools:. - As a plugin's author, ask about the sending functions in the plugin's suggested policy. A verified capability must: OZ-S020 fails lint at the verified level otherwise.
What it does not see
- What a function does with a given call: a Write that only touches the tenant's own records counts as sending out.
- Delegation: an agent that hands work to another agent is checked on its own functions, and the other agent on its own.
- A harness session's own tools (a shell, a web fetch) beyond the functions it is granted.
- A level a tool result declares in its own
_meta, which is known only once a call returns.