chore: add updated a0-development skill

Nicolas Leão committed Mar 25, 2026 at 13:06 UTC 085c3b8d513b4db43f728fd86147e5a10ad46485
1 file changed +844
skills/a0-development/SKILL.md new
+844
@@ -0,0 +1,844 @@
1 +---
2 +name: a0-development
3 +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.
4 +version: 1.0.0
5 +author: Agent Zero Team
6 +tags: ["development", "framework", "agent-zero", "extending", "tools", "extensions", "skills", "api", "agents", "prompts"]
7 +trigger_patterns:
8 + - "extend agent zero"
9 + - "agent zero development"
10 + - "build agent zero feature"
11 + - "create agent zero tool"
12 + - "add extension"
13 + - "framework development"
14 + - "agent zero architecture"
15 + - "how does agent zero work"
16 + - "create agent zero extension"
17 + - "add api endpoint"
18 + - "create agent profile"
19 + - "agent zero internals"
20 + - "how does the agent loop work"
21 + - "extension hook points"
22 + - "prompt system"
23 + - "agent profile"
24 +---
25 +
26 +# Agent Zero Development Guide
27 +
28 +This skill provides comprehensive, accurate guidance for extending and building features for Agent Zero. Use it when you need to:
29 +
30 +- Understand the **architecture** and project layout
31 +- Create new **Tools** for agent capabilities
32 +- Add **Extensions** to hook into the framework lifecycle
33 +- Build **API Endpoints** for the Web UI
34 +- Create **Agent Profiles** (subordinates) with custom prompts
35 +- Understand and extend the **Prompt System**
36 +- Create **Skills** (see the dedicated `create-skill` skill for the full wizard)
37 +- Work with **Projects** and workspace configuration
38 +
39 +> **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.
40 +
41 +> [!IMPORTANT]
42 +> **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.
43 +
44 +Related skills: `a0-plugin-router` (plugin tasks) | `create-skill` (skill creation wizard) | `a0-create-plugin` | `a0-review-plugin` | `a0-manage-plugin` | `a0-contribute-plugin` | `a0-debug-plugin`
45 +
46 +---
47 +
48 +## Architecture Overview
49 +
50 +### Project Layout
51 +
52 +```
53 +/a0/ # Framework root
54 +├── agent.py # Core Agent + AgentContext + AgentConfig classes
55 +├── initialize.py # Agent initialization logic
56 +├── models.py # Model definitions
57 +├── run_ui.py # Web UI entry point
58 +│
59 +├── tools/ # Core tools (search, response, browser, etc.)
60 +├── extensions/
61 +│ ├── python/ # Python lifecycle extensions
62 +│ │ ├── <hook_point>/ # e.g., agent_init/, system_prompt/, etc.
63 +│ │ │ └── _NN_name.py # Numbered extension files
64 +│ │ └── _functions/ # Implicit @extensible decorator extensions
65 +│ └── webui/ # JavaScript WebUI extensions
66 +│ └── <hook_point>/ # e.g., json_api_call_before/
67 +│ └── name.js
68 +├── api/ # Flask API endpoint handlers
69 +├── helpers/ # Framework utilities and base classes
70 +│ ├── tool.py # Tool + Response base classes
71 +│ ├── extension.py # Extension base class + @extensible decorator
72 +│ ├── api.py # ApiHandler base class
73 +│ ├── files.py # File operations + prompt reading
74 +│ ├── plugins.py # Plugin system manager
75 +│ ├── print_style.py # Console output formatting
76 +│ └── ... # Many more utility modules
77 +│
78 +├── prompts/ # Core prompt fragments (system, tools, framework)
79 +├── agents/ # Agent profiles (subordinate specializations)
80 +│ ├── default/ # Base profile (inherited by others)
81 +│ ├── agent0/ # Main user-facing agent
82 +│ ├── developer/ # Developer subordinate
83 +│ ├── hacker/ # Security subordinate
84 +│ ├── researcher/ # Research subordinate
85 +│ └── _example/ # Example profile with tool + extension samples
86 +│
87 +├── plugins/ # Core plugins (tools, extensions, prompts)
88 +│ ├── _code_execution/ # Terminal/Python/Node.js execution
89 +│ ├── _memory/ # Persistent memory system
90 +│ ├── _text_editor/ # File read/write/patch
91 +│ ├── _model_config/ # LLM model selection
92 +│ ├── _infection_check/ # Prompt injection safety
93 +│ └── ... # More core plugins
94 +│
95 +├── skills/ # Core skills (SKILL.md bundles)
96 +├── knowledge/ # Knowledge base files
97 +├── webui/ # Web UI frontend
98 +├── docs/ # Documentation
99 +│
100 +└── usr/ # User-space (survives updates)
101 + ├── agents/ # User-created agent profiles
102 + ├── plugins/ # User-installed plugins
103 + ├── skills/ # User-created skills
104 + ├── knowledge/ # User knowledge base files
105 + ├── extensions/ # Standalone user extensions (created on demand; prefer plugins instead)
106 + ├── projects/ # Project workspaces (created on demand when user adds projects via UI)
107 + └── workdir/ # Default working directory
108 +```
109 +
110 +### Key Architecture Patterns
111 +
112 +1. **Plugin-first design** — Most capabilities (tools, extensions, prompts) are delivered via plugins in `/a0/plugins/` (core) or `/a0/usr/plugins/` (user).
113 +2. **Extensions execute in numeric order** — Files named `_10_*.py`, `_20_*.py`, etc. run sequentially within each hook point.
114 +3. **Tools inherit from `Tool`** — All tools implement the `execute()` method returning a `Response`.
115 +4. **Shared `AgentContext`** — Enables state persistence across agents in a conversation.
116 +5. **Async/await throughout** — All tool execution, extensions, and API handlers are async.
117 +6. **Prompt fragments compose** — System prompts are assembled from named fragments with includes and variable substitution.
118 +7. **Profile inheritance** — Agent profiles inherit from `default/` and override specific prompt fragments.
119 +8. **User-space separation** — Everything under `/a0/usr/` survives framework updates.
120 +
121 +### Agent Loop
122 +
123 +The core execution cycle works as follows:
124 +
125 +1. **User message** arrives (via UI or API)
126 +2. **System prompt assembly** — prompt fragments are composed with includes and variable substitution
127 +3. **LLM call** — the assembled prompt + conversation history is sent to the model
128 +4. **Response parsing** — the framework parses the LLM response looking for JSON tool calls
129 +5. **Tool execution** — if tool calls are found, each tool's `execute()` method is called and the result is appended to history
130 +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
131 +
132 +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.
133 +
134 +---
135 +
136 +## Creating Tools
137 +
138 +Tools are how agents interact with the world. Each tool inherits from the `Tool` base class.
139 +
140 +### Import Path
141 +
142 +```python
143 +from helpers.tool import Tool, Response
144 +```
145 +
146 +### Tool Base Class
147 +
148 +```python
149 +# /a0/helpers/tool.py
150 +
151 +@dataclass
152 +class Response:
153 + message: str # Text response shown to agent
154 + break_loop: bool # True = stop agent message loop
155 + additional: dict[str, Any] | None = None # Extra metadata for history
156 +
157 +class Tool:
158 + def __init__(self, agent: Agent, name: str, method: str | None,
159 + args: dict[str,str], message: str,
160 + loop_data: LoopData | None, **kwargs) -> None:
161 + self.agent = agent
162 + self.name = name
163 + self.method = method # For tools with sub-methods (e.g., "skills_tool:load")
164 + self.args = args
165 + self.loop_data = loop_data
166 + self.message = message
167 +
168 + async def execute(self, **kwargs) -> Response:
169 + pass # Override this
170 +
171 + # Lifecycle hooks (called automatically):
172 + async def before_execution(self, **kwargs): ...
173 + async def after_execution(self, response: Response, **kwargs): ...
174 +```
175 +
176 +### Where Tools Live
177 +
178 +| Location | Purpose |
179 +|---|---|
180 +| `/a0/tools/` | Core framework tools (search, response, call_subordinate, etc.) |
181 +| `/a0/plugins/<plugin>/tools/` | Plugin-provided tools (code_execution, memory, text_editor) |
182 +| `/a0/agents/<profile>/tools/` | Profile-specific tool overrides |
183 +| `/a0/usr/plugins/<plugin>/tools/` | User plugin tools |
184 +
185 +### Example: Creating a Tool
186 +
187 +Based on the actual `_example` profile in `/a0/agents/_example/tools/example_tool.py`:
188 +
189 +```python
190 +# my_tool.py
191 +from helpers.tool import Tool, Response
192 +
193 +class MyTool(Tool):
194 + async def execute(self, **kwargs):
195 + # Get arguments — kwargs contains the tool_args from the agent's JSON
196 + input_data = kwargs.get("input", "")
197 +
198 + # Do something
199 + result = f"Processed: {input_data}"
200 +
201 + # Return response
202 + return Response(
203 + message=result, # Shown to the agent
204 + break_loop=False, # Don't stop the agent loop
205 + )
206 +```
207 +
208 +> [!IMPORTANT]
209 +> 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.
210 +
211 +### Tool Best Practices
212 +
213 +- Always handle errors gracefully — return error messages in `Response`, don't crash
214 +- Access agent context via `self.agent.context`
215 +- Use `self.method` to support sub-methods (e.g., `my_tool:action1`, `my_tool:action2`)
216 +- Use `kwargs.get()` to read arguments with defaults
217 +- For long operations, use `self.set_progress()` or `self.add_progress()` to show status
218 +- Access `self.loop_data` for loop state (iteration count, timing, etc.) — this is the `LoopData` instance passed during tool dispatch
219 +
220 +---
221 +
222 +## Creating Extensions
223 +
224 +Extensions hook into specific lifecycle points in the agent framework.
225 +
226 +### Import Path
227 +
228 +```python
229 +from helpers.extension import Extension
230 +```
231 +
232 +### Extension Base Class
233 +
234 +```python
235 +class Extension:
236 + def __init__(self, agent: "Agent | None", **kwargs):
237 + self.agent: "Agent | None" = agent
238 + self.kwargs = kwargs
239 +
240 + def execute(self, **kwargs) -> None | Awaitable[None]:
241 + pass # Override this — kwargs are hook-point-specific
242 +```
243 +
244 +> 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.
245 +
246 +### Extension File Location
247 +
248 +Extensions live in directories named by their hook point. The path structure is:
249 +
250 +```
251 +extensions/python/<hook_point>/_NN_name.py
252 +```
253 +
254 +Where `_NN_` is a numeric prefix controlling execution order (e.g., `_10_`, `_20_`, `_50_`).
255 +
256 +| Source | Path |
257 +|---|---|
258 +| Core extensions | `/a0/extensions/python/<hook_point>/` |
259 +| Plugin extensions | `/a0/plugins/<plugin>/extensions/python/<hook_point>/` |
260 +| User extensions | `/a0/usr/extensions/python/<hook_point>/` |
261 +| Agent profile extensions | `/a0/agents/<profile>/extensions/<hook_point>/` |
262 +| User plugin extensions | `/a0/usr/plugins/<plugin>/extensions/python/<hook_point>/` |
263 +
264 +### Python Extension Hook Points
265 +
266 +Complete list of available hook points:
267 +
268 +| Hook Point | When It Fires | Common Use |
269 +|---|---|---|
270 +| `agent_init` | Agent is initialized | Load configs, set defaults |
271 +| `system_prompt` | System prompt is being assembled | Inject prompt content |
272 +| `monologue_start` | Agent monologue begins | Pre-processing, state setup |
273 +| `message_loop_start` | Before message processing loop | Pre-loop setup |
274 +| `message_loop_prompts_before` | Before prompt assembly in loop | Modify prompt inputs |
275 +| `message_loop_prompts_after` | After prompt assembly in loop | Add context (memory recall lives here) |
276 +| `before_main_llm_call` | Before the LLM API call | Modify prompts, add context |
277 +| `util_model_call_before` | Before utility model calls | Modify utility prompts |
278 +| `response_stream` | When response streaming begins | Initialize stream handlers |
279 +| `response_stream_chunk` | Per response chunk received | Transform output, collect data |
280 +| `response_stream_end` | Response streaming complete | Finalize, analyze full response |
281 +| `reasoning_stream` | Reasoning/thinking stream begins | Monitor reasoning |
282 +| `reasoning_stream_chunk` | Per reasoning chunk | Collect reasoning data |
283 +| `reasoning_stream_end` | Reasoning stream complete | Analyze reasoning |
284 +| `tool_execute_before` | Before a tool runs | Validation, logging, safety checks |
285 +| `tool_execute_after` | After a tool runs | Post-process results |
286 +| `hist_add_before` | Before adding to history | Modify history entries |
287 +| `hist_add_tool_result` | After tool result added to history | Log tool results |
288 +| `message_loop_end` | After message processing loop | Post-loop cleanup |
289 +| `monologue_end` | Agent monologue complete | Memorization, cleanup |
290 +| `process_chain_end` | Entire processing chain done | Final cleanup |
291 +| `job_loop` | Background job loop tick | Periodic background tasks |
292 +| `error_format` | Error is being formatted | Custom error messages |
293 +| `startup_migration` | Framework startup | Data migrations |
294 +| `banners` | Startup banners displayed | Add custom banners |
295 +| `embedding_model_changed` | Embedding model changed | Reload vector stores (fired programmatically, not a directory-based hook) |
296 +| `user_message_ui` | User message from UI | Pre-process user input |
297 +| `webui_ws_connect` | WebSocket client connects | Session setup |
298 +| `webui_ws_disconnect` | WebSocket client disconnects | Session cleanup |
299 +| `webui_ws_event` | WebSocket event received | Handle custom WS events |
300 +
301 +### The `@extensible` Decorator (Implicit Extension Points)
302 +
303 +Any framework function decorated with `@extensible` automatically gets two extension points:
304 +
305 +```
306 +_functions/<module_path>/<qualname_path>/start
307 +_functions/<module_path>/<qualname_path>/end
308 +```
309 +
310 +The path mapping converts Python module paths and qualified names using `/` separators:
311 +- Module `agent.py` → `agent`
312 +- Class method `Agent.handle_exception` → `Agent/handle_exception`
313 +- Full path: `_functions/agent/Agent/handle_exception/start`
314 +
315 +For nested modules like `helpers.history`, a method `History.add` would map to `_functions/helpers/history/History/add/start`.
316 +
317 +For example, a function `Agent.handle_exception` in module `agent` creates:
318 +- `_functions/agent/Agent/handle_exception/start`
319 +- `_functions/agent/Agent/handle_exception/end`
320 +
321 +Extensions in these directories receive a `data` dict with:
322 +- `data["args"]` — positional args (mutable)
323 +- `data["kwargs"]` — keyword args (mutable)
324 +- `data["result"]` — set this to short-circuit the function
325 +- `data["exception"]` — set to a `BaseException` to force-raise
326 +
327 +This is used by plugins like `_error_retry` to wrap core agent methods.
328 +
329 +### WebUI Extensions (JavaScript)
330 +
331 +Client-side extensions live under `extensions/webui/<hook_point>/`:
332 +
333 +| Hook Point | When It Fires |
334 +|---|---|
335 +| `json_api_call_before` | Before a JSON API request |
336 +| `json_api_call_after` | After a JSON API response |
337 +| `fetch_api_call_before` | Before a fetch API request |
338 +| `fetch_api_call_after` | After a fetch API response |
339 +| `get_message_handler` | Register custom message renderers |
340 +| `set_messages_before_loop` | Before messages are rendered |
341 +| `set_messages_after_loop` | After messages are rendered |
342 +| `webui_ws_push` | WebSocket push to client |
343 +
344 +### Example: Creating an Extension
345 +
346 +Based on the actual `_example` profile in `/a0/agents/_example/extensions/agent_init/_10_example_extension.py`:
347 +
348 +```python
349 +# extensions/python/agent_init/_15_my_extension.py
350 +from helpers.extension import Extension
351 +
352 +class MyExtension(Extension):
353 + async def execute(self, **kwargs):
354 + # Access the agent
355 + agent = self.agent
356 + context = agent.context
357 +
358 + # Extension logic — kwargs content depends on the hook point
359 + agent.agent_name = "CustomAgent" + str(agent.number)
360 +```
361 +
362 +### Extension Execution Order
363 +
364 +Extensions execute in numeric order based on filename prefix:
365 +
366 +```
367 +_10_first.py # Runs first
368 +_20_second.py # Runs second
369 +_50_third.py # Runs third
370 +```
371 +
372 +Use 10-number increments to leave room for future extensions.
373 +
374 +---
375 +
376 +## Creating API Endpoints
377 +
378 +API endpoints serve the Web UI and external clients using Flask.
379 +
380 +### Import Path
381 +
382 +```python
383 +from helpers.api import ApiHandler
384 +from flask import Request, Response
385 +```
386 +
387 +### ApiHandler Base Class
388 +
389 +```python
390 +class ApiHandler:
391 + def __init__(self, app: Flask, thread_lock: ThreadLockType):
392 + self.app = app
393 + self.thread_lock = thread_lock
394 +
395 + # Override these class methods to configure behavior:
396 + @classmethod
397 + def requires_loopback(cls) -> bool: return False # Restrict to localhost
398 + @classmethod
399 + def requires_api_key(cls) -> bool: return False # Require API key
400 + @classmethod
401 + def requires_auth(cls) -> bool: return True # Require auth session
402 + @classmethod
403 + def get_methods(cls) -> list[str]: return ["POST"] # HTTP methods
404 + @classmethod
405 + def requires_csrf(cls) -> bool: return cls.requires_auth() # CSRF protection
406 +
407 + # Implement this:
408 + async def process(self, input: dict, request: Request) -> dict | Response:
409 + pass
410 +
411 + # Utility: get or create an agent context
412 + def use_context(self, ctxid: str, create_if_not_exists: bool = True) -> AgentContext:
413 + ...
414 +```
415 +
416 +### Where API Endpoints Live
417 +
418 +| Location | Purpose |
419 +|---|---|
420 +| `/a0/api/` | Core API endpoints |
421 +| `/a0/plugins/<plugin>/api/` | Plugin API endpoints |
422 +| `/a0/usr/plugins/<plugin>/api/` | User plugin API endpoints |
423 +
424 +Endpoints are auto-discovered by filename. The route is derived from the filename (e.g., `my_endpoint.py` -> `/api/my_endpoint`).
425 +
426 +### Example: API Endpoint
427 +
428 +```python
429 +# api/my_endpoint.py
430 +from helpers.api import ApiHandler
431 +from flask import Request, Response
432 +from agent import AgentContext
433 +
434 +class MyEndpoint(ApiHandler):
435 + @classmethod
436 + def get_methods(cls) -> list[str]:
437 + return ["GET", "POST"]
438 +
439 + async def process(self, input: dict, request: Request) -> dict:
440 + param = input.get("param", "default")
441 +
442 + # Get or create agent context
443 + ctxid = input.get("context", "")
444 + context = self.use_context(ctxid)
445 +
446 + return {
447 + "result": f"processed {param}",
448 + "context": context.id,
449 + }
450 +```
451 +
452 +---
453 +
454 +## Creating Agent Profiles
455 +
456 +Agent profiles define specialized subordinates with custom prompts and behaviors.
457 +
458 +### Profile Directory Structure
459 +
460 +```
461 +agents/<profile-name>/
462 ++-- agent.yaml # Required: profile metadata
463 ++-- prompts/ # Optional: prompt overrides
464 +| +-- agent.system.main.role.md # Role definition (most common override)
465 +| +-- agent.system.main.communication.md # Communication style
466 +| +-- agent.system.tool.<name>.md # Tool-specific prompts
467 ++-- tools/ # Optional: profile-specific tools
468 +| +-- my_tool.py
469 ++-- extensions/ # Optional: profile-specific extensions
470 + +-- <hook_point>/
471 + +-- _NN_extension.py
472 +```
473 +
474 +### agent.yaml Format
475 +
476 +The actual format is simple YAML with only three fields:
477 +
478 +```yaml
479 +title: Developer
480 +description: Agent specialized in complex software development.
481 +context: Use this agent for software development tasks, including writing code,
482 + debugging, refactoring, and architectural design.
483 +```
484 +
485 +| Field | Purpose |
486 +|---|---|
487 +| `title` | Display name shown in UI and agent selection |
488 +| `description` | Brief description of the agent's specialization |
489 +| `context` | Instructions for when to delegate to this profile |
490 +
491 +> [!NOTE]
492 +> There is **no** per-profile model configuration, temperature, or allowed_tools in the profile YAML. Model configuration is managed by the `_model_config` plugin. Tool availability is controlled by plugin activation.
493 +
494 +### Where Profiles Live
495 +
496 +| Location | Purpose |
497 +|---|---|
498 +| `/a0/agents/` | Core profiles (default, agent0, developer, hacker, researcher) |
499 +| `/a0/usr/agents/` | User-created profiles (survives updates) |
500 +
501 +### Prompt Override Mechanism
502 +
503 +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.
504 +
505 +The most common override is `agent.system.main.role.md` which defines the agent's role and specialization.
506 +
507 +### Example: Creating a Profile
508 +
509 +```yaml
510 +# /a0/usr/agents/data-analyst/agent.yaml
511 +title: Data Analyst
512 +description: Agent specialized in data analysis, visualization, and statistical modeling.
513 +context: Use this agent for data analysis tasks, creating visualizations, statistical
514 + analysis, and working with datasets in Python.
515 +```
516 +
517 +```markdown
518 +<!-- /a0/usr/agents/data-analyst/prompts/agent.system.main.role.md -->
519 +
520 +## Your role
521 +You are a specialized data analysis agent.
522 +Your expertise includes:
523 +- Python data analysis (pandas, numpy, scipy)
524 +- Data visualization (matplotlib, seaborn, plotly)
525 +- Statistical modeling and hypothesis testing
526 +- SQL queries and database analysis
527 +- Data cleaning and preprocessing
528 +
529 +## Process
530 +1. Understand the data and the question
531 +2. Choose appropriate tools and methods
532 +3. Execute analysis with code_execution_tool
533 +4. Visualize results when applicable
534 +5. Provide clear interpretation of findings
535 +```
536 +
537 +### Reference: The `_example` Profile
538 +
539 +The framework includes a complete example profile at `/a0/agents/_example/` that demonstrates:
540 +- Custom tool: `/a0/agents/_example/tools/example_tool.py`
541 +- Custom extension: `/a0/agents/_example/extensions/agent_init/_10_example_extension.py`
542 +- Tool prompt: `/a0/agents/_example/prompts/agent.system.tool.example_tool.md`
543 +- Role prompt: `/a0/agents/_example/prompts/agent.system.main.role.md`
544 +
545 +---
546 +
547 +## Prompt System
548 +
549 +Agent Zero assembles system prompts from **named fragments** using includes and variable substitution.
550 +
551 +### Prompt File Naming Convention
552 +
553 +Prompt files follow a dot-separated naming scheme:
554 +
555 +```
556 +agent.system.main.md # Main system prompt (entry point)
557 +agent.system.main.role.md # Role definition
558 +agent.system.main.communication.md # Communication style
559 +agent.system.tool.<name>.md # Tool usage instructions
560 +agent.system.tools.md # Tools overview
561 +agent.system.projects.main.md # Project system
562 +agent.system.secrets.md # Secret handling
563 +agent.system.skills.md # Skills listing
564 +agent.system.datetime.md # Current date/time
565 +agent.context.extras.md # Context extras
566 +fw.*.md # Framework messages (errors, hints, etc.)
567 +```
568 +
569 +### Where Prompts Live
570 +
571 +| Location | Priority | Purpose |
572 +|---|---|---|
573 +| `/a0/agents/<profile>/prompts/` | Highest | Profile-specific overrides |
574 +| `/a0/usr/agents/<profile>/prompts/` | High | User profile overrides |
575 +| `/a0/plugins/<plugin>/prompts/` | Normal | Plugin-provided prompts |
576 +| `/a0/usr/plugins/<plugin>/prompts/` | Normal | User plugin prompts |
577 +| `/a0/prompts/` | Base | Core framework prompts |
578 +
579 +The framework searches directories in priority order and uses the **first match** found.
580 +
581 +### Include Mechanism
582 +
583 +Prompts can include other fragments using double-brace `include` directives.
584 +
585 +The syntax uses opening double-brace, the keyword, and closing double-brace:
586 +
587 +| Directive | Purpose |
588 +|---|---|
589 +| `{{include "agent.system.main.role.md"}}` | Include a named prompt fragment |
590 +| `{{include "agent.system.main.communication.md"}}` | Include another fragment |
591 +| `{{include original}}` | Include the same file from the next lower-priority directory |
592 +
593 +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.
594 +
595 +### Variable Substitution
596 +
597 +Prompts support `{{variable_name}}` placeholders that are replaced at render time with values passed from the framework or plugin configuration.
598 +
599 +### Conditional Blocks
600 +
601 +Prompts support conditional rendering based on variables.
602 +
603 +### Reading Prompts in Code
604 +
605 +```python
606 +# From within an Agent method:
607 +content = self.read_prompt("fw.some_message.md", variable1="value1")
608 +
609 +# From helpers:
610 +from helpers.files import read_prompt_file
611 +content = read_prompt_file("template.md", _directories=[...], var="value")
612 +```
613 +
614 +---
615 +
616 +## Creating Skills
617 +
618 +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.
619 +
620 +| Location | Purpose |
621 +|---|---|
622 +| `/a0/skills/` | Core skills (shipped with framework) |
623 +| `/a0/usr/skills/` | User-created skills (survives updates) |
624 +
625 +The agent interacts with skills through JSON tool calls:
626 +
627 +```json
628 +{"tool_name": "skills_tool:list", "tool_args": {}}
629 +{"tool_name": "skills_tool:load", "tool_args": {"skill_name": "my-skill"}}
630 +```
631 +
632 +> For the complete skill creation wizard — including SKILL.md format, frontmatter fields, directory structure, best practices, and examples — load the `create-skill` skill.
633 +
634 +---
635 +
636 +## Working with Projects
637 +
638 +Projects provide isolated workspaces with custom configuration.
639 +
640 +> 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.
641 +
642 +### Project Structure
643 +
644 +```
645 +/a0/usr/projects/<project-name>/
646 ++-- .a0proj/
647 +| +-- project.json # Project configuration
648 +| +-- agents.json # Per-project agent overrides
649 +| +-- variables.env # Non-sensitive variables
650 +| +-- secrets.env # Encrypted secrets
651 +| +-- memory/ # Project-specific memory
652 +| +-- index.faiss
653 +| +-- index.pkl
654 +| +-- embedding.json
655 ++-- <project-files>/ # Your project files (working directory)
656 +```
657 +
658 +### project.json Format
659 +
660 +```json
661 +{
662 + "title": "My Project",
663 + "description": "Project description",
664 + "instructions": "Markdown instructions for the agent when this project is active",
665 + "color": "#3a86ff",
666 + "git_url": "",
667 + "memory": "own",
668 + "file_structure": {
669 + "enabled": true,
670 + "max_depth": 5,
671 + "max_files": 20,
672 + "max_folders": 20,
673 + "max_lines": 250,
674 + "gitignore": ".a0proj/\nvenv/\n**/__pycache__/\n**/node_modules/\n**/.git/\n"
675 + }
676 +}
677 +```
678 +
679 +| Field | Purpose |
680 +|---|---|
681 +| `title` | Display name |
682 +| `description` | Brief description |
683 +| `instructions` | Markdown injected into agent system prompt when project is active |
684 +| `color` | UI accent color (hex) |
685 +| `git_url` | Optional Git repository URL |
686 +| `memory` | `"own"` for project-specific memory, or shared |
687 +| `file_structure` | Controls the working directory tree shown to the agent |
688 +
689 +---
690 +
691 +## Plugin System Overview
692 +
693 +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.
694 +
695 +> For all plugin tasks — creating, reviewing, managing, contributing, or debugging plugins — load the `a0-plugin-router` skill, which routes to the appropriate specialist skill.
696 +
697 +### Core Plugins
698 +
699 +The framework ships with these core plugins in `/a0/plugins/`:
700 +
701 +| Plugin | Purpose |
702 +|---|---|
703 +| `_code_execution` | Terminal, Python, Node.js code execution |
704 +| `_memory` | Persistent vector memory system |
705 +| `_text_editor` | File read/write/patch with line numbers |
706 +| `_model_config` | LLM model selection and configuration |
707 +| `_browser_agent` | Browser automation and web interaction |
708 +| `_infection_check` | Prompt injection safety checks |
709 +| `_error_retry` | Retry on critical exceptions |
710 +| `_email_integration` | Email communication via IMAP/SMTP |
711 +| `_telegram_integration` | Telegram bot integration |
712 +| `_chat_branching` | Branch chats from any message |
713 +| `_promptinclude` | Persistent behavioral rules (*.promptinclude.md) |
714 +| `_plugin_installer` | Install plugins from ZIP/Git/Hub |
715 +| `_plugin_scan` | Security scanning for plugins |
716 +| `_plugin_validator` | Plugin manifest and code validation |
717 +
718 +---
719 +
720 +## Common Patterns Reference
721 +
722 +### Accessing Agent Context
723 +
724 +```python
725 +# Shared across all agents in a conversation
726 +context = self.agent.context
727 +data = context.data # dict-like shared state
728 +
729 +# Store data
730 +data["my_key"] = my_value
731 +
732 +# Retrieve data
733 +value = data.get("my_key", default)
734 +```
735 +
736 +### Using File Helpers
737 +
738 +```python
739 +from helpers import files
740 +
741 +# File operations
742 +content = files.read_file("path/to/file")
743 +files.write_file("path/to/file", content)
744 +exists = files.exists("path/to/file")
745 +
746 +# Read and render a prompt file
747 +content = files.read_prompt_file("template.md", _directories=[...], var="value")
748 +```
749 +
750 +### Console Output
751 +
752 +```python
753 +from helpers.print_style import PrintStyle
754 +
755 +PrintStyle.hint("Informational message")
756 +PrintStyle.warning("Warning message")
757 +PrintStyle.error("Error message")
758 +PrintStyle(font_color="#85C1E9").print("Custom styled output")
759 +```
760 +
761 +### Error Handling
762 +
763 +```python
764 +from helpers.tool import Response
765 +
766 +try:
767 + result = await risky_operation()
768 +except Exception as e:
769 + PrintStyle.error(f"Operation failed: {e}")
770 + return Response(message=f"Error: {e}", break_loop=False)
771 +```
772 +
773 +---
774 +
775 +## Development Workflow
776 +
777 +When building features for Agent Zero:
778 +
779 +### 1. Choose Your Extension Point
780 +
781 +| Want to... | Use |
782 +|---|---|
783 +| Add a new agent capability | **Tool** (in a plugin) |
784 +| Hook into agent lifecycle | **Extension** (in a plugin) |
785 +| Add Web UI functionality | **API endpoint** + **WebUI extension** |
786 +| Create a specialized agent | **Agent profile** |
787 +| Bundle reusable instructions | **Skill** |
788 +| Package everything together | **Plugin** (recommended) |
789 +
790 +### 2. Develop in User Space
791 +
792 +- New plugins -> `/a0/usr/plugins/<name>/`
793 +- New profiles -> `/a0/usr/agents/<name>/`
794 +- New skills -> `/a0/usr/skills/<name>/`
795 +- New extensions -> `/a0/usr/extensions/python/<hook_point>/`
796 +
797 +### 3. Test and Iterate
798 +
799 +- **Local dev**: Run `python run_ui.py` (default port 50001 at `http://localhost:50001`)
800 +- **Docker**: Restart the container or use the UI restart button; check logs with `docker logs -f <container_name>`
801 +- Test with minimal input first
802 +- Verify in the Web UI
803 +
804 +### 4. Contributing
805 +
806 +For contribution guidelines, see `/a0/docs/contribution.md`. For plugin contributions to the community Plugin Index, load the `a0-contribute-plugin` skill.
807 +
808 +---
809 +
810 +## Best Practices
811 +
812 +### DO
813 +- Use the **plugin system** for new features (see `a0-create-plugin` skill)
814 +- Follow existing code patterns and conventions
815 +- Write clear docstrings and comments
816 +- Handle errors gracefully in tools and extensions
817 +- Create prompt fragments for every tool (`agent.system.tool.<name>.md`)
818 +- Develop in `/a0/usr/` directories to survive updates
819 +- Test with the `_example` profile as a reference
820 +- Use `from helpers.*` imports (not `from python.helpers.*`)
821 +
822 +### DON'T
823 +- Modify files in `/a0/plugins/` or `/a0/tools/` directly (use usr/ space)
824 +- Hardcode paths or configuration values
825 +- Skip creating prompt files for tools
826 +- Ignore the plugin system (it's the intended extension mechanism)
827 +- Mix sync and async code carelessly
828 +- Access internal structures when helpers exist
829 +
830 +---
831 +
832 +## Quick Reference: Key Files
833 +
834 +| File | Purpose |
835 +|---|---|
836 +| `/a0/agent.py` | Core `Agent`, `AgentContext`, `AgentConfig` classes |
837 +| `/a0/helpers/tool.py` | `Tool` + `Response` base classes |
838 +| `/a0/helpers/extension.py` | `Extension` base + `@extensible` decorator |
839 +| `/a0/helpers/api.py` | `ApiHandler` base class |
840 +| `/a0/helpers/files.py` | File ops + prompt reading |
841 +| `/a0/helpers/plugins.py` | Plugin system manager |
842 +| `/a0/helpers/print_style.py` | Console output formatting |
843 +| `/a0/agents/_example/` | Reference example profile with tool + extension |
844 +| `/a0/prompts/agent.system.main.md` | Main system prompt entry point |
\ No newline at end of file