docs/developer/extensions.md
[!NOTE] Agent Zero is built with extensibility in mind. It provides a framework for creating custom extensions, agents, skills, and tools that can be used to enhance the functionality of the framework.
Here's a summary of the extensible components:
Extensions are components that hook into specific points in the agent's lifecycle. They allow you to modify or enhance the behavior of Agent Zero at predefined extension points. The framework uses a plugin-like architecture where extensions are automatically discovered and loaded.
Agent Zero provides several extension points where custom code can be injected:
The extension mechanism in Agent Zero works through the call_extensions function in agent.py, which:
/python/extensions/{extension_point}//agents/{agent_profile}/extensions/{extension_point}/To create a custom extension:
Extension base classexecute method/python/extensions/{extension_point}//agents/{agent_profile}/extensions/{extension_point}/Example extension:
# File: /agents/_example/extensions/agent_init/_10_example_extension.py
from helpers.extension import Extension
class ExampleExtension(Extension):
async def execute(self, **kwargs):
# rename the agent to SuperAgent0
self.agent.agent_name = "SuperAgent" + str(self.agent.number)
When an extension with the same filename exists in both the default location and an agent-specific location, the agent-specific version takes precedence. This allows for selective overriding of extensions while inheriting the rest of the default behavior.
For example, if both these files exist:
/python/extensions/agent_init/example.py/agents/my_agent/extensions/agent_init/example.pyThe version in /agents/my_agent/extensions/agent_init/example.py will be used, completely replacing the default version.
The system prompt is built by multiple focused extensions in extensions/python/system_prompt/, each handling one concern:
| Extension | Section | Decorator |
|---|---|---|
_10_main_prompt.py | Main system manual | @extensible |
_11_tools_prompt.py | Tool instructions + vision | @extensible |
_12_mcp_prompt.py | MCP server tools | @extensible |
_13_skills_prompt.py | Available skills | @extensible |
_13_secrets_prompt.py | Secrets and variables | @extensible |
_14_project_prompt.py | Project context | @extensible |
Each extension exposes a top-level build_prompt(agent) function decorated with @extensible, which auto-creates implicit start and end extension folders. Plugins can hook into these to modify the prompt before or after it's built.
The implicit path is composed from the function's full module path and full nested __qualname__ path:
_functions/<module path>/<qualname path>/start_functions/<module path>/<qualname path>/endFor example, a top-level function build_prompt in module extensions.python.system_prompt._10_main_prompt maps to:
extensions/python/_functions/extensions/python/system_prompt/_10_main_prompt/build_prompt/start/extensions/python/_functions/extensions/python/system_prompt/_10_main_prompt/build_prompt/end/For nested callables, every namespace-like segment is kept. For example, helpers.something -> Outer.Inner.__init__ maps to:
_functions/helpers/something/Outer/Inner/__init__/start_functions/helpers/something/Outer/Inner/__init__/endThis deep directory structure avoids collisions between functions that previously would have been flattened into the same extension point name.
Numbers _10–_14 run before plugin extensions (which start at _15+), ensuring core prompt sections are built first.
Tool prompt collection: _11_tools_prompt.py collects all agent.system.tool.*.md files from the full directory hierarchy via subagents.get_paths. Plugins that need to pass config values to their tool prompts can register per-file kwargs on agent.data["_tool_prompt_kwargs"] from an earlier-numbered extension:
# plugins/my_plugin/extensions/python/system_prompt/_09_my_config.py
class MyConfig(Extension):
async def execute(self, **kwargs):
tool_kwargs = self.agent.data.setdefault("_tool_prompt_kwargs", {})
tool_kwargs["agent.system.tool.my_tool.md"] = {"my_var": "value"}
Tools are modular components that provide specific functionality to agents. They are invoked by the agent through tool calls in the LLM response. Tools are discovered dynamically and can be extended or overridden.
Each tool is implemented as a Python class that inherits from the base Tool class. Tools are located in:
/python/tools//agents/{agent_profile}/tools/When a tool with the same name is requested, Agent Zero first checks for its existence in the agent-specific tools directory. If found, that version is used. If not found, it falls back to the default tools directory.
Example tool override:
# File: /agents/_example/tools/response.py
from helpers.tool import Tool, Response
# example of a tool redefinition
# the original response tool is in python/tools/response.py
# for the example agent this version will be used instead
class ResponseTool(Tool):
async def execute(self, **kwargs):
print("Redefined response tool executed")
return Response(message=self.args["text"] if "text" in self.args else self.args["message"], break_loop=True)
When a tool is called, it goes through the following lifecycle:
before_execution methodexecute method (main functionality)after_execution methodAPI endpoints expose Agent Zero functionality to external systems or the user interface. They are modular and can be extended or replaced.
API endpoints are located in:
/python/api/Each endpoint is a separate Python file that handles a specific API request.
Helper modules provide utility functions and shared logic used across the framework. They support the extensibility of other components by providing common functionality.
Helpers are located in:
/python/helpers/Prompts define the instructions and context provided to the LLM. They are highly extensible and can be customized for different agents.
Prompts are located in:
/prompts//agents/{agent_profile}/prompts/[!NOTE] Since v0.9.7, custom prompts should be placed under
agents/<agent_profile>/prompts/instead of a sharedpromptssubdirectory.
Agent Zero's prompt system supports several powerful features:
Prompts can include variables using the {{var}} syntax. These variables are replaced with actual values when the prompt is processed.
Example:
# Current system date and time of user
- current datetime: {{date_time}}
- rely on this info always up to date
For more advanced prompt customization, you can create Python files with the same name as your prompt files. These Python files act as dynamic variable loaders that generate variables at runtime.
When a prompt file is processed, Agent Zero automatically looks for a corresponding .py file in the same directory. If found, it uses this Python file to generate dynamic variables for the prompt.
Example:
If you have a prompt file agent.system.tools.md, you can create agent.system.tools.py alongside it:
from helpers.files import VariablesPlugin
from helpers import files
class Tools(VariablesPlugin):
def get_variables(self, file: str, backup_dirs: list[str] | None = None) -> dict[str, Any]:
# Dynamically collect all tool instruction files
folder = files.get_abs_path(os.path.dirname(file))
folders = [folder]
if backup_dirs:
folders.extend([files.get_abs_path(d) for d in backup_dirs])
prompt_files = files.get_unique_filenames_in_dirs(folders, "agent.system.tool.*.md")
tools = []
for prompt_file in prompt_files:
tool = files.read_file(prompt_file)
tools.append(tool)
return {"tools": "\n\n".join(tools)}
Then in your agent.system.tools.md prompt file, you can use:
# Available Tools
{{tools}}
This approach allows for highly dynamic prompts that can adapt based on available extensions, configurations, or runtime conditions. See existing examples in the /prompts/ directory for reference implementations.
Prompts can include content from other prompt files using the {{ include "path/to/file.md" }} syntax. This allows for modular prompt design and reuse.
Example:
# Agent Zero System Manual
{{ include "agent.system.main.role.md" }}
{{ include "agent.system.main.environment.md" }}
{{ include "agent.system.main.communication.md" }}
When overriding a prompt file, you can extend the original instead of replacing it entirely using {{include original}}. This finds the same filename in the next lower-priority directory and includes its content.
Example: Override agents/developer/prompts/agent.system.main.communication.md:
{{include original}}
- always explain your reasoning
- include code snippets in responses
This resolves to: find agent.system.main.communication.md in the next directory up the hierarchy → finds the default in prompts/ → includes it. Result:
## Communication
- be concise
- use markdown formatting
- ask clarifying questions when unsure
- always explain your reasoning
- include code snippets in responses
The override stays small and automatically inherits any future changes to the default file. Works at any level of the hierarchy — if multiple overrides each use {{include original}}, they chain together from highest to lowest priority.
The default agent.system.main.md includes agent.system.main.specifics.md — an empty file by default. Subagent profiles can override just this file to add profile-specific instructions without touching role, communication, or other sections.
Example: agents/developer/prompts/agent.system.main.specifics.md:
## Developer specifics
- always use git branches for new features
- prefer Python 3.12+ syntax
- run tests before committing
Similar to extensions and tools, prompts follow an override pattern. When the agent reads a prompt, it first checks for its existence in the agent-specific prompts directory. If found, that version is used. If not found, it falls back to the default prompts directory.
Example of a prompt override:
> !!!
> This is an example prompt file redefinition.
> The original file is located at /prompts.
> Only copy and modify files you need to change, others will stay default.
> !!!
## Your role
You are Agent Zero, a sci-fi character from the movie "Agent Zero".
This example overrides the default role definition in /prompts/agent.system.main.role.md with a custom one for a specific agent profile.
Agent Zero supports creating specialized subagents with customized behavior. The _example agent in the /agents/_example/ directory demonstrates this pattern.
/usr/agents/{agent_profile}/ for user-created profiles, or /agents/{agent_profile}/ only for built-in framework profiles./usr/agents/{agent_profile}/agent.yaml - required profile metadata/usr/agents/{agent_profile}/extensions/ - custom extensions/usr/agents/{agent_profile}/tools/ - custom tools/usr/agents/{agent_profile}/prompts/ - custom promptsModel settings are not stored in agent.yaml or profile settings.json. Main, Utility, and Embedding model configuration is handled by the _model_config plugin. For a user-created profile, profile-scoped model settings live at:
/a0/usr/agents/{agent_profile}/plugins/_model_config/config.json
Scoped _model_config/config.json files are selected as a whole, not deep-merged with global settings. If you create one, include a complete effective config with chat_model, utility_model, and embedding_model. See the Agent Profiles guide for details.
/usr/agents/my-profile/
├── agent.yaml
├── extensions/
│ └── agent_init/
│ └── _10_example_extension.py
├── prompts/
│ └── ...
├── tools/
│ ├── example_tool.py
│ └── response.py
└── plugins/
└── _model_config/
└── config.json
In this example:
_10_example_extension.py is an extension that renames the agent when initializedresponse.py overrides the default response tool with custom behaviorexample_tool.py is a new tool specific to this agentplugins/_model_config/config.json optionally gives this profile its own Main, Utility, and Embedding model settingsProjects provide isolated workspaces for individual chats, keeping prompts, memory, knowledge, files, and secrets scoped to a specific use case.
Projects are ideal for multi-client or multi-domain work because each project can have its own agent/subagents and context windows, preventing context mixing. They are especially powerful when combined with the Tasks scheduler.
/a0/usr/projects/Each project directory contains a hidden .a0proj folder with project metadata and configuration:
/a0/usr/projects/{project_name}/
└── .a0proj/
├── project.json # project metadata and settings
├── instructions/ # additional prompt/instruction files
├── knowledge/ # files to be imported into memory
├── memory/ # project-specific memory storage
├── plugins/ # project-scoped plugin configuration
├── secrets.env # sensitive variables (secrets)
└── variables.env # non-sensitive variables
When a project is activated for a chat:
.a0proj/instructions/ are automatically injected into the context window (all text files are imported).a0proj/memory/The .a0proj/knowledge/ folder contains files that are imported into the project’s memory, enabling project-focused knowledge bases.
Each project manages its own configuration values via environment files in .a0proj/:
secrets.env – sensitive variables, such as API keys or passwordsvariables.env – non-sensitive variables, such as configuration flags or identifiersThese files allow you to keep credentials and configuration tightly scoped to a single project.
Plugin-owned project configuration is stored under .a0proj/plugins/<plugin_name>/. For example, _model_config stores project model settings and project-only presets here:
/a0/usr/projects/{project_name}/.a0proj/plugins/_model_config/config.json
/a0/usr/projects/{project_name}/.a0proj/plugins/_model_config/presets.yaml
The _model_config/presets.yaml file is a plain YAML list:
- name: Research
chat:
provider: openrouter
name: anthropic/claude-sonnet-4.6
utility:
provider: openrouter
name: openai/gpt-5.4-mini
Projects are the recommended way to create specialized workflows in Agent Zero when you need to:
See Usage → Tasks & Scheduling for how to pair projects with scheduled tasks.