Agent Zero Plugin Debugger
Work through these checks in order. Stop at the first failure and fix it before continuing.
1. Plugin not appearing in the Plugins list
# Check plugin.yaml exists
ls /a0/usr/plugins/<name>/plugin.yaml
# Validate YAML
python3 -c "import yaml; yaml.safe_load(open('/a0/usr/plugins/<name>/plugin.yaml'))"
# Check directory name doesn't start with '.'
ls /a0/usr/plugins/
Common causes:
- Missing
plugin.yaml- plugin not discovered - Invalid YAML syntax - plugin skipped silently
- Directory name starts with
.- skipped by discovery
2. Plugin appears but won't enable
# Check toggle state
ls -la /a0/usr/plugins/<name>/.toggle-*
# Check for conflicting scoped toggles
ls -la project/.a0proj/plugins/<name>/.toggle-* 2>/dev/null
ls -la /a0/usr/agents/default/plugins/<name>/.toggle-* 2>/dev/null
3. API endpoint not responding
- Verify the handler file is in
api/and subclassesApiHandler - Route format:
POST /api/plugins/<plugin_name>/<handler_filename_without_.py> - Check for Python import errors on startup (check Agent Zero logs)
- Verify correct import paths:
from agent import AgentContextnotfrom helpers.context import AgentContext
# Check for syntax errors in handler
python3 -m py_compile /a0/usr/plugins/<name>/api/my_handler.py
4. Frontend component not rendering / store errors
- Check browser console for Alpine.js errors
- Verify the store file is imported in HTML
<head>via<script type="module"> - Confirm Store Gate pattern is used (missing gate = undefined error if store not yet loaded)
- Verify store name in
createStore(...)matches$store.<name>in templates
5. Extension point not injecting
- Check the HTML file is in
extensions/webui/<correct_breakpoint_name>/ - Verify the breakpoint name exists in core UI (check
webui/index.htmlor component files for<x-extension id="...">) - Common breakpoints:
sidebar-quick-actions-main-start,plugins-list-header-buttons,chat-input-bottom-actions-end - Confirm the HTML file has a root element with
x-dataand anx-move-*directive
For backend extension hooks:
- Named lifecycle hooks must live under
extensions/python/<point>/ - Implicit
@extensiblehooks must live underextensions/python/_functions/<module>/<qualname>/<start|end>/ - The retired flattened form
extensions/python/<module>_<qualname>_<start|end>/no longer loads
6. Settings not saving / loading wrong values
Config resolution order (highest priority first):
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
# Find which config file is actually being loaded
find /a0 -path "*/plugins/<name>/config.json" 2>/dev/null
7. hooks.py install hook not running
The install() hook is called automatically by the plugin installer after placement. If it didn't run:
- Check the function is named exactly
install(noton_installor similar) - Check for exceptions in the function (add try/except with print for debugging)
- Manually trigger in the framework runtime (not via
code_execution_toolpython - that uses/opt/venv, not/opt/venv-a0):
cd /a0 && /opt/venv-a0/bin/python -c "
import asyncio
from helpers.plugins import call_plugin_hook
asyncio.run(call_plugin_hook('<plugin_name>', 'install'))
print('Done')
"
If the pre_update() hook is not running before plugin updates:
- Check the function is named exactly
pre_update - Check for exceptions in the function
- Manually trigger it in the framework runtime the same way:
cd /a0 && /opt/venv-a0/bin/python -c "
import asyncio
from helpers.plugins import call_plugin_hook
asyncio.run(call_plugin_hook('<plugin_name>', 'pre_update'))
print('Done')
"
If the uninstall() hook is not running when the plugin is removed:
- Check the function is named exactly
uninstall(noton_uninstallor similar) - Check for exceptions in the function
- The
uninstall()hook is called byuninstall_plugin()inhelpers/plugins.pybefore the plugin directory is deleted. If the user removed the plugin manually (rm -rf), the hook was bypassed — always use the API or UI to uninstall. - Manually trigger it in the framework runtime the same way:
cd /a0 && /opt/venv-a0/bin/python -c "
import asyncio
from helpers.plugins import call_plugin_hook
asyncio.run(call_plugin_hook('<plugin_name>', 'uninstall'))
print('Done')
"
8. Check Agent Zero logs
# Run from the Docker host; replace the name if needed
docker logs --tail 200 a0-instance
Plugin-related errors appear in the container output as Python tracebacks mentioning the plugin path.
How Plugin Discovery Works
- Agent Zero walks
usr/plugins/thenplugins/at startup - Any directory containing
plugin.yamlis treated as a plugin usr/plugins/<name>takes priority overplugins/<name>when both exist (user overrides core)- Toggle state is evaluated:
.toggle-0disables,.toggle-1enables, no file = enabled by default - Enabled plugins have their
extensions/,api/,tools/, etc. registered into the runtime, including both named extension points and implicit_functions/...extensible hooks
Plugins are re-scanned when:
- Agent Zero restarts
- A plugin is installed/removed via the installer
- The "Refresh" action is triggered in the Plugins UI
References
- Plugin architecture:
/a0/plugins/AGENTS.md - Manage (install/update/uninstall): read
/a0/skills/a0-manage-plugin/SKILL.md