What a plugin is
For: tenant administrators and plugin authors.
Plugins contain the tools, agents, skills and checks specific to your organisation. Official plugins use the same parts and interfaces available to your own plugins, so installing one does not require a change to the core.
Choose the parts your task needs, then the plugin kind that owns them. Applications that call those parts run outside Orchestrator Zero.
The parts
A plugin holds parts. Each one is a file or a folder of the plugin:
| Part | What it is | Status |
|---|---|---|
| Tools | A component exposing callable actions, backed by an MCP server or a flow. Each action is a function addressed as <tool>.<function> | Works today |
| Skills | Folders with a SKILL.md in the Agent Skills format, which teach an agent how and when to do something | Works today: Pydantic AI and OpenAI Agents SDK agents, the Claude Agent SDK harness and the ACP harnesses; remote agents load none |
| Agents | A definition of instructions, model, tools, contracts, limits and delegation, written in Markdown or YAML | Works today: Pydantic AI, the OpenAI Agents SDK, harnesses and remote agents |
| Flows | Declarative steps in YAML that chain tools, agents, conditions and approvals | Works today |
| Hooks | Functions of your plugin that the platform asks before and after tool calls and at the start and end of a job; they answer allow, deny, modify or escalate | Works today (before every tool call, harness tools included; after every call of a plugin's tool; every job) |
| Event sources | A function that turns a delivery from outside, such as a forge's webhook, into events that routines, flows and waiting jobs get | Works today |
| Connections | How the plugin's tools reach an outside system as the tenant, such as an OAuth app or a GitHub App: an admin connects it once, and each call gets a token of its own | Works today |
| Harnesses | A command that runs one session of an agent harness, such as the Claude Agent SDK or an ACP agent, per job; or a remote agent service | Works today |
| Evals | Test cases for agents and flows, run with plugin test and recorded model answers, and on a test node before a new version reaches the fleet | Works today |
The kinds
A plugin holds the parts of one thing, and says which kind of thing with kind: in its manifest:
| Kind | One per | It holds | Example |
|---|---|---|---|
| Connector plugin | outside system | the system's tools, its connection, its event sources and contract tests; at most one generic delegate agent | ai.oz0/github, ai.oz0/slack |
| Capability plugin | task or use case, owned by one team | its agents, skills, flows, hooks and evals; it reaches connectors only through the exact functions it is granted | ai.oz0/pr-reviewer, ai.oz0/support-triage |
| Policy plugin | organisation | hooks and guardrail packs that apply to every agent of the tenant | ai.oz0/guardrails |
| Plugin set | combination evaluated together | no parts of its own: other plugins, each at an exact version, installed as one decision (sets) | ai.oz0/essentials |
Harness and remote-agent plugins are connectors: they connect to an outside agent runtime, such as the Claude Agent SDK, an ACP agent, Claude Managed Agents or another organisation's A2A agent, as other connectors connect to an outside system. A capability's agent runs on one by naming it (runtime: harness:claude-agent-sdk).
Applications: a support portal, a chat app, an internal tool
| runtime API, AG-UI, MCP or a chat channel
v
+------------------------------- one tenant -------------------------------+
| capability: support-triage policy: guardrails |
| agents, skills, flows, hooks, evals hooks for every agent |
| | |
| | uses: exact functions, granted by an admin |
| v |
| connector: jira connector: github connector: a |
| tools, connection, tools, connection, harness or a |
| event sources event sources remote agent |
+--------------------------------------------------------------------------+
|
v
The outside systems and agent runtimes
How to structure plugins says when to split a plugin, how to name it, and the house rules each kind keeps.
Applications stay outside
An application is never a plugin. The portal, chat app or internal tool your users open lives outside Orchestrator Zero, with its own users, releases and hosting, and calls agents over the runtime API, AG-UI, MCP or a chat channel. One application uses many capabilities, and one capability serves many applications.
One plugin, one unit
The plugin is the one unit of ownership, version, trust, grant, evals, rollout and distribution: one owner, one version, one signature and digest, one listing in an index, one rollout. Its parts are never packaged, listed, versioned or granted one by one. Another plugin reaches them through its own uses:, naming exact functions, agents and skills, under a grant an admin makes for the whole plugin. A part that needs a version of its own gets a plugin of its own.
How agents combine
A plugin is never a bundle of agents, and there is no crew or team of agents to define. Agents combine at run time:
- inside a plugin: delegation, hand-offs, flow steps, colleagues, best-of-N and outcome reviewers;
- across plugins: an agent of another plugin, named under
uses:and granted at install (below); - across owners and clusters: A2A and MCP.
Whatever an agent is granted, the platform also checks what it holds together: an agent with private data, outside input and a function that sends without asking is flagged where you install and configure it (What an agent combines).
What a plugin is made of
A plugin is a Git repository with an oz0-plugin.yaml at its root, or the same files as a bundle or a folder of the tenant's workspace. The manifest names the plugin, its kind and its version, and lists its parts; the manifest reference has every key. Claude Code plugins and Agent Plugins install as they are.
What happens when you install one
The edge locks it to a commit
It resolves the ref you give (or the latest vX.Y.Z tag) to a commit and stores that commit with the plugin. A bundle is locked to its SHA-256 digest instead, and a workspace folder to a revision.
The edge checks and packs it
The same checks as plugin lint, then a packed artifact, stored by its sha256: digest. Unpinned packages are pinned to the version the registry has now.
A version with evals passes them first
One node of the tenant runs the new version's evals against your models; a version that does worse is stopped, and the fleet keeps the one it has. See Quality gates.
Every node of the tenant gets it from the edge
Nodes never reach Git. Each node that matches the plugin's selector downloads the artifact from the edge, checks its digest and unpacks it.
The node builds its environment and starts it
uv builds a Python environment from the plugin's lock file, packages get their own environments, and the MCP servers start. The node reports the functions it found.
A failed update keeps the previous version running and reports the failure. That version keeps its own code, its approved tool snapshot and its pinned origins, and takes the tenant's state as the edge sends it now: a rotated secret, a removed credential binding, a changed setting or a hidden skill reaches it at once, and a harness-extras opt-in or a reviewed mark that was withdrawn is withdrawn from it too (one cannot be added to it).
What it may reach of other plugins is what it declared under uses:, by the grant as it is now: while the update installs and after it failed, never the wider reach the new version declares. When the new assignment no longer carries a secret the old version runs with, or a setting it requires, the old version stops as well (... stopped: the version that runs ... needs the tenant secret ...): nothing runs on what the tenant may have withdrawn. Fix the update, or assign the old version again. Plugins of different tenants never mix.
Plugins that use other plugins
A plugin's agents and flows reach their own plugin's tools and agents and the built-ins oz.*. To call another plugin's tools, delegate to its agents, run them as reviewers or best-of candidates, or ask them as colleagues, a plugin declares what it uses under uses:, and a tenant admin grants that when installing it:
pr-reviewer 0.1.0 uses other plugins:
pr-reviewer wants oz0_github.get_pull_request, oz0_github.merge_pull_request and delegation to oz0-github, from plugin github
install plugin github from hub:ai.oz0/[email protected] (a trusted hub index lists it)
Grant it, with the plugins it installs first, with: --accept-uses sha256:3f1c...
The grant is one decision: a used plugin the tenant does not have is installed first, from the source you name, the plugin's own uses: source, or a trusted index that lists it in the version range. A later version that asks for more needs a new grant; one that asks for less does not, and reaches less. A used plugin that uses others in turn is part of the same decision, and an admin can narrow or revoke a grant later without removing the plugin (oz0 plugin revoke).
The node refuses everything else first, with a reason the model reads, and the edge refuses it again, so a modified node cannot go around it either. See Install: plugins that use other plugins.
Trust
Plugins run as processes with the node's permissions, so install only plugins you trust and run nodes as a user without root. Harness sessions, and the jobs a webhook starts, run in a sandbox on nodes that have one.