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