Agent Zero allows plugin developers to surface UI elements using the banners extension point. This allows your plugin to present information, prompts, or actionable "discovery cards" directly on the Welcome Screen without needing to inject arbitrary HTML into the frontend.
Banners are collected on the backend and sent to the frontend UI as an array of dictionaries. By appending to the banners array inside a Python extension, you can easily surface your plugin to the user.
To inject a banner, you create a Python extension script hooking into banners.
Create a python file in your plugin's extensions folder:
plugins/<your_plugin>/extensions/python/banners/10_my_plugin_banner.py
(Note: the 10_ prefix is for ordering; extensions run in alphabetical order).
The UI distinguishes banners primarily by the type property.
These are standard top-level alerts displayed on the welcome screen.
banners.append({
"id": "my-plugin-warning",
"type": "warning",
"priority": 90,
"title": "My Plugin Issue",
"html": "<strong>Action required:</strong> Please configure your settings.",
"dismissible": True,
})These are rich, interactive cards displayed in the Discovery section. They are designed to prompt the user to try new plugins or features.
hero: A wide, prominent card. Usually reserved for core system features (e.g., the Plugin Hub).feature: A smaller card in a grid layout. This is the recommended type for plugin contributors to showcase their plugin.
Here is an example of injecting a feature card for a custom plugin:
from helpers.extension import Extension
from helpers import plugins
class MyPluginDiscoveryCard(Extension):
"""Injects a discovery card for My Custom Plugin."""
async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs):
# 1. Condition Check
# Only show the discovery card if the user hasn't configured the plugin yet.
config = plugins.get_plugin_config("my_custom_plugin") or {}
# If the API key is already set, we don't need to advertise the setup!
if config.get("api_key"):
return
# 2. Add the Card
banners.append({
"id": "discovery-my-custom-plugin",
"type": "feature", # 'feature' or 'hero'
"title": "Connect My Service", # Card title
"description": "Unlock amazing capabilities by linking your account.",
# Visuals (use either thumbnail OR icon)
"thumbnail": "/plugins/my_custom_plugin/assets/thumb.png", # Path to image
"icon": "bolt", # Or a Material Symbol icon name
# Call To Action (CTA)
"cta_text": "Setup Now",
"cta_action": "open-plugin-config:my_custom_plugin", # Opens your plugin's config modal
# Behavior
"dismissible": True, # Let the user hide it
"priority": 40, # Higher numbers appear first
})When a user clicks the button on a discovery card, the cta_action string determines what happens. The frontend currently supports the following actions:
open-plugin-config:<plugin_folder_name>: Automatically opens the settings modal for the specified plugin. (e.g.,open-plugin-config:_telegram_integration).open-plugin-hub: Opens the main Plugin Hub UI.open-url:<url>: Opens a web link in a new browser tab. (e.g.,open-url:https://example.com/docs).
- Check Configuration First: Always check your plugin's configuration before injecting a card. If the user has already set up your plugin, they shouldn't keep seeing a discovery card asking them to set it up.
- Unique IDs: Ensure your banner
idis highly unique (e.g., prefix it with your plugin name) to avoid collisions with other plugins. - Use
featuretype: Community plugins should stick to thefeaturetype rather thanheroto ensure a clean grid layout for users.