docs/developer/plugins.md
This page documents the current Agent Zero plugin system, including manifest format, discovery rules, scoped configuration, activation behavior, and how to share a plugin with the community.
Plugins extend Agent Zero through convention-based folders. A plugin can provide:
@extensible hooksPrimary roots (priority order):
usr/plugins/ (user/custom plugins)plugins/ (core/built-in plugins)On name collisions, user plugins take precedence.
plugin.yaml)Every plugin must contain plugin.yaml. This is the runtime manifest — it drives Agent Zero behavior. It is distinct from the index manifest used when publishing to the Plugin Index (see Publishing to the Plugin Index below).
name: my_plugin # required for community plugins (^[a-z0-9_]+$, must match dir name)
title: My Plugin
description: What this plugin does.
version: 1.0.0
settings_sections:
- agent
per_project_config: false
per_agent_config: false
always_enabled: false
Field reference:
name: plugin identifier; required by CI for index submission; must be ^[a-z0-9_]+$ and match the index folder name exactlytitle: UI display namedescription: short plugin summaryversion: plugin version stringsettings_sections: where plugin settings appear (agent, external, mcp, developer, backup)per_project_config: enables project-scoped settings/togglesper_agent_config: enables agent-profile-scoped settings/togglesalways_enabled: forces ON state and disables toggle controlsusr/plugins/<plugin_name>/
├── plugin.yaml
├── execute.py # optional user-triggered plugin script
├── hooks.py # optional runtime hook functions callable by the framework
├── default_config.yaml # optional defaults
├── README.md # optional locally; strongly recommended for community plugins
├── LICENSE # optional locally (shown in Plugin List UI when present); required at repo root for Plugin Index submission
├── api/ # ApiHandler implementations
├── tools/ # Tool implementations
├── helpers/ # shared Python logic
├── prompts/
├── agents/
│ └── <profile>/agent.yaml # optional plugin-distributed agent profile
├── extensions/
│ ├── python/<extension_point>/
│ ├── python/_functions/<module>/<qualname>/<start|end>/
│ └── webui/<extension_point>/
└── webui/
├── config.html # optional settings UI
└── ...
Use one of these backend layouts:
extensions/python/<extension_point>/ for named lifecycle hooks such as agent_init, system_prompt, or tool_execute_beforeextensions/python/_functions/<module>/<qualname>/<start|end>/ for implicit @extensible hook targetsThe _functions layout keeps the full module path and nested __qualname__ path, which avoids collisions between similarly named functions. Do not create the retired flattened form extensions/python/<module>_<qualname>_<start|end>/; it is stale and will not be resolved by the current extensible system.
For plugin-local Python imports inside usr/plugins/<plugin_name>/, use the
fully qualified usr.plugins.<plugin_name>... path.
Good:
from usr.plugins.my_plugin.helpers.runtime import do_work
import usr.plugins.my_plugin.helpers.state as state
Avoid:
sys.path.insert(0, ...)
from helpers.runtime import do_work
from plugins.my_plugin.helpers.runtime import do_work
This is the preferred pattern because it keeps plugin imports explicit,
requires no directory renaming like name_helpers, requires no symlink into
plugins/, and leaves no global import hack behind when the plugin is deleted.
execute.py)Plugins can include an optional execute.py at the plugin root for user-triggered operations such as setup, post-install actions, maintenance, repair steps, or other manual tasks that should run only when explicitly requested.
import subprocess
import sys
def main():
print("Installing dependencies...")
result = subprocess.run(
[sys.executable, "-m", "pip", "install", "requests==2.31.0"],
text=True,
)
if result.returncode != 0:
print("ERROR: Installation failed")
return result.returncode
print("Refreshing plugin resources...")
print("Done.")
return 0
if __name__ == "__main__":
sys.exit(main())
Return 0 on success, non-zero on failure. Print progress for user feedback. Use sys.executable for pip commands. Prefer making the script safe to run more than once; if reruns are not safe, detect the current state and print a clear explanation.
First rule of plugin side effects: do not modify the system permanently unless the user explicitly asked for it and the plugin also provides a cleanup path. Deleting a plugin should not leave behind symlinks, orphaned services, framework patches, or unmanaged files outside plugin-owned locations.
hooks.py)Plugins can also include an optional hooks.py at the plugin root. Agent Zero loads this module on demand and calls exported functions by name through helpers.plugins.call_plugin_hook(...).
hooks.py executes inside the Agent Zero framework runtime and Python environment.Use execute.py when the user should explicitly decide when the operation runs. Use hooks.py or lifecycle extensions when the work belongs to framework-managed behavior.
Current built-in usage:
install() from hooks.py after copying a plugin into placepre_update() from hooks.py immediately before pulling new plugin code into placehooks.py runs sys.executable -m pip install ..., it installs into the same Python environment that is currently running Agent Zero.If you need to install into a different environment, do it explicitly from a subprocess. In practice, that means targeting the correct interpreter or activating the correct environment inside the subprocess before running pip or another package manager.
Examples of the right approach:
pipIn Docker deployments, hooks.py normally affects the framework runtime at /opt/venv-a0, while the agent execution runtime is /opt/venv.
Plugin settings are resolved by scope. Higher priority overrides lower priority:
project/.a0proj/agents/<profile>/plugins/<name>/config.jsonproject/.a0proj/plugins/<name>/config.jsonusr/agents/<profile>/plugins/<name>/config.jsonusr/plugins/<name>/config.jsonplugins/<name>/default_config.yaml (fallback defaults)Notes:
Activation is independent per scope and file-based:
.toggle-1 means ON.toggle-0 means OFFWebUI activation states:
ON: explicit ON or implicit defaultOFF: explicit OFF rule at selected scopeAdvanced: at least one project/agent-profile override existsalways_enabled: true bypasses OFF state and keeps the plugin ON in both backend and UI.
Current plugin UX surfaces activation in two places:
Advanced option when scoped overrides are enabledScope synchronization behavior:
Core plugin management endpoint: POST /api/plugins
Supported actions:
get_configsave_configlist_configsdelete_configtoggle_pluginget_doc (fetches README.md or LICENSE for display in the UI)The Plugin Index is a community-maintained repository at https://github.com/agent0ai/a0-plugins. Plugins listed there are discoverable by all Agent Zero users.
There are two completely different manifest files — they must not be confused:
Runtime manifest (plugin.yaml, inside your plugin's own repo — drives Agent Zero behavior):
name: my_plugin # REQUIRED for index submission; must match index folder name
title: My Plugin
description: What this plugin does.
version: 1.0.0
settings_sections:
- agent
per_project_config: false
per_agent_config: false
always_enabled: false
Index manifest (index.yaml, submitted to a0-plugins under plugins/<your_plugin_name>/ — drives discoverability only):
title: My Plugin
description: What this plugin does.
github: https://github.com/yourname/your-plugin-repo
tags:
- tools
- example
screenshots: # optional, up to 5 full image URLs
- https://raw.githubusercontent.com/yourname/your-plugin-repo/main/docs/screen.png
The index manifest file is named index.yaml (not plugin.yaml). Required fields: title, description, github. Optional: tags (up to 5), screenshots (up to 5 URLs). The github URL must point to a public GitHub repository that contains a runtime plugin.yaml at the repository root, and that plugin.yaml must include a name field matching the index folder name exactly. That repository must also include a LICENSE file at its root (Plugin Index / community contribution requirement).
Plugin repos should expose the plugin contents at the repo root, so they can be cloned directly into usr/plugins/<name>/:
your-plugin-repo/ ← GitHub repository root
├── plugin.yaml ← runtime manifest (must include name field)
├── default_config.yaml
├── README.md
├── LICENSE ← required for Plugin Index listings
├── api/
├── tools/
├── extensions/
└── webui/
plugin.yaml (including the name field) at the repo root.https://github.com/agent0ai/a0-plugins.plugins/<your_plugin_name>/ and add index.yaml (the index manifest, not plugin.yaml). Optionally add a square thumbnail image (≤ 20 KB, named thumbnail.png|jpg|webp).Submission rules:
^[a-z0-9_]+$ (lowercase, numbers, underscores — no hyphens)name field in your remote plugin.yamlLICENSE at its root (community contribution requirement)_ are reserved for internal usetitle: max 50 charactersdescription: max 500 charactersindex.yaml total: max 2000 characterstags: optional, up to 5, see https://github.com/agent0ai/a0-plugins/blob/main/TAGS.mdscreenshots: optional, up to 5 full image URLs (png/jpg/webp, each ≤ 2 MB)Agent Zero now exposes the community Plugin Hub through the always-enabled Plugin Installer plugin. Users can browse Plugin Index entries directly from the Plugins UI without leaving the application.
Users can open the Plugin Hub from the Plugins dialog in two ways:
The Plugin Hub supports search, filtering, sorting, and a plugin detail view with README content and the install action.
Plugin UIs must use the A0 notification system for user feedback. Do not show errors or success via inline elements (e.g. a red box bound to store.error).
toastFrontendError(message, title), toastFrontendSuccess(message, title), etc. from /components/notifications/notification-store.js, or $store.notificationStore.frontendError(...) in templates.AgentNotification.error(...), AgentNotification.success(...) from helpers.notification.This keeps toasts and notification history consistent. See Notifications for the full API.
docs/agents/AGENTS.plugins.md for full architecture detailsskills/a0-plugin-router/SKILL.md for the primary agent-facing entry point across plugin create/review/manage/contribute/debug tasksskills/a0-create-plugin/SKILL.md for direct plugin authoring workflow when the task is specifically to build or extend a pluginplugins/README.md for core plugin directory overviewx-extension anchor.confirm_dialog_after_render can extend the shared confirm dialog using the supplied DOM nodes and caller extensionContext.