Plugin sets and policies
For: Plugin authors looking up manifest fields.
Look up the fields for plugin sets and policies.
members
A plugin of kind: set has no parts of its own. It lists plugins, each pinned to an exact version and source, with
settings and model mappings it suggests, and evals that run them together. Installing a set installs its members
as one decision; afterwards they are ordinary plugins.
apiVersion: oz0/v1
name: starter
version: 1.0.0
kind: set
description: The connectors and the capabilities that use them, evaluated together
members:
- plugin: github
version: 1.4.2
source: hub:ai.oz0/github
settings: {GITHUB_ORG: acme}
models: {default: smart}
- plugin: pr-reviewer
version: 1.2.0
source: hub:ai.oz0/pr-reviewer
evals: [evals/]
hub:<publisher>/<name>, a Git URL at a full commit
(https://github.com/acme/notes.git@<40-hex commit>), or an image by digest (oci://<image>@sha256:<64 hex>). A
tag or a branch is refused, since it can move.<provider>/<model>.- At least one member; a set of one is a warning.
- A set's evals name its members' agents and flows by address (
pr-reviewer/oz0-pr-reviewer). - Nothing else:
tools,agents,skills,flows,hooks,harnesses,events,channels,connections,egress,requires.secrets, optional secrets and settings,provides,reads,records,startup,mail,procedure,uses,policyandruntimeare each refused with "a set has no parts of its own: move<key>into a member plugin".
policy
The plugin's suggested policy: its word on its own functions, as rules that only tighten. An install writes them as the tenant's rules, attributed to the plugin (Tool policy).
policy:
- match: oz0_github.merge_pull_request
action: ask
when: 'args.base == "main"'
reason: the plugin asks before it merges
- match: oz0_github.delete_branch
action: judge
question: Is this branch merged and no longer needed?
reason: the plugin asks before it deletes
<tool>.<function> or <tool>.* of one of its tools, or the same with its own
address (github/oz0_github.*). Any other pattern, a bare * among them, is refused: "a suggestion covers only
this plugin's functions".ask, refuse or judge. allow is refused: a suggestion only tightens.args.base == "main".judge, refused otherwise: what the judge decides.Two rules with the same match and when are refused. The keys are a tool policy rule's, so an install writes each
as an ordinary rule.
What a suggestion does at install. The install writes each rule into the tenant's tool policy after the tenant's
own rules, marked as the plugin's, with its reason (ask and judge as an Ask, refuse as a Refuse). An installer
needs no governance permission for it, since it never overrides the tenant's own rules and only tightens what a
function's type gives it. A function's default is then the first that applies:
- a rule the tenant already has that decides the function's calls;
- the plugin's suggestion;
- what the function declares (its annotations), and the plugin's
requires_approval, which asks whatever comes first unless the tenant refuses.
Where the tenant's policy is already stricter than a suggestion (it refuses destructive calls, say), the stricter word stays and the install says so. A pattern is written as one rule only where none of the tenant's defaults is stricter than it; otherwise one rule per function the plugin lists, so a function it does not list is decided by the tenant's defaults.
The check reads the measured listing, and, at an update, what nodes listed of the installed version; when the first node's listing of the version is recorded, the server checks the rules again against it, and narrows a rule that would decide a function it lists more loosely than the tenant's policy.
The installer may switch a suggested Ask to Allow, for a function or a group, with a reason and a second admin where four eyes are on; the switched rule is then the tenant's own. An update writes the new version's rules, keeps a rule the new version drops or loosens (and says which), and keeps asking about a function the new version takes off requires_approval.
Uninstalling the plugin removes its rules, and the rules written for its functions when the tenant tightened a default, except the ones the tenant switched.
Only stricter. plugin lint reads each rule against the measured listing (and a remote
tool's snapshot): a rule that would let a call run that the function's annotations or requires_approval already ask
a person about is an error, such as a judge on a destructive function, and an install refuses it too. A rule that
covers no listed function is a warning. A verified plugin asks about each write function this way (OZ-S018).
A judge is written as an Ask until judges ship, and the install screen says so; its question is kept with the
rule.