plugins: update docs and skills for extensible refactor

Alessandro committed Mar 23, 2026 at 03:42 UTC c48b26797e6b87f2f78d695aa30f34f38d8ad22b
15 files changed +82 -16
docs/agents/AGENTS.plugins.md
+12 -2
@@ -12,7 +12,7 @@ Agent Zero uses a convention-over-configuration plugin model where runtime capab
12
13 1. Backend discovery (python/helpers/plugins.py): Resolves roots (usr/plugins/ first, then plugins/) and builds the effective set of plugins.
14 2. Path resolution (python/helpers/subagents.py): Injects plugin paths into the agent's search space for prompts, tools, and configurations.
15 -3. Python extensions (python/helpers/extension.py): Executes lifecycle hooks from extensions/python/<point>/.
15 +3. Python extensions (python/helpers/extension.py): Executes named lifecycle hooks from `extensions/python/<point>/` and implicit `@extensible` hooks from `extensions/python/_functions/<module>/<qualname>/<start|end>/`.
16 4. WebUI extensions (webui/js/extensions.js): Injects HTML/JS contributions into core UI breakpoints (x-extension).
17
18 ---
@@ -37,13 +37,23 @@ usr/plugins/<plugin_name>/
37 ├── prompts/ # Prompt templates
38 ├── agents/ # Agent profiles (agents/<profile>/agent.yaml)
39 ├── extensions/
40 -│ ├── python/<point>/ # Backend lifecycle hooks
40 +│ ├── python/<point>/ # Named backend lifecycle hooks
41 +│ ├── python/_functions/<module>/<qualname>/<start|end>/ # Implicit @extensible hooks
42 │ └── webui/<point>/ # UI HTML/JS contributions
43 └── webui/
44 ├── config.html # Optional: Plugin settings UI
45 └── ... # Full plugin pages/components
46 ```
47
48 +### Python extension layouts
49 +
50 +Use one of these backend extension layouts, depending on what you are extending:
51 +
52 +- `extensions/python/<extension_point>/` for named lifecycle hooks such as `system_prompt`, `monologue_start`, or `tool_execute_before`
53 +- `extensions/python/_functions/<module>/<qualname>/<start|end>/` for implicit `@extensible` call sites
54 +
55 +The `_functions` layout preserves every module segment and every nested `__qualname__` segment. Do not use the retired flattened form `extensions/python/<module>_<qualname>_<start|end>/`; those folder names no longer match the runtime lookup logic.
56 +
57 ### Python import rule for user plugins
58
59 For plugin-local Python code in `usr/plugins/<plugin_name>/`, import through the
docs/developer/plugins.md
+11 -1
@@ -6,7 +6,7 @@ This page documents the current Agent Zero plugin system, including manifest for
6
7 Plugins extend Agent Zero through convention-based folders. A plugin can provide:
8
9 -- Backend: API handlers, tools, helpers, Python lifecycle extensions
9 +- Backend: API handlers, tools, helpers, Python lifecycle extensions, and implicit `@extensible` hooks
10 - Frontend: WebUI components and extension-point injections
11 - Agent profiles: plugin-scoped subagent definitions
12 - Settings: scoped plugin configuration loaded through the plugin settings store
@@ -64,12 +64,22 @@ usr/plugins/<plugin_name>/
64 │ └── <profile>/agent.yaml # optional plugin-distributed agent profile
65 ├── extensions/
66 │ ├── python/<extension_point>/
67 +│ ├── python/_functions/<module>/<qualname>/<start|end>/
68 │ └── webui/<extension_point>/
69 └── webui/
70 ├── config.html # optional settings UI
71 └── ...
72 ```
73
74 +## Python Extension Layouts
75 +
76 +Use one of these backend layouts:
77 +
78 +- `extensions/python/<extension_point>/` for named lifecycle hooks such as `agent_init`, `system_prompt`, or `tool_execute_before`
79 +- `extensions/python/_functions/<module>/<qualname>/<start|end>/` for implicit `@extensible` hook targets
80 +
81 +The `_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.
82 +
83 ## Python Imports for User Plugins
84
85 For plugin-local Python imports inside `usr/plugins/<plugin_name>/`, use the
plugins/README.md
+7 -1
@@ -21,12 +21,18 @@ For detailed guides on how to create, extend, or configure plugins, refer to:
21
22 Plugins are automatically discovered based on the presence of a `plugin.yaml` file. Each plugin can contribute:
23
24 -- **Backend**: API handlers, tools, helpers, and lifecycle extensions
24 +- **Backend**: API handlers, tools, helpers, named lifecycle extensions, and implicit `@extensible` hooks under `extensions/python/_functions/...`
25 - **Frontend**: HTML/JS UI contributions via core extension breakpoints
26 - **Settings**: Isolated configuration scoped per-project and per-agent profile
27 - **Activation**: Global and scoped ON/OFF rules via `.toggle-1` and `.toggle-0` files, including advanced per-scope switching in the WebUI
28 - **Agent profiles**: Plugin-distributed subagent definitions under `agents/<profile>/agent.yaml`
29
30 +Backend extension layouts:
31 +- `extensions/python/<point>/` for named lifecycle hooks
32 +- `extensions/python/_functions/<module>/<qualname>/<start|end>/` for implicit `@extensible` hooks
33 +
34 +Do not use the retired flattened `extensions/python/<module>_<qualname>_<start|end>/` form.
35 +
36 ## Plugin Manifest
37
38 Every plugin requires a `plugin.yaml` at its root:
plugins/_error_retry/README.md
+2 -2
@@ -22,8 +22,8 @@ It does **not** retry exceptions that are already treated as controlled agent fl
22
23 ## Key Files
24
25 -- `extensions/python/agent_Agent_monologue_start/_10_reset_critical_exception_counter.py`
26 -- `extensions/python/agent_Agent_handle_exception_end/_80_retry_critical_exception.py`
25 +- `extensions/python/_functions/agent/Agent/monologue/start/_10_reset_critical_exception_counter.py`
26 +- `extensions/python/_functions/agent/Agent/handle_exception/end/_80_retry_critical_exception.py`
27
28 ## Configuration Scope
29
plugins/_plugin_installer/README.md
+3 -3
@@ -1,6 +1,6 @@
1 # Plugin Installer
2
3 -Install and update Agent Zero plugins from ZIP uploads, Git repositories, or a community index.
3 +Install and update Agent Zero plugins from ZIP uploads, Git repositories, or the community Plugin Index surfaced through the Plugin Hub.
4
5 ## What It Does
6
@@ -20,8 +20,8 @@ This plugin provides the built-in installation workflow for third-party plugins.
20 - Rejects plugin name conflicts.
21 - **Install hooks and refresh**
22 - Runs the plugin install hook when present and calls `after_plugin_change(...)` so the app refreshes plugin state.
23 -- **Community browsing UI**
24 - - The web UI store handles browsing index entries, showing readme content, prompting about third-party plugin risk, and launching install/update actions.
23 +- **Plugin Hub UI**
24 + - The web UI store handles browsing Plugin Index entries, showing README content, prompting about third-party plugin risk, and launching install/update actions.
25
26 ## Key Files
27
plugins/_plugin_validator/webui/plugin-validator-checks.json
+1 -1
@@ -16,7 +16,7 @@
16 },
17 "structure": {
18 "label": "Structure Validation",
19 - "detail": "Inspect the directory layout and role of each top-level file or folder. Check that api/ contains Python ApiHandler files, tools/ contains Tool subclasses, extensions/ follows python/<point>/ or webui/<point>/ conventions, webui/config.html is backed by settings_sections, hooks.py exposes install when expected, execute.py follows the main()/sys.exit(main()) pattern, and the root contains only expected plugin files. Also verify a file named LICENSE exists at the plugin root (same directory as plugin.yaml). Agent Zero does not require LICENSE for loading a local plugin, but the Plugin Index requires LICENSE at the repository root for community listings; a missing LICENSE must not be rated pass for this phase.",
19 + "detail": "Inspect the directory layout and role of each top-level file or folder. Check that api/ contains Python ApiHandler files, tools/ contains Tool subclasses, extensions/ follows python/<point>/, python/_functions/<module>/<qualname>/<start|end>/, or webui/<point>/ conventions, and flag the retired flattened python/<module>_<qualname>_<start|end>/ form if present. Also verify webui/config.html is backed by settings_sections, hooks.py exposes install when expected, execute.py follows the main()/sys.exit(main()) pattern, and the root contains only expected plugin files. Also verify a file named LICENSE exists at the plugin root (same directory as plugin.yaml). Agent Zero does not require LICENSE for loading a local plugin, but the Plugin Index requires LICENSE at the repository root for community listings; a missing LICENSE must not be rated pass for this phase.",
20 "criteria": {
21 "pass": "Directory layout cleanly matches Agent Zero plugin conventions and LICENSE exists at the plugin root",
22 "warning": "Layout mostly works but LICENSE is missing at the plugin root (required for Plugin Index submission; optional for local-only use), or there are unusual files or minor convention drift",
plugins/_plugin_validator/webui/plugin-validator-guidance.md
+1
@@ -1,6 +1,7 @@
1 - Store gate pattern: wrap store-backed UI in `<template x-if="$store.myStore">` and mount cleanup on the inner element.
2 - Store definition: use `createStore` from `/js/AlpineStore.js`; do not register Alpine stores inline in HTML or via `alpine:init`.
3 - Notifications: use `toastFrontendError`, `toastFrontendSuccess`, or backend notification helpers; do not render inline error boxes.
4 +- Python extensions: use `extensions/python/<point>/` for named lifecycle hooks and `extensions/python/_functions/<module>/<qualname>/<start|end>/` for implicit `@extensible` hooks. The flattened `extensions/python/<module>_<qualname>_<start|end>/` layout is stale and should be flagged.
5 - API handlers: subclass `ApiHandler` and return a dict or `Response`.
6 - Tools: subclass `Tool` from `helpers.tool`.
7 - AgentContext imports: use `from agent import AgentContext, AgentContextType`, never `helpers.context`.
plugins/_plugin_validator/webui/plugin-validator-prompt.md
+1 -1
@@ -20,7 +20,7 @@ Follow these steps in order:
20
21 1. Resolve the plugin root and list every file below it. Do not sample; inspect the full plugin.
22 2. Read `plugin.yaml` and record the plugin's name, title, description, and version.
23 -3. Map the directory structure and identify every top-level file or folder that affects behavior. Record whether a `LICENSE` file exists at the plugin root (required for Plugin Index submission per project policy; optional for local-only plugins).
23 +3. Map the directory structure and identify every top-level file or folder that affects behavior. Record whether backend extensions use named points under `extensions/python/<point>/`, implicit `@extensible` hooks under `extensions/python/_functions/<module>/<qualname>/<start|end>/`, or any stale flattened `extensions/python/<module>_<qualname>_<start|end>/` folders. Record whether a `LICENSE` file exists at the plugin root (required for Plugin Index submission per project policy; optional for local-only plugins).
24 4. Run ONLY the selected validation phases listed below.
25 5. If a temporary clone or extracted directory was used, perform the cleanup exactly as instructed.
26
skills/a0-contribute-plugin/SKILL.md
+3 -1
@@ -60,10 +60,12 @@ your-plugin-repo/ <- GitHub repository root
60 ├── prompts/ <- prompt templates
61 ├── agents/ <- agent profiles
62 ├── conf/ <- config files (e.g. model_providers.yaml)
63 -├── extensions/ <- lifecycle and UI extensions
63 +├── extensions/ <- lifecycle, UI, and implicit @extensible hooks
64 └── webui/ <- frontend pages, stores, components
65 ```
66
67 +Inside `extensions/`, use `python/<point>/` for named lifecycle hooks, `python/_functions/<module>/<qualname>/<start|end>/` for implicit `@extensible` hooks, and `webui/<point>/` for UI breakpoints. Do not publish the retired flattened `python/<module>_<qualname>_<start|end>/` form.
68 +
69 ### Runtime `plugin.yaml` requirements
70
71 The remote `plugin.yaml` must include a **`name` field** - this is validated by CI and must exactly match the index folder name:
skills/a0-create-plugin/SKILL.md
+4 -1
@@ -196,7 +196,8 @@ save_plugin_config(
196 conf/
197 model_providers.yaml # Optional: add or override model providers
198 extensions/
199 - python/agent_init/ # Python lifecycle extensions
199 + python/<extension_point>/ # Named Python lifecycle extensions
200 + python/_functions/<module>/<qualname>/<start|end>/ # Implicit @extensible hooks
201 webui/<point>/ # HTML/JS hook extensions
202 webui/
203 config.html # Optional: plugin settings UI
@@ -204,6 +205,8 @@ save_plugin_config(
205 my-store.js # Alpine stores
206 ```
207
208 +Do not create the retired flattened extensible path form `extensions/python/<module>_<qualname>_<start|end>/`. The current runtime only resolves the deep `_functions/<module>/<qualname>/<start|end>` layout for implicit `@extensible` hooks.
209 +
210 ### Import rule for plugin-local Python code
211
212 Use the fully qualified `usr.plugins.<plugin_name>...` path for plugin-local
skills/a0-debug-plugin/SKILL.md
+6 -1
@@ -85,6 +85,11 @@ python3 -m py_compile /a0/usr/plugins/<name>/api/my_handler.py
85 - Common breakpoints: `sidebar-quick-actions-main-start`, `plugins-list-header-buttons`, `chat-input-bottom-actions-end`
86 - Confirm the HTML file has a root element with `x-data` and an `x-move-*` directive
87
88 +For backend extension hooks:
89 +- Named lifecycle hooks must live under `extensions/python/<point>/`
90 +- Implicit `@extensible` hooks must live under `extensions/python/_functions/<module>/<qualname>/<start|end>/`
91 +- The retired flattened form `extensions/python/<module>_<qualname>_<start|end>/` no longer loads
92 +
93 ---
94
95 ## 6. Settings not saving / loading wrong values
@@ -138,7 +143,7 @@ Plugin-related errors appear as Python tracebacks mentioning the plugin path.
143 2. Any directory containing `plugin.yaml` is treated as a plugin
144 3. `usr/plugins/<name>` takes priority over `plugins/<name>` when both exist (user overrides core)
145 4. Toggle state is evaluated: `.toggle-0` disables, `.toggle-1` enables, no file = enabled by default
141 -5. Enabled plugins have their `extensions/`, `api/`, `tools/`, etc. registered into the runtime
146 +5. Enabled plugins have their `extensions/`, `api/`, `tools/`, etc. registered into the runtime, including both named extension points and implicit `_functions/...` extensible hooks
147
148 Plugins are re-scanned when:
149 - Agent Zero restarts
skills/a0-manage-plugin/SKILL.md
+1
@@ -127,6 +127,7 @@ If the scan times out or errors (500), inform the user and ask whether to procee
127
128 The Plugin Hub marks a plugin as **Installed** by cross-referencing Plugin Hub keys against `usr/plugins/` directory names at request time. To appear installed:
129 - The plugin directory must exist at `usr/plugins/<name>/` with a valid `plugin.yaml`
130 +- If the plugin ships extensions, the framework will register both named extension points under `extensions/python/<point>/` and implicit `@extensible` hooks under `extensions/python/_functions/<module>/<qualname>/<start|end>/` after the plugin cache is refreshed
131 - The framework plugin cache must be cleared (the API handles this automatically)
132 - Re-fetching the Plugin Hub index will then show it as installed
133
skills/a0-plugin-router/SKILL.md
+3 -1
@@ -72,7 +72,7 @@ always_enabled: false # forces ON, disables toggle (framework use only)
72 |---|---|
73 | `api/` | API handlers (`ApiHandler` subclasses) |
74 | `tools/` | Agent tools (`Tool` subclasses) |
75 -| `extensions/python/<point>/` | Backend lifecycle hooks |
75 +| `extensions/python/<point>/` and `extensions/python/_functions/<module>/<qualname>/<start_or_end>/` | Backend lifecycle hooks and implicit `@extensible` hooks |
76 | `extensions/webui/<point>/` | HTML/JS injected into UI breakpoints |
77 | `webui/config.html` | Plugin settings UI |
78 | `webui/*.html`, `webui/*.js` | Full plugin pages and Alpine stores |
@@ -84,6 +84,8 @@ always_enabled: false # forces ON, disables toggle (framework use only)
84 | `conf/model_providers.yaml` | Add/override model providers |
85 | `LICENSE` | Optional under `usr/plugins/`; required at the root of a plugin GitHub repo before submitting to the Plugin Index |
86
87 +For `@extensible` targets, the only valid implicit hook layout is `extensions/python/_functions/<module>/<qualname>/<start|end>/`. The older flattened `extensions/python/<module>_<qualname>_<start|end>/` folders are obsolete.
88 +
89 ### Activation
90
91 - Global toggle: `.toggle-1` (ON) / `.toggle-0` (OFF) files in the plugin dir
skills/a0-review-plugin/SKILL.md
+1 -1
@@ -46,7 +46,7 @@ Inspect the plugin directory layout:
46 - [ ] Directory name matches `^[a-z0-9_]+$`
47 - [ ] If `api/` exists: contains Python files only; each should subclass `ApiHandler`
48 - [ ] If `tools/` exists: contains Python files only; each should subclass `Tool`
49 -- [ ] If `extensions/` exists: check subdirs follow `python/<point>/` or `webui/<point>/` pattern
49 +- [ ] If `extensions/` exists: check subdirs follow `python/<point>/`, `python/_functions/<module>/<qualname>/<start|end>/`, or `webui/<point>/` patterns; flag the retired flattened `python/<module>_<qualname>_<start|end>/` form
50 - [ ] If `helpers/` exists: shared Python logic (standard directory)
51 - [ ] If `prompts/` exists: prompt templates (standard directory)
52 - [ ] If `agents/` exists: agent profiles with `<profile>/agent.yaml` (standard directory)
skills/a0-review-plugin/checklists.md
+26
@@ -124,6 +124,32 @@ class MyTool(Tool):
124
125 ---
126
127 +## Python Extension Layout
128 +
129 +Use one of these backend extension layouts:
130 +
131 +```text
132 +extensions/python/<extension_point>/
133 +```
134 +
135 +For named lifecycle hooks such as `agent_init`, `system_prompt`, `monologue_start`, or `tool_execute_before`.
136 +
137 +```text
138 +extensions/python/_functions/<module>/<qualname>/<start|end>/
139 +```
140 +
141 +For implicit `@extensible` hook targets. The path must keep the full module path and every nested `__qualname__` segment.
142 +
143 +**FAIL pattern**:
144 +
145 +```text
146 +extensions/python/<module>_<qualname>_<start|end>/
147 +```
148 +
149 +That flattened form is stale and no longer matches the current extensible runtime lookup.
150 +
151 +---
152 +
153 ## AgentContext Access
154
155 ```python