Refactor a0-development into grounded references

Split the monolithic a0-development skill into a lean entry point plus focused reference files for runtime, DOX, tools, extensions, API/WebUI, profiles, prompts, skills, projects, and plugin workflow.

Update the skill DOX ownership for the new references directory and clarify the root framework-vs-agent Python runtimes plus port-discovery guidance.

Verified with git diff --check, targeted skill/tool tests under PYTHONPATH, and live localhost:32769 skill loading/read_file checks before committing.
This commit is contained in:
Alessandro 2026-06-23 17:51:43 +02:00
parent d707fe7bcf
commit 4b49386f96
11 changed files with 752 additions and 820 deletions

View file

@ -3,8 +3,8 @@
[Generated using reconnaissance on 2026-02-22]
## Quick Reference
Tech Stack: Python 3.12+ | Flask | Alpine.js | LiteLLM | WebSocket (Socket.io)
Dev Server: python run_ui.py (runs on http://localhost:50001 by default)
Tech Stack: Framework Python 3.12+ | Agent execution Python 3.13 in Docker | Flask | Alpine.js | LiteLLM | WebSocket (Socket.io)
Dev Server: python run_ui.py (discover host/port from startup output or runtime configuration; do not assume a default port)
Run Tests: pytest (standard) or pytest tests/test_name.py (file-scoped)
Documentation: README.md | docs/
Frontend & Plugin DOX: [WebUI](webui/AGENTS.md) | [Components](webui/components/AGENTS.md) | [Frontend JS](webui/js/AGENTS.md) | [Plugins](plugins/AGENTS.md)
@ -43,22 +43,24 @@ Do not combine these commands; run them individually:
pip install -r requirements.txt
```
- Start WebUI: python run_ui.py
- Discover the WebUI URL from startup output, launcher/Docker port mappings, or explicit `--host`/`--port`/`WEB_UI_PORT` configuration; do not hardcode a default port.
---
## Docker Environment
When running in Docker, Agent Zero uses two distinct Python runtimes to isolate the framework from the code being executed:
When running in Docker, Agent Zero uses two distinct Python runtimes to isolate the framework itself from code executed on behalf of the agent:
### 1. Framework Runtime (/opt/venv-a0)
- Version: Python 3.12.4
- Purpose: Runs the Agent Zero backend, API, and core logic.
- Packages: Contains all dependencies from requirements.txt.
- Purpose: Runs the Agent Zero framework itself: WebUI backend, API, core loop, scheduler, framework imports, and plugin hooks/tools that execute inside the framework process.
- Packages: Contains framework dependencies from requirements.txt.
- Verification: Use this runtime for framework/backend import checks, WebUI startup checks, and plugin hook behavior unless the code explicitly switches environments.
### 2. Execution Runtime (/opt/venv)
### 2. Agent Execution Runtime (/opt/venv)
- Version: Python 3.13
- Purpose: Default environment for the interactive terminal and the agent's code execution tool.
- Behavior: This is the environment active when you docker exec into the container. Packages installed by the agent via pip install during a task are stored here.
- Purpose: Default Python environment for the agent's terminal/code-execution tasks and user code run by the agent.
- Behavior: Packages installed by the agent during a task belong here so task dependencies do not pollute or prove the framework runtime. Do not use this runtime as evidence that framework imports, WebUI startup, or plugin hooks work.
---

View file

@ -3,27 +3,35 @@
## Purpose
- Own the broad Agent Zero development guide used by agents extending the framework.
- Keep architecture, tools, extensions, API, agents, prompts, projects, and skills guidance in sync with the repository.
- Keep architecture, tools, extensions, API, agents, prompts, projects, plugins, runtime, and skills guidance in sync with the repository.
## Ownership
- `SKILL.md` owns the development overview, path conventions, and implementation references.
- `SKILL.md` owns the concise development entry point, routing workflow, path conventions, and reference map.
- `references/` owns detailed source-grounded development references loaded on demand.
## Local Contracts
- Keep paths and examples current with source files and DOX contracts.
- Route plugin-specific tasks to the plugin router or specialist plugin skills.
- Do not duplicate long contracts that belong in narrower AGENTS.md files when a reference is enough.
- Reference files must identify current source or DOX anchors and avoid hardcoded default WebUI ports.
## Work Guidance
- Update this skill after durable framework workflow, extension, tool, API, prompt, or profile changes.
- Keep examples operational and compatible with the current helper classes.
- Keep `SKILL.md` lean; move detailed schemas, examples, and topic-specific guidance to `references/`.
## Verification
- Manually read `SKILL.md` for stale architecture references and broken related-skill links.
- Manually read `SKILL.md` and changed reference files for stale architecture references, broken relative paths, and specialist-skill duplication.
- Load the skill after reference-map changes and confirm `skills_tool` exposes the expected reference file tree.
## Child DOX Index
No child DOX files.
Direct child DOX files:
| Child | Scope |
| --- | --- |
| [references/AGENTS.md](references/AGENTS.md) | Source-grounded development references loaded by this skill. |

View file

@ -1,9 +1,9 @@
---
name: a0-development
description: Development guide for extending and building features for the Agent Zero AI framework. Covers architecture, tools, extensions, API endpoints, agent profiles, projects, prompts, and skills — with correct paths, imports, and patterns matching the current codebase.
version: 1.0.0
description: Development guide for extending Agent Zero from current source and DOX. Use for framework architecture, tools, extensions, API/WebUI handlers, agent profiles, prompts, skills, projects, runtime boundaries, and contribution workflow. Load the focused reference files before giving implementation guidance.
version: 1.1.0
author: Agent Zero Team
tags: ["development", "framework", "agent-zero", "extending", "tools", "extensions", "skills", "api", "agents", "prompts"]
tags: ["development", "framework", "agent-zero", "extending", "tools", "extensions", "skills", "api", "agents", "prompts", "dox"]
trigger_patterns:
- "extend agent zero"
- "agent zero development"
@ -21,826 +21,60 @@ trigger_patterns:
- "extension hook points"
- "prompt system"
- "agent profile"
- "dox"
---
# Agent Zero Development Guide
# Agent Zero Development
This skill provides comprehensive, accurate guidance for extending and building features for Agent Zero. Use it when you need to:
Use this skill as the entry point for Agent Zero framework development. It is intentionally lean: load only the reference files that match the task, then verify against the current repository before changing code.
- Understand the **architecture** and project layout
- Create new **Tools** for agent capabilities
- Add **Extensions** to hook into the framework lifecycle
- Build **API Endpoints** for the Web UI
- Create **Agent Profiles** (subordinates) with custom prompts
- Understand and extend the **Prompt System**
- Create **Skills** (see the dedicated `build-skill` skill for the full wizard)
- Work with **Projects** and workspace configuration
## Reality Rules
> **Path convention:** Throughout this guide, `/a0/` refers to the framework root — this is `/a0/` inside Docker, or your local repository root in development. All paths are relative to this root.
1. Source and nearest DOX beat memory, examples, and this skill if they disagree.
2. Before editing, read the applicable `AGENTS.md` chain from the repo root to every file you expect to touch.
3. New capabilities should usually be plugins. For plugin-specific work, load `a0-plugin-router` and follow the routed specialist skill.
4. Do not assume ports. Discover WebUI host/port from startup output, launcher or Docker mapping, or explicit `--host`, `--port`, `WEB_UI_HOST`, and `WEB_UI_PORT` configuration.
5. In Docker, framework checks belong to `/opt/venv-a0` and agent/user code execution belongs to `/opt/venv`. Do not use one runtime as proof for the other.
6. Treat `/a0/` as the runtime framework root inside Docker. In local development it means the repository root. If a live container matters, prove that `/a0` matches the checkout before trusting source-only conclusions.
7. Do not document or change ignored `usr/` or `tmp/` runtime state unless the user explicitly asks.
> [!IMPORTANT]
> **Plugins are the primary way to extend Agent Zero.** Most new tools, extensions, and prompts should be packaged as plugins. For all plugin tasks (create, review, manage, debug, contribute), load the `a0-plugin-router` skill which routes to the appropriate specialist. This guide covers the underlying framework patterns that plugins build upon.
## Reference Map
Related skills: `a0-plugin-router` (plugin tasks) | `build-skill` (skill creation wizard) | `a0-create-plugin` | `a0-review-plugin` | `a0-manage-plugin` | `a0-contribute-plugin` | `a0-debug-plugin`
---
## Architecture Overview
### Project Layout
```
/a0/ # Framework root
├── agent.py # Core Agent + AgentContext + AgentConfig classes
├── initialize.py # Agent initialization logic
├── models.py # Model definitions
├── run_ui.py # Web UI entry point
├── tools/ # Core tools (search, response, browser, etc.)
├── extensions/
│ ├── python/ # Python lifecycle extensions
│ │ ├── <hook_point>/ # e.g., agent_init/, system_prompt/, etc.
│ │ │ └── _NN_name.py # Numbered extension files
│ │ └── _functions/ # Implicit @extensible decorator extensions
│ └── webui/ # JavaScript WebUI extensions
│ └── <hook_point>/ # e.g., json_api_call_before/
│ └── name.js
├── api/ # Flask API endpoint handlers
├── helpers/ # Framework utilities and base classes
│ ├── tool.py # Tool + Response base classes
│ ├── extension.py # Extension base class + @extensible decorator
│ ├── api.py # ApiHandler base class
│ ├── files.py # File operations + prompt reading
│ ├── plugins.py # Plugin system manager
│ ├── print_style.py # Console output formatting
│ └── ... # Many more utility modules
├── prompts/ # Core prompt fragments (system, tools, framework)
├── agents/ # Agent profiles (subordinate specializations)
│ ├── default/ # Base profile (inherited by others)
│ ├── agent0/ # Main user-facing agent
│ ├── developer/ # Developer subordinate
│ ├── hacker/ # Security subordinate
│ ├── researcher/ # Research subordinate
│ └── _example/ # Example profile with tool + extension samples
├── plugins/ # Core plugins (tools, extensions, prompts)
│ ├── _code_execution/ # Terminal/Python/Node.js execution
│ ├── _memory/ # Persistent memory system
│ ├── _text_editor/ # File read/write/patch
│ ├── _model_config/ # LLM model selection
│ ├── _infection_check/ # Prompt injection safety
│ └── ... # More core plugins
├── skills/ # Core skills (SKILL.md bundles)
├── knowledge/ # Knowledge base files
├── webui/ # Web UI frontend
├── docs/ # Documentation
└── usr/ # User-space (survives updates)
├── agents/ # User-created agent profiles
├── plugins/ # User-installed plugins
├── skills/ # User-created skills
├── knowledge/ # User knowledge base files
├── extensions/ # Standalone user extensions (created on demand; prefer plugins instead)
├── projects/ # Project workspaces (created on demand when user adds projects via UI)
└── workdir/ # Default working directory
```
### Key Architecture Patterns
1. **Plugin-first design** — Most capabilities (tools, extensions, prompts) are delivered via plugins in `/a0/plugins/` (core) or `/a0/usr/plugins/` (user).
2. **Extensions execute in numeric order** — Files named `_10_*.py`, `_20_*.py`, etc. run sequentially within each hook point.
3. **Tools inherit from `Tool`** — All tools implement the `execute()` method returning a `Response`.
4. **Shared `AgentContext`** — Enables state persistence across agents in a conversation.
5. **Async/await throughout** — All tool execution, extensions, and API handlers are async.
6. **Prompt fragments compose** — System prompts are assembled from named fragments with includes and variable substitution.
7. **Profile inheritance** — Agent profiles inherit from `default/` and override specific prompt fragments.
8. **User-space separation** — Everything under `/a0/usr/` survives framework updates.
### Agent Loop
The core execution cycle works as follows:
1. **User message** arrives (via UI or API)
2. **System prompt assembly** — prompt fragments are composed with includes and variable substitution
3. **LLM call** — the assembled prompt + conversation history is sent to the model
4. **Response parsing** — the framework parses the LLM response looking for JSON tool calls
5. **Tool execution** — if tool calls are found, each tool's `execute()` method is called and the result is appended to history
6. **Loop continues** — steps 3-5 repeat until the agent produces a `response` tool call (which ends the loop) or a loop limit is reached
Extensions fire at each stage (e.g., `monologue_start`, `before_main_llm_call`, `tool_execute_before`, etc.), allowing plugins to observe and modify behavior at every point.
---
## Creating Tools
Tools are how agents interact with the world. Each tool inherits from the `Tool` base class.
### Import Path
```python
from helpers.tool import Tool, Response
```
### Tool Base Class
```python
# /a0/helpers/tool.py
@dataclass
class Response:
message: str # Text response shown to agent
break_loop: bool # True = stop agent message loop
additional: dict[str, Any] | None = None # Extra metadata for history
class Tool:
def __init__(self, agent: Agent, name: str, method: str | None,
args: dict[str,str], message: str,
loop_data: LoopData | None, **kwargs) -> None:
self.agent = agent
self.name = name
self.method = method # For tools with sub-methods (e.g., "skills_tool:load")
self.args = args
self.loop_data = loop_data
self.message = message
async def execute(self, **kwargs) -> Response:
pass # Override this
# Lifecycle hooks (called automatically):
async def before_execution(self, **kwargs): ...
async def after_execution(self, response: Response, **kwargs): ...
```
### Where Tools Live
| Location | Purpose |
|---|---|
| `/a0/tools/` | Core framework tools (search, response, call_subordinate, etc.) |
| `/a0/plugins/<plugin>/tools/` | Plugin-provided tools (code_execution, memory, text_editor) |
| `/a0/agents/<profile>/tools/` | Profile-specific tool overrides |
| `/a0/usr/plugins/<plugin>/tools/` | User plugin tools |
### Example: Creating a Tool
Based on the actual `_example` profile in `/a0/agents/_example/tools/example_tool.py`:
```python
# my_tool.py
from helpers.tool import Tool, Response
class MyTool(Tool):
async def execute(self, **kwargs):
# Get arguments — kwargs contains the tool_args from the agent's JSON
input_data = kwargs.get("input", "")
# Do something
result = f"Processed: {input_data}"
# Return response
return Response(
message=result, # Shown to the agent
break_loop=False, # Don't stop the agent loop
)
```
> [!IMPORTANT]
> Every tool needs a corresponding **prompt fragment** so the agent knows how to use it. Create a file named `agent.system.tool.<tool_name>.md` in the appropriate `prompts/` directory. See the [Prompt System](#prompt-system) section.
### Tool Best Practices
- Always handle errors gracefully — return error messages in `Response`, don't crash
- Access agent context via `self.agent.context`
- Use `self.method` to support sub-methods (e.g., `my_tool:action1`, `my_tool:action2`)
- Use `kwargs.get()` to read arguments with defaults
- For long operations, use `self.set_progress()` or `self.add_progress()` to show status
- Access `self.loop_data` for loop state (iteration count, timing, etc.) — this is the `LoopData` instance passed during tool dispatch
---
## Creating Extensions
Extensions hook into specific lifecycle points in the agent framework.
### Import Path
```python
from helpers.extension import Extension
```
### Extension Base Class
```python
class Extension:
def __init__(self, agent: "Agent | None", **kwargs):
self.agent: "Agent | None" = agent
self.kwargs = kwargs
def execute(self, **kwargs) -> None | Awaitable[None]:
pass # Override this — kwargs are hook-point-specific
```
> Extensions can be sync or async. If `execute()` returns an `Awaitable`, the framework will `await` it automatically. The `agent` parameter is nullable because some hook points (like `startup_migration` or `banners`) fire before an agent exists.
### Extension File Location
Extensions live in directories named by their hook point. The path structure is:
```
extensions/python/<hook_point>/_NN_name.py
```
Where `_NN_` is a numeric prefix controlling execution order (e.g., `_10_`, `_20_`, `_50_`).
| Source | Path |
|---|---|
| Core extensions | `/a0/extensions/python/<hook_point>/` |
| Plugin extensions | `/a0/plugins/<plugin>/extensions/python/<hook_point>/` |
| User extensions | `/a0/usr/extensions/python/<hook_point>/` |
| Agent profile extensions | `/a0/agents/<profile>/extensions/<hook_point>/` |
| User plugin extensions | `/a0/usr/plugins/<plugin>/extensions/python/<hook_point>/` |
### Python Extension Hook Points
Complete list of available hook points:
| Hook Point | When It Fires | Common Use |
|---|---|---|
| `agent_init` | Agent is initialized | Load configs, set defaults |
| `system_prompt` | System prompt is being assembled | Inject prompt content |
| `monologue_start` | Agent monologue begins | Pre-processing, state setup |
| `message_loop_start` | Before message processing loop | Pre-loop setup |
| `message_loop_prompts_before` | Before prompt assembly in loop | Modify prompt inputs |
| `message_loop_prompts_after` | After prompt assembly in loop | Add context (memory recall lives here) |
| `before_main_llm_call` | Before the LLM API call | Modify prompts, add context |
| `util_model_call_before` | Before utility model calls | Modify utility prompts |
| `response_stream` | When response streaming begins | Initialize stream handlers |
| `response_stream_chunk` | Per response chunk received | Transform output, collect data |
| `response_stream_end` | Response streaming complete | Finalize, analyze full response |
| `reasoning_stream` | Reasoning/thinking stream begins | Monitor reasoning |
| `reasoning_stream_chunk` | Per reasoning chunk | Collect reasoning data |
| `reasoning_stream_end` | Reasoning stream complete | Analyze reasoning |
| `tool_execute_before` | Before a tool runs | Validation, logging, safety checks |
| `tool_execute_after` | After a tool runs | Post-process results |
| `hist_add_before` | Before adding to history | Modify history entries |
| `hist_add_tool_result` | After tool result added to history | Log tool results |
| `message_loop_end` | After message processing loop | Post-loop cleanup |
| `monologue_end` | Agent monologue complete | Memorization, cleanup |
| `process_chain_end` | Entire processing chain done | Final cleanup |
| `job_loop` | Background job loop tick | Periodic background tasks |
| `error_format` | Error is being formatted | Custom error messages |
| `startup_migration` | Framework startup | Data migrations |
| `banners` | Startup banners displayed | Add custom banners |
| `embedding_model_changed` | Embedding model changed | Reload vector stores (fired programmatically, not a directory-based hook) |
| `user_message_ui` | User message from UI | Pre-process user input |
| `webui_ws_connect` | WebSocket client connects | Session setup |
| `webui_ws_disconnect` | WebSocket client disconnects | Session cleanup |
| `webui_ws_event` | WebSocket event received | Handle custom WS events |
### The `@extensible` Decorator (Implicit Extension Points)
Any framework function decorated with `@extensible` automatically gets two extension points:
```
_functions/<module_path>/<qualname_path>/start
_functions/<module_path>/<qualname_path>/end
```
The path mapping converts Python module paths and qualified names using `/` separators:
- Module `agent.py``agent`
- Class method `Agent.handle_exception``Agent/handle_exception`
- Full path: `_functions/agent/Agent/handle_exception/start`
For nested modules like `helpers.history`, a method `History.add` would map to `_functions/helpers/history/History/add/start`.
For example, a function `Agent.handle_exception` in module `agent` creates:
- `_functions/agent/Agent/handle_exception/start`
- `_functions/agent/Agent/handle_exception/end`
Extensions in these directories receive a `data` dict with:
- `data["args"]` — positional args (mutable)
- `data["kwargs"]` — keyword args (mutable)
- `data["result"]` — set this to short-circuit the function
- `data["exception"]` — set to a `BaseException` to force-raise
This is used by plugins like `_error_retry` to wrap core agent methods.
### WebUI Extensions (JavaScript)
Client-side extensions live under `extensions/webui/<hook_point>/`:
| Hook Point | When It Fires |
|---|---|
| `json_api_call_before` | Before a JSON API request |
| `json_api_call_after` | After a JSON API response |
| `fetch_api_call_before` | Before a fetch API request |
| `fetch_api_call_after` | After a fetch API response |
| `get_message_handler` | Register custom message renderers |
| `set_messages_before_loop` | Before messages are rendered |
| `set_messages_after_loop` | After messages are rendered |
| `webui_ws_push` | WebSocket push to client |
### Example: Creating an Extension
Based on the actual `_example` profile in `/a0/agents/_example/extensions/agent_init/_10_example_extension.py`:
```python
# extensions/python/agent_init/_15_my_extension.py
from helpers.extension import Extension
class MyExtension(Extension):
async def execute(self, **kwargs):
# Access the agent
agent = self.agent
context = agent.context
# Extension logic — kwargs content depends on the hook point
agent.agent_name = "CustomAgent" + str(agent.number)
```
### Extension Execution Order
Extensions execute in numeric order based on filename prefix:
```
_10_first.py # Runs first
_20_second.py # Runs second
_50_third.py # Runs third
```
Use 10-number increments to leave room for future extensions.
---
## Creating API Endpoints
API endpoints serve the Web UI and external clients using Flask.
### Import Path
```python
from helpers.api import ApiHandler
from flask import Request, Response
```
### ApiHandler Base Class
```python
class ApiHandler:
def __init__(self, app: Flask, thread_lock: ThreadLockType):
self.app = app
self.thread_lock = thread_lock
# Override these class methods to configure behavior:
@classmethod
def requires_loopback(cls) -> bool: return False # Restrict to localhost
@classmethod
def requires_api_key(cls) -> bool: return False # Require API key
@classmethod
def requires_auth(cls) -> bool: return True # Require auth session
@classmethod
def get_methods(cls) -> list[str]: return ["POST"] # HTTP methods
@classmethod
def requires_csrf(cls) -> bool: return cls.requires_auth() # CSRF protection
# Implement this:
async def process(self, input: dict, request: Request) -> dict | Response:
pass
# Utility: get or create an agent context
def use_context(self, ctxid: str, create_if_not_exists: bool = True) -> AgentContext:
...
```
### Where API Endpoints Live
| Location | Purpose |
|---|---|
| `/a0/api/` | Core API endpoints |
| `/a0/plugins/<plugin>/api/` | Plugin API endpoints |
| `/a0/usr/plugins/<plugin>/api/` | User plugin API endpoints |
Endpoints are auto-discovered by filename. The route is derived from the filename (e.g., `my_endpoint.py` -> `/api/my_endpoint`).
### Example: API Endpoint
```python
# api/my_endpoint.py
from helpers.api import ApiHandler
from flask import Request, Response
from agent import AgentContext
class MyEndpoint(ApiHandler):
@classmethod
def get_methods(cls) -> list[str]:
return ["GET", "POST"]
async def process(self, input: dict, request: Request) -> dict:
param = input.get("param", "default")
# Get or create agent context
ctxid = input.get("context", "")
context = self.use_context(ctxid)
return {
"result": f"processed {param}",
"context": context.id,
}
```
---
## Creating Agent Profiles
Agent profiles define specialized subordinates with custom prompts and behaviors.
> For a guided, step-by-step wizard (scope selection, `agent.yaml` schema, prompt overrides, tool/extension stubs, test checklist) use the dedicated `/a0/skills/a0-create-agent/SKILL.md` skill.
### Profile Directory Structure
```
agents/<profile-name>/
+-- agent.yaml # Required: profile metadata
+-- prompts/ # Optional: prompt overrides
| +-- agent.system.main.role.md # Role definition (most common override)
| +-- agent.system.main.communication.md # Communication style
| +-- agent.system.tool.<name>.md # Tool-specific prompts
+-- tools/ # Optional: profile-specific tools
| +-- my_tool.py
+-- extensions/ # Optional: profile-specific extensions
+-- <hook_point>/
+-- _NN_extension.py
```
### agent.yaml Format
The actual format is simple YAML with only three fields:
```yaml
title: Developer
description: Agent specialized in complex software development.
context: Use this agent for software development tasks, including writing code,
debugging, refactoring, and architectural design.
```
| Field | Purpose |
|---|---|
| `title` | Display name shown in UI and agent selection |
| `description` | Brief description of the agent's specialization |
| `context` | Instructions for when to delegate to this profile |
> [!NOTE]
> There is **no** model configuration, temperature, or allowed_tools in the profile YAML. `agent.yaml` contains only `title`, `description`, and `context`. Profile-specific Main/Utility model settings are managed by the `_model_config` plugin in `usr/agents/<profile>/plugins/_model_config/config.json`. Tool availability is controlled by plugin activation.
### Where Profiles Live
| Location | Purpose |
|---|---|
| `/a0/agents/` | Core profiles (default, agent0, developer, hacker, researcher) |
| `/a0/usr/agents/` | User-created profiles (survives updates) |
### Prompt Override Mechanism
Profiles inherit all prompts from the `default/` profile. To customize behavior, place prompt files with the **same name** in your profile's `prompts/` directory. The framework searches profile-specific prompts first, then falls back to the default.
The most common override is `agent.system.main.role.md` which defines the agent's role and specialization.
### Example: Creating a Profile
```yaml
# /a0/usr/agents/data-analyst/agent.yaml
title: Data Analyst
description: Agent specialized in data analysis, visualization, and statistical modeling.
context: Use this agent for data analysis tasks, creating visualizations, statistical
analysis, and working with datasets in Python.
```
```markdown
<!-- /a0/usr/agents/data-analyst/prompts/agent.system.main.role.md -->
## Your role
You are a specialized data analysis agent.
Your expertise includes:
- Python data analysis (pandas, numpy, scipy)
- Data visualization (matplotlib, seaborn, plotly)
- Statistical modeling and hypothesis testing
- SQL queries and database analysis
- Data cleaning and preprocessing
## Process
1. Understand the data and the question
2. Choose appropriate tools and methods
3. Execute analysis with code_execution_tool
4. Visualize results when applicable
5. Provide clear interpretation of findings
```
### Reference: The `_example` Profile
The framework includes a complete example profile at `/a0/agents/_example/` that demonstrates:
- Custom tool: `/a0/agents/_example/tools/example_tool.py`
- Custom extension: `/a0/agents/_example/extensions/agent_init/_10_example_extension.py`
- Tool prompt: `/a0/agents/_example/prompts/agent.system.tool.example_tool.md`
- Role prompt: `/a0/agents/_example/prompts/agent.system.main.role.md`
---
## Prompt System
Agent Zero assembles system prompts from **named fragments** using includes and variable substitution.
### Prompt File Naming Convention
Prompt files follow a dot-separated naming scheme:
```
agent.system.main.md # Main system prompt (entry point)
agent.system.main.role.md # Role definition
agent.system.main.communication.md # Communication style
agent.system.tool.<name>.md # Tool usage instructions
agent.system.tools.md # Tools overview
agent.system.projects.main.md # Project system
agent.system.secrets.md # Secret handling
agent.system.skills.md # Skills listing
agent.system.datetime.md # Current date/time
agent.context.extras.md # Context extras
fw.*.md # Framework messages (errors, hints, etc.)
```
### Where Prompts Live
| Location | Priority | Purpose |
|---|---|---|
| `/a0/agents/<profile>/prompts/` | Highest | Profile-specific overrides |
| `/a0/usr/agents/<profile>/prompts/` | High | User profile overrides |
| `/a0/plugins/<plugin>/prompts/` | Normal | Plugin-provided prompts |
| `/a0/usr/plugins/<plugin>/prompts/` | Normal | User plugin prompts |
| `/a0/prompts/` | Base | Core framework prompts |
The framework searches directories in priority order and uses the **first match** found.
### Include Mechanism
Prompts can include other fragments using double-brace `include` directives.
The syntax uses opening double-brace, the keyword, and closing double-brace:
| Directive | Purpose |
|---|---|
| `{{include "agent.system.main.role.md"}}` | Include a named prompt fragment |
| `{{include "agent.system.main.communication.md"}}` | Include another fragment |
| `{{include original}}` | Include the same file from the next lower-priority directory |
The `include original` directive is particularly useful for **extending** rather than fully **replacing** a prompt — your override can include the base version and add to it.
### Variable Substitution
Prompts support `{{variable_name}}` placeholders that are replaced at render time with values passed from the framework or plugin configuration.
### Conditional Blocks
Prompts support conditional rendering based on variables.
### Reading Prompts in Code
```python
# From within an Agent method:
content = self.read_prompt("fw.some_message.md", variable1="value1")
# From helpers:
from helpers.files import read_prompt_file
content = read_prompt_file("template.md", _directories=[...], var="value")
```
---
## Creating Skills
Skills are reusable instruction bundles that the agent loads on demand via the `skills_tool`. Each skill lives in a directory containing a `SKILL.md` file with YAML frontmatter.
| Location | Purpose |
|---|---|
| `/a0/skills/` | Core skills (shipped with framework) |
| `/a0/usr/skills/` | User-created skills (survives updates) |
The agent interacts with skills through JSON tool calls:
Load references with:
```json
{"tool_name": "skills_tool:list", "tool_args": {}}
{"tool_name": "skills_tool:load", "tool_args": {"skill_name": "my-skill"}}
{"tool_name": "skills_tool:read_file", "tool_args": {"skill_name": "a0-development", "file_path": "references/<file>.md"}}
```
> For the complete skill creation wizard — including SKILL.md format, frontmatter fields, directory structure, best practices, and examples — load the `build-skill` skill.
---
## Working with Projects
Projects provide isolated workspaces with custom configuration.
> Projects are typically created and managed via the Web UI. The `.a0proj/` directory and `project.json` are auto-generated when you create a project through the UI.
### Project Structure
```
/a0/usr/projects/<project-name>/
+-- .a0proj/
| +-- project.json # Project configuration
| +-- agents.json # Per-project agent overrides
| +-- variables.env # Non-sensitive variables
| +-- secrets.env # Encrypted secrets
| +-- memory/ # Project-specific memory
| +-- index.faiss
| +-- index.pkl
| +-- embedding.json
+-- <project-files>/ # Your project files (working directory)
```
### project.json Format
```json
{
"title": "My Project",
"description": "Project description",
"instructions": "Markdown instructions for the agent when this project is active",
"color": "#3a86ff",
"git_url": "",
"memory": "own",
"file_structure": {
"enabled": true,
"max_depth": 5,
"max_files": 20,
"max_folders": 20,
"max_lines": 250,
"gitignore": ".a0proj/\nvenv/\n**/__pycache__/\n**/node_modules/\n**/.git/\n"
}
}
```
| Field | Purpose |
| Need | Read |
|---|---|
| `title` | Display name |
| `description` | Brief description |
| `instructions` | Markdown injected into agent system prompt when project is active |
| `color` | UI accent color (hex) |
| `git_url` | Optional Git repository URL |
| `memory` | `"own"` for project-specific memory, or shared |
| `file_structure` | Controls the working directory tree shown to the agent |
| Runtime split, root layout, discovery order, path and port boundaries | `references/architecture-runtime.md` |
| DOX edit workflow, when to update docs, file-level DOX checks | `references/dox-workflow.md` |
| Tool contracts, locations, prompts, and verification | `references/tools.md` |
| Python/WebUI extension discovery, hook points, ordering, implicit hooks | `references/extensions.md` |
| HTTP API, WebSocket handlers, WebUI extension surfaces | `references/api-webui.md` |
| Agent profiles, prompts, skills, projects | `references/agents-prompts-skills-projects.md` |
| Plugin-first workflow, where to put new work, handoffs to plugin skills | `references/plugins-workflow.md` |
---
## Working Flow
## Plugin System Overview
1. Classify the request: tool, extension, API/WebUI, profile, prompt, skill, project, plugin, runtime, or docs.
2. Read the root `AGENTS.md`, then the nearest child `AGENTS.md` files for the target paths.
3. Read the focused reference file from this skill.
4. Inspect the current source files named by the reference before making a claim or patch.
5. Keep changes narrow and in the repo-owned surface. Prefer `usr/` for user-created runtime content, but do not document ignored user state unless requested.
6. Update DOX when a durable contract, path, behavior, workflow, responsibility, or verification rule changes.
7. Run targeted checks from the relevant DOX file. For skill-only changes, at minimum verify frontmatter parsing, reference paths, and markdown sanity.
Plugins are the **primary extension mechanism** in Agent Zero. A plugin can bundle tools, extensions, prompts, API endpoints, helpers, and UI components into a self-contained package.
## Handoffs
> For all plugin tasks — creating, reviewing, managing, contributing, or debugging plugins — load the `a0-plugin-router` skill, which routes to the appropriate specialist skill.
- Plugin creation: load `a0-create-plugin`.
- Plugin management or installation: load `a0-manage-plugin`.
- Plugin debugging: load `a0-debug-plugin`.
- Plugin review or publishing: load `a0-review-plugin` or `a0-contribute-plugin`.
- Agent profile creation: load `a0-create-agent`.
- Skill creation or skill format work: load `build-skill`.
### Core Plugins
## Closeout
The framework ships with these core plugins in `/a0/plugins/`:
| Plugin | Purpose |
|---|---|
| `_code_execution` | Terminal, Python, Node.js code execution |
| `_memory` | Persistent vector memory system |
| `_text_editor` | File read/write/patch with line numbers |
| `_model_config` | LLM model selection and configuration |
| `_browser` | Direct browser automation and WebUI viewing |
| `_infection_check` | Prompt injection safety checks |
| `_error_retry` | Retry on critical exceptions |
| `_email_integration` | Email communication via IMAP/SMTP |
| `_telegram_integration` | Telegram bot integration |
| `_chat_branching` | Branch chats from any message |
| `_promptinclude` | Persistent behavioral rules (*.promptinclude.md) |
| `_plugin_installer` | Install plugins from ZIP/Git/Hub |
| `_plugin_scan` | Security scanning for plugins |
| `_plugin_validator` | Plugin manifest and code validation |
---
## Common Patterns Reference
### Accessing Agent Context
```python
# Shared across all agents in a conversation
context = self.agent.context
data = context.data # dict-like shared state
# Store data
data["my_key"] = my_value
# Retrieve data
value = data.get("my_key", default)
```
### Using File Helpers
```python
from helpers import files
# File operations
content = files.read_file("path/to/file")
files.write_file("path/to/file", content)
exists = files.exists("path/to/file")
# Read and render a prompt file
content = files.read_prompt_file("template.md", _directories=[...], var="value")
```
### Console Output
```python
from helpers.print_style import PrintStyle
PrintStyle.hint("Informational message")
PrintStyle.warning("Warning message")
PrintStyle.error("Error message")
PrintStyle(font_color="#85C1E9").print("Custom styled output")
```
### Error Handling
```python
from helpers.tool import Response
try:
result = await risky_operation()
except Exception as e:
PrintStyle.error(f"Operation failed: {e}")
return Response(message=f"Error: {e}", break_loop=False)
```
---
## Development Workflow
When building features for Agent Zero:
### 1. Choose Your Extension Point
| Want to... | Use |
|---|---|
| Add a new agent capability | **Tool** (in a plugin) |
| Hook into agent lifecycle | **Extension** (in a plugin) |
| Add Web UI functionality | **API endpoint** + **WebUI extension** |
| Create a specialized agent | **Agent profile** |
| Bundle reusable instructions | **Skill** |
| Package everything together | **Plugin** (recommended) |
### 2. Develop in User Space
- New plugins -> `/a0/usr/plugins/<name>/`
- New profiles -> `/a0/usr/agents/<name>/`
- New skills -> `/a0/usr/skills/<name>/`
- New extensions -> `/a0/usr/extensions/python/<hook_point>/`
### 3. Test and Iterate
- **Local dev**: Run `python run_ui.py` (default port 50001 at `http://localhost:50001`)
- **Docker**: Restart the container or use the UI restart button; check logs with `docker logs -f <container_name>`
- Test with minimal input first
- Verify in the Web UI
### 4. Contributing
For contribution guidelines, see `/a0/docs/contribution.md`. For plugin contributions to the community Plugin Index, load the `a0-contribute-plugin` skill.
---
## Best Practices
### DO
- Use the **plugin system** for new features (see `a0-create-plugin` skill)
- Follow existing code patterns and conventions
- Write clear docstrings and comments
- Handle errors gracefully in tools and extensions
- Create prompt fragments for every tool (`agent.system.tool.<name>.md`)
- Develop in `/a0/usr/` directories to survive updates
- Test with the `_example` profile as a reference
- Use `from helpers.*` imports (not `from python.helpers.*`)
### DON'T
- Modify files in `/a0/plugins/` or `/a0/tools/` directly (use usr/ space)
- Hardcode paths or configuration values
- Skip creating prompt files for tools
- Ignore the plugin system (it's the intended extension mechanism)
- Mix sync and async code carelessly
- Access internal structures when helpers exist
---
## Quick Reference: Key Files
| File | Purpose |
|---|---|
| `/a0/agent.py` | Core `Agent`, `AgentContext`, `AgentConfig` classes |
| `/a0/helpers/tool.py` | `Tool` + `Response` base classes |
| `/a0/helpers/extension.py` | `Extension` base + `@extensible` decorator |
| `/a0/helpers/api.py` | `ApiHandler` base class |
| `/a0/helpers/files.py` | File ops + prompt reading |
| `/a0/helpers/plugins.py` | Plugin system manager |
| `/a0/helpers/print_style.py` | Console output formatting |
| `/a0/agents/_example/` | Reference example profile with tool + extension |
| `/a0/prompts/agent.system.main.md` | Main system prompt entry point |
Report the exact files changed, the grounding checks used, whether DOX was updated or intentionally left unchanged, and what verification ran. If a claim depends on a live Docker runtime, include the runtime proof, not only checkout evidence.

View file

@ -0,0 +1,38 @@
# A0 Development References DOX
## Purpose
- Own focused reference files loaded by the `a0-development` skill on demand.
- Keep detailed framework-development guidance grounded in current source files and nearest DOX contracts.
## Ownership
- `architecture-runtime.md` owns runtime, path, discovery-order, and port-boundary guidance.
- `dox-workflow.md` owns the edit and closeout workflow for DOX-governed changes.
- `tools.md` owns core and plugin tool development contracts.
- `extensions.md` owns backend and frontend extension contracts.
- `api-webui.md` owns HTTP API, WebSocket, and WebUI extension guidance.
- `agents-prompts-skills-projects.md` owns profiles, prompt fragments, skills, and project metadata guidance.
- `plugins-workflow.md` owns plugin-first placement and handoff guidance.
## Local Contracts
- Every reference file must list source anchors or DOX anchors that can be checked in the repository.
- Prefer pointing to narrower `AGENTS.md` files instead of copying long subtree contracts.
- Keep examples minimal and compatible with the current helper classes.
- Do not include hardcoded default WebUI ports or environment-specific credentials.
## Work Guidance
- Update the focused reference file when source or DOX changes make its guidance stale.
- If a reference starts duplicating a specialist skill, shorten it and hand off to that skill instead.
- Treat checked-in examples as examples, not authority, when they conflict with current discovery code.
## Verification
- Manually read changed references for broken relative paths, stale source anchors, and duplicated specialist-skill material.
- After changing reference names, load `a0-development` and confirm the file tree exposes the new paths through `skills_tool`.
## Child DOX Index
No child DOX files.

View file

@ -0,0 +1,95 @@
# Agents, Prompts, Skills, And Projects
## Source Anchors
- Agent profiles: `/a0/helpers/subagents.py`, `/a0/agents/AGENTS.md`
- Prompt rendering: `/a0/agent.py`, `/a0/helpers/files.py`, `/a0/prompts/AGENTS.md`
- Skill runtime: `/a0/helpers/skills.py`, `/a0/tools/skills_tool.py`, `/a0/skills/AGENTS.md`
- Project metadata: `/a0/helpers/projects.py`, `/a0/api/projects.py`, `/a0/webui/components/projects/`
## Agent Profiles
Bundled profiles live under `agents/<profile>/`. User-created profiles live under `usr/agents/<profile>/`. Plugin-distributed profiles live under plugin `agents/` directories.
The current profile loader accepts `agent.yaml` or `agent.json` and validates through `helpers.subagents.SubAgentListItem` / `SubAgent` fields:
| Field | Meaning |
|---|---|
| `title` | Human-readable display name. Defaults to profile name if empty. |
| `description` | Brief specialization. |
| `context` | Delegation guidance for when to use the profile. |
| `enabled` | Optional availability flag in list contexts. |
Bundled `agent.yaml` files currently use `title`, `description`, and `context`. Model settings are not read from `agent.yaml`; the `_model_config` plugin owns model configuration and scoped overrides.
Profile folders may contain `prompts/`, `tools/`, `extensions/`, and `skills/`, but verify discovery code before relying on example layout. Source and DOX beat stale examples.
## Prompt System
Agents render prompt fragments through `Agent.read_prompt(...)`, which calls `helpers.files.read_prompt_file(...)`.
Prompt capabilities:
- Placeholder replacement with `{{variable_name}}`.
- Conditional blocks with `{{if ...}} ... {{endif}}`.
- Include directives such as `{{include "file.md"}}`.
- `{{include original}}` to include the same file from a lower-priority directory.
Prompt locations include:
| Location | Use |
|---|---|
| `prompts/` | Core framework prompts. |
| `agents/<profile>/prompts/` | Bundled profile overrides. |
| `usr/agents/<profile>/prompts/` | User profile overrides. |
| `plugins/<plugin>/prompts/` | Bundled plugin prompt additions or overrides. |
| `usr/plugins/<plugin>/prompts/` | User plugin prompts. |
Prompt changes can change agent behavior. Keep edits narrow and run targeted prompt, budget, snapshot, tool, or behavior tests.
## Skills
Skills are directories containing `SKILL.md` frontmatter plus optional `references/`, `scripts/`, or `assets/`.
Skill roots come from `helpers.skills.get_skill_roots(...)`, including bundled skills, user skills, project metadata, profile skills, and plugin skills.
`skills_tool` actions:
| Action | Purpose |
|---|---|
| `list` | List available skills without full content. |
| `search` | Search skill metadata and triggers. |
| `load` | Load `SKILL.md` body and show the skill file tree. |
| `read_file` | Read a file inside the skill directory, such as `references/foo.md`. |
Keep always-loaded `SKILL.md` concise. Move long examples, schemas, policies, and variant-specific details into one-level-deep `references/` files and tell the agent when to read them.
Use `build-skill` for skill creation and skill format work.
## Projects
Projects live under `usr/projects/<name>/` and store metadata in `.a0proj/`.
Important project files and folders:
| Path | Purpose |
|---|---|
| `.a0proj/project.json` | Project title, description, instructions, color, git URL, include-AGENTS option, and file-structure settings. |
| `.a0proj/instructions/` | Additional text instruction files. |
| `.a0proj/knowledge/` | Project knowledge files. |
| `.a0proj/variables.env` | Non-sensitive project variables. |
| `.a0proj/secrets.env` | Encrypted project secrets. |
| `.a0proj/agents/` | Per-project agent profile material. |
| `.a0proj/skills/` | Project-scoped skills. |
| `.a0proj/mcp_servers.json` | Project MCP server configuration. |
`helpers.projects.BasicProjectData` currently normalizes `title`, `description`, `instructions`, `include_agents_md`, `color`, `git_url`, and `file_structure`. `EditProjectData` adds runtime/editing fields such as `variables`, `secrets`, `mcp_servers`, `subagents`, and git status.
Project file-structure injection uses settings for `enabled`, `max_depth`, `max_files`, `max_folders`, `max_lines`, and `gitignore`.
## Verification
- Run profile-loading tests when changing agent profile schema or discovery.
- Inspect rendered prompts when changing prompt filenames, include behavior, placeholders, or prompt order.
- Run skill runtime/catalog tests after changing skill loading, search, active/hidden behavior, or skill format.
- For project changes, test create/load/edit paths and project prompt injection when relevant.

View file

@ -0,0 +1,93 @@
# API And WebUI
## Source Anchors
- HTTP handler base and route registration: `/a0/helpers/api.py`
- API DOX: `/a0/api/AGENTS.md`
- WebSocket handler base: `/a0/helpers/ws.py`
- WebUI shell DOX: `/a0/webui/AGENTS.md`
- Component and JS DOX: `/a0/webui/components/AGENTS.md`, `/a0/webui/js/AGENTS.md`
- Frontend extension loading: `/a0/webui/js/extensions.js`
## HTTP API Contract
HTTP API handlers derive from `helpers.api.ApiHandler`:
```python
from flask import Request, Response
from helpers.api import ApiHandler
class MyEndpoint(ApiHandler):
@classmethod
def get_methods(cls) -> list[str]:
return ["POST"]
async def process(self, input: dict, request: Request) -> dict | Response:
return {"ok": True}
```
Defaults from `ApiHandler`:
| Method | Default |
|---|---|
| `requires_loopback()` | `False` |
| `requires_api_key()` | `False` |
| `requires_auth()` | `True` |
| `get_methods()` | `["POST"]` |
| `requires_csrf()` | `requires_auth()` |
Override these only when the endpoint contract requires it. Keep auth and CSRF protection intact for browser-facing state changes.
## API Routes
`helpers.api.register_api_route(...)` registers:
```text
/api/<path:path>
```
Resolution:
- Built-in endpoint `api/<name>.py` becomes `/api/<name>`.
- Plugin endpoint `plugins/<plugin>/api/<handler>.py` becomes `/api/plugins/<plugin>/<handler>`.
Return a Flask `Response` for files, redirects, custom status codes, and plain text. Return a dictionary for JSON success payloads.
Direct files under `api/*.py` require matching `api/*.py.dox.md`.
## WebSocket Handlers
WebSocket handlers live in `api/ws_*.py` or plugin API folders and derive from `helpers.ws.WsHandler`:
```python
from helpers.ws import WsHandler
class MyHandler(WsHandler):
async def process(self, event: str, data: dict, sid: str) -> dict | None:
return {"ok": True}
```
`WsHandler` mirrors `ApiHandler` security flags: auth defaults to `True`, CSRF defaults to auth, API-key and loopback default to `False`. Handlers should validate event data before using it and avoid returning secrets or unfiltered exception details.
## WebUI Work
Follow the nearest WebUI DOX before changing frontend files:
- `webui/AGENTS.md` for the shell, CSS, assets, vendor, and extension loader.
- `webui/js/AGENTS.md` for stores, modals, API helpers, and JS infrastructure.
- `webui/components/AGENTS.md` and child docs for Alpine components.
Patterns:
- Store-dependent content should be gated by a `template x-if` guard before using `$store.<name>`.
- Stores are registered with `createStore` from `/js/AlpineStore.js`.
- Modals use `openModal(path)` and `closeModal()` from `/js/modals.js`.
- Plugin settings UIs bind persisted plugin values to `config.*` and modal-only state/actions to `context.*`.
- Plugin UI should use the A0 notification system instead of inline success/error boxes.
## Verification
- Run endpoint-specific tests or nearest API/WebSocket tests for handler behavior.
- For auth, CSRF, upload/download, tunnel, or file endpoints, run security-focused regressions.
- For WebUI changes, use targeted component/store tests or a browser smoke check when practical.
- Check file-level DOX coverage when touching direct `api/*.py` modules.

View file

@ -0,0 +1,79 @@
# Architecture And Runtime
## Source Anchors
- Root contract: `/a0/AGENTS.md`
- WebUI entry point: `/a0/run_ui.py`
- Runtime arguments and WebUI port resolution: `/a0/helpers/runtime.py`
- Docker Python runtimes: `/a0/docker/base/fs/ins/install_python.sh`
- Docker framework activation: `/a0/docker/run/fs/ins/setup_venv.sh`
- Docker UI launch manager: `/a0/docker/run/fs/exe/self_update_manager.py`
- Search/discovery roots: `/a0/helpers/subagents.py`, `/a0/helpers/skills.py`, `/a0/helpers/projects.py`
## Runtime Split
Agent Zero has two Docker Python runtimes:
| Runtime | Python | Purpose |
|---|---|---|
| `/opt/venv-a0` | 3.12.4 | Framework runtime. Runs the WebUI backend, API, scheduler, agent loop, framework imports, plugin hooks, and framework-side tools. |
| `/opt/venv` | 3.13 | Agent execution runtime. Use for Python code executed on behalf of the agent or user task dependencies. |
Use `/opt/venv-a0` for framework import checks, WebUI startup checks, API/plugin hook behavior, and `py_compile` of framework code inside Docker. Use `/opt/venv` only when the feature explicitly targets agent/user code execution.
Do not claim a package works in the framework because it imports in `/opt/venv`, and do not claim user-code execution works because it imports in `/opt/venv-a0`.
## Ports And URLs
Do not hardcode a WebUI default port in guidance. Discover the effective URL from:
- WebUI startup output.
- Launcher or Docker published-port mapping.
- Explicit `--host` and `--port` arguments.
- `WEB_UI_HOST` and `WEB_UI_PORT` environment configuration.
- Live container inspection when the task targets a running runtime.
`helpers.runtime.get_web_ui_port()` has a code fallback, and the Docker UI manager passes an internal container port. Those are implementation details, not a stable user-facing URL contract.
## Root Paths
- `/a0/` means the framework root inside the Docker runtime.
- In a local checkout, `/a0/` in documentation maps to the repository root.
- `usr/` contains user state, projects, settings, skills, plugins, chats, and workdirs.
- `tmp/` contains runtime caches and generated working files.
- Do not document ignored `usr/` or `tmp/` changes unless explicitly asked.
When the user names a live Dockerized runtime, the live `/a0` tree is a separate artifact. Verify the file sync or runtime state directly before treating checkout code as live behavior.
## Project Layout
Key root areas:
| Path | Purpose |
|---|---|
| `agent.py` | `Agent`, `AgentContext`, `AgentConfig`, prompt reading, tool loop. |
| `initialize.py` | Framework initialization and background loop startup. |
| `models.py` | Model provider and LiteLLM transport configuration. |
| `run_ui.py` | Flask/Socket.IO ASGI WebUI startup. |
| `api/` | HTTP API handlers and `ws_*.py` WebSocket handlers. |
| `helpers/` | Shared framework utilities and base contracts. |
| `tools/` | Core tool implementations. |
| `extensions/` | Built-in backend and WebUI extension points. |
| `plugins/` | Bundled system plugins. |
| `agents/` | Bundled agent profiles. |
| `prompts/` | Core prompt fragments. |
| `skills/` | Bundled skills. |
| `webui/` | Alpine.js frontend shell, components, CSS, assets, and vendor code. |
## Discovery Order
Agent-specific path resolution is handled by `helpers.subagents.get_paths(...)`. In broad terms, project and user/profile paths have higher priority than plugin and bundled defaults, then user root/plugin roots, then base defaults. Inspect `helpers/subagents.py` for exact order before changing discovery behavior.
Skill discovery is handled by `helpers.skills.get_skill_roots(...)`. Skills may come from bundled `skills/`, user `usr/skills/`, project metadata, agent profile folders, and plugin roots. Loaded skills can expose additional files via `skills_tool action=read_file`.
## Development Bias
- Prefer plugins for new capabilities.
- Prefer `helpers/` only for reusable framework behavior.
- Prefer small, source-backed changes over broad rewrites.
- If an example conflicts with source discovery code or DOX, treat the example as stale until verified.

View file

@ -0,0 +1,66 @@
# DOX Workflow
## Source Anchors
- Root DOX contract: `/a0/AGENTS.md`
- Skill parent contract: `/a0/skills/AGENTS.md`
- Local skill contract: `/a0/skills/a0-development/AGENTS.md`
- Reference-file contract: `/a0/skills/a0-development/references/AGENTS.md`
- File-level DOX examples: `/a0/api/*.py.dox.md`, `/a0/tools/*.py.dox.md`, `/a0/helpers/*.py.dox.md`
## Before Editing
1. Read the root `AGENTS.md`.
2. Identify every path you expect to touch.
3. Walk from the root to each target path.
4. Read every `AGENTS.md` found on that route.
5. If a parent `AGENTS.md` lists a child whose scope contains the path, read that child and continue.
6. Use the nearest `AGENTS.md` as the local contract. Parent docs still apply.
7. If docs conflict, the closer doc controls local details, but no child weakens DOX.
Do not rely on memory for DOX. Re-read the current files.
## When To Update DOX
Update the nearest owning `AGENTS.md` when a meaningful change affects:
- Purpose, ownership, responsibilities, or scope.
- Durable structure, directories, file contracts, or child indexes.
- Runtime behavior, required inputs/outputs, side effects, or verification rules.
- User or agent workflow rules.
- Creation, deletion, rename, or movement of an `AGENTS.md` file.
Update parent docs when parent-level structure or child indexes change. Remove stale or contradictory text rather than explaining old history.
Small implementation edits that do not change contracts may leave DOX unchanged, but still perform the DOX closeout pass and say why docs stayed unchanged.
Do not create or update DOX under ignored `usr/` or `tmp/` unless explicitly requested.
## File-Level DOX
Some directories require per-file `.dox.md` companions:
| Directory | Requirement |
|---|---|
| `api/` | Every direct `*.py` endpoint or `ws_*.py` module must have matching `*.py.dox.md`. |
| `tools/` | Every direct `*.py` tool module must have matching `*.py.dox.md`. |
| `helpers/` | Many helper modules use file-level DOX; follow `helpers/AGENTS.md` before changing helper behavior. |
When adding, deleting, renaming, or behaviorally changing one of those files, update the companion DOX in the same change.
## Closeout
1. Re-check changed paths against the DOX chain.
2. Update nearest owning docs and affected parents or children.
3. Refresh affected Child DOX Index tables.
4. Remove stale or contradictory text.
5. Run relevant verification from the nearest DOX.
6. Report docs intentionally left unchanged and why.
## Practical Verification
- `git diff --check` for whitespace.
- Targeted tests named by the relevant DOX file.
- Manual read-through for skill/reference link changes.
- Shell coverage checks for file-level DOX when touching `api/` or `tools/`.
- Runtime or live-container proof when the user asks about the running Dockerized system.

View file

@ -0,0 +1,150 @@
# Extensions
## Source Anchors
- Extension base and discovery: `/a0/helpers/extension.py`
- Backend extension DOX: `/a0/extensions/AGENTS.md`, `/a0/extensions/python/AGENTS.md`
- WebUI extension DOX: `/a0/extensions/webui/AGENTS.md`
- Plugin extension contract: `/a0/plugins/AGENTS.md`
- Example profile note: `/a0/agents/_example/AGENTS.md`
## Python Extension Contract
Backend extensions derive from `helpers.extension.Extension`:
```python
from helpers.extension import Extension
class MyExtension(Extension):
async def execute(self, **kwargs):
...
```
`self.agent` may be `None` for startup or non-agent hooks. Match the arguments supplied by the hook point. Keep imports light because many extensions run in hot paths.
## Python Discovery Layout
`helpers.extension._get_extension_classes(...)` discovers backend extension classes through:
```text
extensions/python/<extension_point>/
```
using `helpers.subagents.get_paths(agent, "extensions/python", extension_point)`.
Common locations:
| Location | Use |
|---|---|
| `extensions/python/<point>/` | Built-in framework extension. |
| `plugins/<plugin>/extensions/python/<point>/` | Bundled plugin extension. |
| `usr/plugins/<plugin>/extensions/python/<point>/` | User plugin extension. |
| `usr/extensions/python/<point>/` | Standalone user extension. Prefer plugin packaging for durable features. |
| Project/profile roots resolved by `helpers.subagents.get_paths(...)` | Scope-specific extension overrides when discovery supports the path. Verify before copying examples. |
The checked-in `_example` profile contains an older-looking `agents/_example/extensions/agent_init/...` sample. Current discovery code expects `extensions/python/<point>`. Treat source code and DOX as authority before copying profile extension layout.
## Ordering And Overrides
- Files are sorted by filename. Numeric prefixes like `_10_`, `_20_`, `_50_` control order.
- Use gaps between prefixes so future extensions can fit between them.
- Discovery de-duplicates by module filename, preserving the first occurrence by search priority.
- Do not bypass secret masking, auth, persistence, or cleanup extensions for convenience.
## Implicit `@extensible` Hooks
Functions decorated with `@extensible` emit two implicit hook points:
```text
_functions/<module>/<qualname>/start
_functions/<module>/<qualname>/end
```
The path preserves every module segment and nested qualname segment. Example:
```text
helpers.something.Outer.Inner.__init__
```
becomes:
```text
_functions/helpers/something/Outer/Inner/__init__/start
_functions/helpers/something/Outer/Inner/__init__/end
```
Extensions receive a mutable `data` dict with `args`, `kwargs`, `result`, and `exception`. They may mutate inputs, short-circuit by setting `result`, or force/clear an exception.
Do not use retired flattened `_functions` folder names.
## Current Built-In Python Hook Directories
Directory-backed built-in hook points currently include:
```text
agent_init
banners
before_main_llm_call
error_format
hist_add_before
hist_add_tool_result
job_loop
message_loop_end
message_loop_prompts_after
message_loop_prompts_before
message_loop_start
monologue_end
monologue_start
process_chain_end
reasoning_stream
reasoning_stream_chunk
reasoning_stream_end
response_stream
response_stream_chunk
response_stream_end
startup_migration
system_prompt
tool_execute_after
tool_execute_before
user_message_ui
util_model_call_before
webui_ws_connect
webui_ws_disconnect
webui_ws_event
```
This list comes from the current `extensions/python/` tree. Re-check the tree before claiming the complete current set.
## WebUI Extension Points
Frontend extension files live under:
```text
extensions/webui/<point>/
plugins/<plugin>/extensions/webui/<point>/
usr/plugins/<plugin>/extensions/webui/<point>/
```
Current built-in WebUI extension directories include:
```text
fetch_api_call_after
fetch_api_call_before
get_message_handler
initFw_end
json_api_call_after
json_api_call_before
right-canvas-panels
right_canvas_register_surfaces
set_messages_after_loop
set_messages_before_loop
webui_ws_push
```
Plugin frontend HTML extensions should include a root Alpine scope and use `x-move-*` directives when targeting static breakpoints. JS extensions export a default function.
## Verification
- Run targeted lifecycle, prompt, stream, WebSocket, or WebUI extension tests for changed hook points.
- Smoke-test startup for `agent_init`, `startup_migration`, and `system_prompt` changes when practical.
- Check the exact directory path used by `helpers.extension` before adding profile or plugin extension files.

View file

@ -0,0 +1,91 @@
# Plugins And Development Workflow
## Source Anchors
- Plugin contract: `/a0/plugins/AGENTS.md`
- Plugin helper code: `/a0/helpers/plugins.py`
- Plugin specialist skills: `/a0/skills/a0-plugin-router/SKILL.md`, `/a0/skills/a0-create-plugin/SKILL.md`, `/a0/skills/a0-debug-plugin/SKILL.md`, `/a0/skills/a0-review-plugin/SKILL.md`
- Root development contract: `/a0/AGENTS.md`
## Plugin-First Rule
Plugins are the primary way to extend Agent Zero. A plugin can bundle:
- `plugin.yaml`
- `default_config.yaml`
- `hooks.py`
- `execute.py`
- `tools/`
- `api/`
- `helpers/`
- `prompts/`
- `skills/`
- `extensions/python/`
- `extensions/webui/`
- `webui/`
- plugin-local docs and assets
Use root framework directories only when changing bundled framework behavior itself. For custom or experimental work, use `usr/plugins/<plugin>/` unless the task is explicitly to change a bundled plugin.
## Imports And Runtime
- Bundled plugins under `plugins/` may use `plugins.<plugin_name>...` imports.
- User plugins under `usr/plugins/` should use `usr.plugins.<plugin_name>...` imports.
- Avoid `sys.path` hacks and symlink-dependent imports.
- `hooks.py` runs inside the framework runtime (`/opt/venv-a0` in Docker).
- If a plugin must prepare the agent execution runtime or system packages, it must explicitly target that environment in a subprocess.
## Manifest And Configuration
Every plugin needs `plugin.yaml`. Runtime fields include:
- `name`
- `title`
- `description`
- `version`
- `settings_sections`
- `per_project_config`
- `per_agent_config`
- `always_enabled`
Defaults belong in `default_config.yaml`. Runtime user settings belong under `usr/`.
Settings resolution order is project/profile, project, user/profile, user plugin config, then bundled `default_config.yaml`.
## Activation And Cleanup
- Global and scoped activation are independent.
- Activation files use `.toggle-1` for ON and `.toggle-0` for OFF.
- `always_enabled: true` forces ON and disables UI toggles.
- Plugin deletion or disablement should not leave unmanaged services, symlinks, or files outside plugin-owned paths unless explicitly documented with cleanup.
## Routes And UI
Plugin routes:
| Route | Purpose |
|---|---|
| `GET /plugins/<name>/<path>` | Static/plugin web assets. |
| `POST /api/plugins/<name>/<handler>` | Plugin API handler. |
| `POST /api/plugins` | Plugin management actions. |
Plugin settings UIs should bind saved values to `config.*` and modal-only state/actions to `context.*` through `$store.pluginSettingsPrototype`.
Plugin UI errors, warnings, success, and info should use the A0 notification system.
## Workflow
1. Decide whether the request is plugin-specific. If yes, load `a0-plugin-router`.
2. If creating a plugin, load `a0-create-plugin`.
3. If debugging a plugin, load `a0-debug-plugin`.
4. If reviewing or publishing a plugin, load `a0-review-plugin` or `a0-contribute-plugin`.
5. Read `plugins/AGENTS.md` and any plugin-local `AGENTS.md`.
6. Keep changes inside the plugin boundary unless shared framework behavior truly belongs in `helpers/` or root code.
7. Update plugin docs/DOX when user-visible behavior, configuration, routes, hooks, or cleanup changes.
## Verification
- Run plugin-specific tests after changing a bundled plugin.
- Run framework tests for touched tools, API handlers, extension points, settings, or WebUI surfaces.
- Smoke-test external-service, browser, desktop, or connector integrations when practical.
- For discovery banners/cards, verify rendering, dismiss behavior, ordering, and CTA behavior.

View file

@ -0,0 +1,76 @@
# Tools
## Source Anchors
- Tool base class: `/a0/helpers/tool.py`
- Core tool contract: `/a0/tools/AGENTS.md`
- Tool dispatch path: `/a0/agent.py`
- Skills tool reference-file behavior: `/a0/tools/skills_tool.py`
- Example profile tool: `/a0/agents/_example/tools/example_tool.py`
- Prompt fragments: `/a0/prompts/AGENTS.md`
## Contract
All tools derive from `helpers.tool.Tool` and implement:
```python
from helpers.tool import Tool, Response
class MyTool(Tool):
async def execute(self, **kwargs) -> Response:
return Response(message="done", break_loop=False)
```
`Response` fields:
| Field | Meaning |
|---|---|
| `message` | Text appended as the tool result and shown back to the agent. |
| `break_loop` | `True` stops the current message loop. |
| `additional` | Optional metadata added with the tool result. |
`Tool` instances receive `agent`, `name`, `method`, `args`, `message`, and `loop_data`. Use `self.method` for method-style tools such as `skills_tool:load`.
## Locations
| Location | Use |
|---|---|
| `tools/` | Core framework tools. Use only for bundled framework behavior. |
| `plugins/<plugin>/tools/` | Bundled plugin tools. |
| `usr/plugins/<plugin>/tools/` | User plugin tools. This is the preferred place for custom plugin work. |
| `agents/<profile>/tools/` | Profile-local tools. Verify current discovery before relying on profile examples. |
Most new tools should be packaged in a plugin, not added directly to root `tools/`.
## Prompt Contract
Every tool needs an agent-facing prompt fragment so the model knows the tool name, JSON shape, arguments, and when to use it.
Common locations:
- Core tool prompt: `prompts/agent.system.tool.<tool_name>.md`
- Plugin tool prompt: `plugins/<plugin>/prompts/agent.system.tool.<tool_name>.md`
- User plugin prompt: `usr/plugins/<plugin>/prompts/agent.system.tool.<tool_name>.md`
- Profile override prompt: `agents/<profile>/prompts/agent.system.tool.<tool_name>.md`
When changing a tool name, argument shape, output behavior, safety rule, or `break_loop` behavior, update its prompt and tests together.
## Progress And Interventions
- Use `await self.set_progress(...)` when progress should be visible through the tool-output update extension.
- `self.add_progress(...)` only accumulates local progress text.
- For long-running or external-result workflows, follow `tools/AGENTS.md` and use `await self.agent.handle_intervention(...)` where pause/intervention flow matters.
- Sanitize and mask secrets before logging or returning outputs.
## Core Tool DOX
Direct files under `tools/*.py` require matching `tools/*.py.dox.md`. The companion file owns purpose, arguments, output, `break_loop`, side effects, prompt contract notes, dependencies, and verification.
Plugin tool documentation belongs in that plugin's docs or DOX contract, not in root `tools/`.
## Verification
- Run targeted tests for changed tools.
- Run prompt/snapshot tests when tool instructions or output shape changes.
- For direct root tools, verify every `tools/*.py` has a matching `.py.dox.md`.
- If the tool is plugin-scoped, also run plugin-specific checks from the plugin's `AGENTS.md`.