Parts

Addresses

Every part has one address, <plugin>/<part>. Where you write one, how the server checks it against the part's owner, and why a part is never renamed in place.

For: plugin authors.

Name another plugin's part with its full address: the plugin name, a slash and the part name. Use this form in manifests, commands, console fields and tool policy rules.

A bare name refers to a part of the same plugin.

The forms

PartAddressSuch as
A function<plugin>/<tool>.<function>, with * where a pattern is allowedgithub/oz0_github.get_pull_request, github/oz0_github.*, github/*
A whole tool<plugin>/<tool> (kill switches and the inventory)github/oz0_github
An agent<plugin>/<agent>pr-reviewer/pr-reviewer
A flow<plugin>/<flow>merge-when-green/merge-when-green
A skill<plugin>/<skill>, or <plugin>/* for every oneweb/research

Names hold no /, so an address has exactly one. A function's name inside its tool keeps its own form: github/oz0_github.get_pull_request is plugin github, tool oz0_github, function get_pull_request. An address can read twice, as in github/oz0_github.get_file, because authors start their tool IDs with the plugin's name to keep them apart in a tenant; that is expected.

A bare name means the same plugin

Inside a plugin, oz0_github.get_pull_request means this plugin's function, and review this plugin's agent. A reference to another plugin's part names its plugin:

agents/release-notes.yaml
name: acme-release-notes
description: Writes release notes from the merged pull requests.
model:
  use: default
instructions: prompts/release-notes.md
tools:
  - github/oz0_github.list_pull_requests    # github's function, granted under uses:
  - oz.delegate
delegation:
  allow: [github/oz0-github]                # github's agent
oz0-plugin.yaml
uses:
  github:
    version: ">=1.1, <2"
    tools: [oz0_github.list_pull_requests]   # under the plugin's own key, its parts are bare
    agents: [oz0-github]

A bare name of another plugin's part still works, since names are unique in a tenant, and plugin lint warns with the address to write (plugin lint --fix writes it); for a verified plugin it is an error. The plugin in an address is the plugin itself or one its manifest lists under uses:. The manifest reference lists every field that takes one.

The owner check

Tool IDs and agent and flow names are unique per tenant: an install that would add a second one is refused. So the server always knows which plugin owns a part, and wherever a part is named after the plugin is installed, it checks the address against that owner before it acts:

  • Starting a job: oz0 run github/oz0-github "...", oz0 chat pr-reviewer/pr-reviewer, the runtime API's StartJob and the catalog's lookup by name.
  • Calling a tool by hand: oz0 tool call github/oz0_github.get_pull_request --args '{...}'.
  • Kill switches and the inventory: oz0 kill agent pr-reviewer/pr-reviewer, oz0 kill tool github/oz0_github, oz0 inventory set agent pr-reviewer/pr-reviewer --purpose ....
  • Tool policy rules: oz0 policy ask 'github/oz0_github.*' decides only github's functions; see a rule by address.
  • Lists: oz0 job search --agent pr-reviewer/pr-reviewer.

An address that names another plugin is refused, with the owner the server found:

github/triage is not an agent of github: triage is support-triage's

The check comes after the caller's permission: someone who may not start jobs is refused for that first, and a key scoped to some agents learns nothing about an agent outside its scopes. Once the address is checked, the server acts on the bare name exactly as it always has: the job, its history, its child jobs, the calls a node makes and what is stored all carry the bare name, so nodes of an older version and jobs that were running before see no change.

The console, oz0 job get, oz0 job trace, oz0 catalog, oz0 approval list and oz0 plugin inspect show parts by address, from the owner the server knows. The console's pages stay where they were (/t/<tenant>/agents/<name>).

Two plugins that define one name

An install refuses a second agent or flow of a name, and a second tool ID. A tenant that has two anyway, from before installs refused it or written to the store some other way, runs neither: the edge and every node withhold the name, and a job of it fails at its start with the reason ("plugins a and b each define an agent or flow named triage, so neither runs"). Remove one of the plugins, or update one to a version whose part has another name.

The names a model sees

A model sees a function as <tool>__<function>, never with its plugin. Model providers limit a function's name: 64 characters for OpenAI's formats, 128 for Anthropic's Messages API. A node leaves out a function whose name a model would see as longer than 64 characters, saying which, and plugin lint warns about one in the plugin's measured listing (tools.listing.json). Keep tool IDs and function names short enough for both.

Renaming a part

Do not rename a part in place. An agent's name is in its model calls' activity names in every running job's history, in its child jobs' IDs, and in the tenant's routes and policies: a job that started under the old name needs it until the job ends. Ship the new name beside the old one in a new version, move what starts it (routines, other plugins' uses:, your own scripts) to the new name, and remove the old part in a later version, once its jobs have ended (oz0 job search --agent <plugin>/<old name> --status running shows them).

The same holds for a tool's ID and a function's name: other plugins' uses: grants and the tenant's tool policy name them, and an update that drops a function another installed plugin names is refused unless forced with a reason.

Copyright © 2026