What a plugin can surface
Enabled plugin components fold into the agent namespaced as<plugin-id-last-segment>:<name>. Native components always shadow a plugin
component on a name clash.
Prompt macros expand
$ARGUMENTS, $1–$9, and @file references, then run as
a normal turn. Macros whose body is a shell (!bash) command are filtered out:
a command file is a prompt template, not an execution channel.
Hook events are mapped from Claude Code’s vocabulary onto Ziro’s. An event with
no Ziro equivalent is skipped rather than guessed at.
Discovery roots
Ziro scans, in order:Trust and consent
This is the security spine of the whole system. Third-party plugin code can run shell commands and spawn subprocesses, so those capabilities are inert until you explicitly trust the plugin. During import, Ziro extracts a grant for each capability a plugin wants. Three grant kinds are treated as dangerous:
Network access and http/sse MCP servers are not dangerous grants. They
surface without a trust decision, because they cannot execute local code.
Before anything installs, Ziro renders a consent manifest listing exactly what
the plugin wants, and waits for your decision.
1
Stage
Clone or copy the plugin at a pinned ref, import it, and build the consent
manifest. Nothing is active yet.
2
Decide
install records trust and enables everything. safe_only installs with the
dangerous parts inert. cancel discards the staged copy.3
Commit
Write the ledger entry and reload the registry.
Trust is content-hashed
Trust is keyed on plugin id plus a hash of its contents. Edit any file in a trusted plugin (including via an update) and the hash drifts, which auto-revokes trust until you confirm again. A plugin cannot be trusted once and then quietly changed underneath you. Revoking is symmetric: remove the plugin, or disable it, and its hooks and stdio MCP servers stop being surfaced.Installing
Without a flag, consent is interactive on a TTY and fails closed otherwise.
Managing
Marketplaces
A marketplace is a registry of plugin listings, parsed from a Claude Codemarketplace.json. Registered marketplaces live in a JSON file under your user
root.
local listing points at a subdirectory
of the marketplace repo, a github or git listing at a URL. Installing then
uses the normal staged-consent flow.
preapproved_marketplaces in plugin_config.yaml is discovery only. It
auto-registers a fetch origin so ziro plugin install <market>:<plugin>
resolves without a manual marketplace add. It never skips the consent
manifest and never grants trust.In chat
/plugins (alias /plugin) is one command covering the whole surface.
Install uses a staged-then-confirm flow rather than a blocking prompt, so it
works identically in the TUI and the REPL.
Changes hot-load without a restart: skills reindex, MCP servers reconcile through
sync_servers(), and prompt macros re-register.
Thread-scoped activation
Installation and trust are global. Activation is per thread. A thread entry inthreads.json carries an optional per-plugin override map.
Activation resolves per plugin:
/plugins disable foo in one thread turns foo off for that conversation
only, leaving your other threads untouched. To change the global default, use the
CLI (ziro plugin enable|disable) or install the plugin.
Enforcement is hybrid, applied at each point of use rather than by filtering one
list:
- Skill hits owned by an inactive plugin are dropped from search results.
- A hook belonging to an inactive plugin no-ops when invoked.
- A prompt macro declines at dispatch.
- Spawning an inactive plugin’s subagent is rejected. A spawned child inherits the parent’s active set.
- MCP servers are re-synced on a toggle rather than filtered at call time.
The plugin_config.yaml policy gate
Everything above describes what is currently on. plugin_config.yaml describes
what is permitted at all. It is a ceiling, not a switch: a thread override can
narrow within it, but can never widen past it.
This applies to the absence of the file, not to an unset enabled: key
inside one. A file that only narrows with allow / deny still means the author
wanted plugins, and stays permissive within its allowlist.
default (the Generalist) ships this file, and it
ships permissive: discovering and using whatever a task needs is its whole job.
researcher and researcher_docker ship no file and are therefore plugin-free
until you add one.
A malformed
plugin_config.yaml fails closed: no plugins, plus a loud
warning. The file existing means someone meant to constrain something, so a
parse error must not be read as “no constraints”.Project layers are trust-gated too
plugin_config.yaml is a dangerous project file. A project-layer copy is ignored
wholesale until you trust the folder, and folder trust is content-hashed the same
way plugin trust is. A cloned untrusted repo cannot set plugin policy on you.
The SDK is hermetic
A code-firstcreate_agent(...) surfaces zero plugins by default, so the same
script behaves identically on two machines regardless of what each has installed.
Opt in explicitly:
TypeError, so wrap it in a list. An empty list
normalizes to “no plugins”, kept distinct from True.
Next steps
Plugin CLI reference
Every
ziro plugin subcommand and flag.Skills
How plugin skills join the skill index.
MCP servers
How plugin MCP servers fold into the live manager.