skills/a0-create-agent/SKILL.md
[!IMPORTANT] Do not create new profiles in
/a0/agents/— that directory is reserved for core framework profiles (default,agent0,developer,hacker,researcher,_example). User profiles belong in/a0/usr/agents/<profile_name>/.
Related skills: /a0/skills/a0-development/SKILL.md (broader framework guide) | /a0/skills/a0-create-plugin/SKILL.md (bundle a profile inside a plugin).
Primary references:
/a0/agents/_example/ — the canonical reference profile (tool + extension + prompt overrides)/a0/agents/default/ — the base profile every other profile inherits from/a0/docs/agents/AGENTS.plugins.md — plugin-distributed profiles + per-profile configThe built-in profiles are intentionally split into two layers:
agent.yaml is tiny metadata for discovery and delegation:
titledescriptioncontextprompts/agent.system.main.specifics.md.Use the shipped profiles as calibration:
| Profile | Pattern to copy |
|---|---|
agent0 | Minimal top-level assistant identity |
developer | Rich capabilities, methodology, output requirements |
researcher | Rich capabilities, methodology, evidence standards |
hacker | Short, direct operational identity plus optional environment override |
_example | Minimal demo of prompt/tool/extension override surfaces |
For most new profiles, create agent.yaml plus one strong agent.system.main.specifics.md. Add other prompt overrides, tools, or extensions only when the blueprint explicitly needs them.
Do not ask the user a long form. New users are easily overwhelmed. Guide them with lossy compression: ask only the next highest-value question, one or two questions per turn maximum.
Default assumptions unless the user says otherwise:
/a0/usr/agents/<name>._model_config.agent.yaml plus prompts/agent.system.main.specifics.md.Recommended interview flow:
name, title, description, and context, then ask for confirmation or corrections.Never open with all blueprint fields. Do not mention obscure paths until they matter. Hide defaults, but use them.
If the user gives a broad idea, infer sensible defaults and mark uncertainties in validation.open_questions instead of stalling.
Before writing files, produce exactly one valid JSON object in a fenced json block using this schema. This blueprint is the source of truth. Do not require a utility model or prose post-processing to extract fields.
{
"schema": "agent_zero.agent_profile_blueprint.v1",
"status": "draft",
"profile": {
"scope": "user",
"root": "/a0/usr/agents",
"name": "data-analyst",
"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."
},
"behavior": {
"role": "You are a specialized data analysis agent.",
"primary_capabilities": [
"Python data analysis with pandas, numpy, and scipy",
"Data visualization with matplotlib, seaborn, and plotly",
"Statistical modeling and hypothesis testing"
],
"operating_principles": [
"Inspect data before drawing conclusions",
"Prefer reproducible code and explicit assumptions",
"Explain uncertainty and limitations"
],
"workflow": [
"Clarify the question and available data",
"Profile and clean the dataset",
"Run analysis with appropriate methods",
"Visualize and interpret results"
],
"output_preferences": [
"Concise findings first",
"Tables or charts when useful",
"Reproducible code when analysis is performed"
]
},
"prompt_strategy": {
"base_pattern": "specifics_only",
"override_rationale": [
"Use agent.system.main.specifics.md for role, expertise, and process.",
"Keep the inherited communication contract unchanged."
],
"root_prompt_overrides": [
{
"file": "agent.system.main.communication.md",
"reason": "Only include if the profile needs a different response JSON schema or output format."
}
]
},
"llm_config": {
"enabled": false,
"path": "/a0/usr/agents/data-analyst/plugins/_model_config/config.json",
"source": "inherit_global",
"chat_model": null,
"utility_model": null,
"embedding_model": null,
"notes": [
"Do not put model settings in agent.yaml.",
"Only create this config file if the user wants profile-specific Main or Utility models.",
"Scoped _model_config config is not deep-merged; include a complete config with chat_model, utility_model, and embedding_model."
]
},
"files": [
{
"path": "/a0/usr/agents/data-analyst/agent.yaml",
"kind": "yaml",
"content": "title: Data Analyst\ndescription: Agent specialized in data analysis, visualization, and statistical modeling.\ncontext: Use this agent for data analysis tasks, creating visualizations, statistical analysis, and working with datasets in Python.\n"
},
{
"path": "/a0/usr/agents/data-analyst/prompts/agent.system.main.specifics.md",
"kind": "markdown",
"content": "## Your role\n\nYou are a specialized data analysis agent.\n\n## Expertise\n- Python data analysis with pandas, numpy, and scipy\n- Data visualization with matplotlib, seaborn, and plotly\n- Statistical modeling and hypothesis testing\n\n## Process\n1. Clarify the question and available data\n2. Profile and clean the dataset\n3. Run analysis with appropriate methods\n4. Visualize and interpret results\n"
}
],
"optional_components": {
"extra_prompt_overrides": [],
"tools": [],
"extensions": []
},
"validation": {
"needs_user_confirmation": true,
"unique_name_checked": false,
"yaml_valid": false,
"open_questions": []
}
}
Rules for the blueprint:
profile.name must be lowercase letters, numbers, hyphens, or underscores only.prompt_strategy.root_prompt_overrides must list any inherited root /prompts files being considered or replaced and why.prompt_strategy but do not add it to files until confirmed.llm_config.enabled controls whether a profile-scoped _model_config/config.json file is created. Keep it false when models should inherit from global/project settings.files[*].content must be the exact file content to write.status to draft until all required choices are known; set it to ready only after resolving open questions.The blueprint must contain these required profile inputs:
| Input | Rule | Example |
|---|---|---|
| name (directory name) | lowercase letters, numbers, hyphens or underscores; must be unique across profile search paths | data-analyst |
| title | human-readable display name shown in the UI | Data Analyst |
| description | one-line specialization summary | Agent specialized in data analysis, visualization, and statistical modeling. |
| context | instructions telling the superior agent when to delegate to this profile | Use this agent for data analysis tasks, creating visualizations, statistical analysis, and working with datasets in Python. |
[!NOTE]
agent.yamlhas only these three content fields (title,description,context). Do not add model, temperature, orallowed_toolsfields toagent.yaml. Profile-specific model settings live in a companion_model_configplugin config file, and tool availability is controlled by plugin activation.
After the user confirms the blueprint, create exactly the paths listed in files.
<PROFILE_ROOT>/<name>/
├── agent.yaml # Required
├── prompts/ # Optional — prompt overrides
├── tools/ # Optional — profile-specific tools
└── extensions/ # Optional — profile-specific extensions
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.
A profile with only agent.yaml is valid — it inherits everything from default/. Add the sections below only when you need to change something.
Agent Zero does not read Main/Utility model settings from agent.yaml. The _model_config plugin is always enabled and supports per-agent-profile config. If the user wants this profile to use specific LLMs, create a companion config file:
| Profile scope | Model config path |
|---|---|
| User profile | /a0/usr/agents/<profile>/plugins/_model_config/config.json |
| Plugin-distributed profile | /a0/usr/plugins/<plugin>/agents/<profile>/plugins/_model_config/config.json |
| Project-scoped profile | <project>/.a0proj/agents/<profile>/plugins/_model_config/config.json |
Scoped _model_config/config.json files are selected as a whole; they are not deep-merged with broader global/project config. Therefore, if you create this file, include a complete effective model config. When the user only wants to customize Main or Utility, copy the other sections from the current effective config.
Minimal complete profile-scoped config:
{
"allow_chat_override": true,
"chat_model": {
"provider": "openrouter",
"name": "anthropic/claude-sonnet-4.6",
"api_base": "",
"ctx_length": 200000,
"ctx_history": 0.7,
"vision": true,
"rl_requests": 0,
"rl_input": 0,
"rl_output": 0,
"kwargs": {}
},
"utility_model": {
"provider": "openrouter",
"name": "openai/gpt-5.4-mini",
"api_base": "",
"ctx_length": 128000,
"ctx_input": 0.7,
"rl_requests": 0,
"rl_input": 0,
"rl_output": 0,
"kwargs": {}
},
"embedding_model": {
"provider": "huggingface",
"name": "sentence-transformers/all-MiniLM-L6-v2",
"api_base": "",
"rl_requests": 0,
"rl_input": 0,
"kwargs": {}
}
}
Rules:
chat_model, utility_model, and embedding_model in the generated file if any profile-scoped model config is created._model_config config._model_config expects.files only when llm_config.enabled is true.Profiles inherit all prompts from /a0/prompts/ and from /a0/agents/default/. To change behavior, drop a file with the same filename into <PROFILE_ROOT>/<name>/prompts/. The loader searches profile-specific prompts first and falls back to the defaults.
agent.system.main.specifics.mdThis is the designated extension slot for profile-specific role, identity, and behavior instructions. The file ships empty in both /a0/prompts/agent.system.main.specifics.md and /a0/agents/default/agent.system.main.specifics.md precisely so profiles can fill it in without fighting the base prompt. It is included from agent.system.main.md right after agent.system.main.role.md, so whatever you put here layers on top of the inherited role.
Every shipped profile in /a0/agents/ overrides this file — a good sanity check that this is the right place for your specialization. Look at the existing profiles for concrete shape:
| Profile | What its agent.system.main.specifics.md does |
|---|---|
/a0/agents/agent0/prompts/agent.system.main.specifics.md | Establishes the top-level user-facing agent's behavior |
/a0/agents/developer/prompts/agent.system.main.specifics.md | Full "Master Developer" role + process spec (most elaborate example) |
/a0/agents/hacker/prompts/agent.system.main.specifics.md | Concise red/blue team pentester identity |
/a0/agents/researcher/prompts/agent.system.main.specifics.md | Research methodology and deliverable expectations |
/a0/agents/_example/prompts/agent.system.main.specifics.md | Minimal demo override (fictional "Agent Zero" persona) |
Start by copying whichever existing profile's specifics.md is closest to your target, then rewrite.
Example agent.system.main.specifics.md for a data analyst:
## 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
The root /a0/prompts directory contains powerful defaults. A profile can override any of these by placing a file with the same name in <PROFILE_ROOT>/<name>/prompts/. Use this when the requested profile needs a different protocol, not just a different specialty.
| File | Override when the user wants... |
|---|---|
agent.system.main.communication.md | A different response contract, such as no thoughts array, a different JSON schema, plain Markdown answers, or a domain-specific output envelope. This is the main lever for output format changes. |
agent.system.main.solving.md | A different problem-solving loop, delegation policy, verification standard, or autonomy level. |
agent.system.main.tips.md | Different file-handling, skill-use, memory, or operational best-practice defaults. |
agent.system.main.environment.md | A different runtime/environment description than the default Kali/Docker Agent Zero environment. |
agent.system.main.role.md | A fundamentally different base identity. Rare; prefer specifics.md unless replacing the base role is intentional. |
agent.system.tool.response.md | Different final-response tool instructions, such as stricter final formatting or use of includes for long output. |
fw.user_message.md / fw.ai_response.md | Different framework message wrapping. Advanced and fragile; override only with a clear reason. |
When a blueprint includes any of these, add an entry to prompt_strategy.root_prompt_overrides and include the exact override file in files.
| File | When to override | Shipped example |
|---|---|---|
agent.system.main.role.md | Replace the base role framing wholesale (rare — most profiles layer via specifics.md instead) | /a0/agents/agent0/prompts/agent.system.main.role.md |
agent.system.main.communication.md | Change reply format / communication style | /a0/agents/developer/prompts/agent.system.main.communication.md, /a0/agents/researcher/prompts/... |
agent.system.main.environment.md | Describe a non-default runtime environment | /a0/agents/hacker/prompts/agent.system.main.environment.md (Kali/Docker) |
agent.system.tool.<name>.md | Document a profile-specific tool (see Step 6) | /a0/agents/_example/prompts/agent.system.tool.example_tool.md |
[!TIP] Only override what you actually need to change. Copying unchanged prompt files creates silent drift when the framework updates the originals —
specifics.mdis safe to own because its default is empty by design.
Drop a Python tool class in <PROFILE_ROOT>/<name>/tools/<tool_name>.py:
from helpers.tool import Tool, Response
class ExampleTool(Tool):
async def execute(self, **kwargs):
test_input = kwargs.get("test_input", "")
return Response(
message=f"Example tool executed with test_input: {test_input}",
break_loop=False,
)
Two important rules:
prompts/agent.system.tool.<tool_name>.md describing its usage and JSON call schema. The prompt loader auto-includes every file matching agent.system.tool.*.md.tools/response.py) replaces the core tool for this profile only. See /a0/agents/_example/tools/response.py for a redefinition example.Lifecycle hooks go in <PROFILE_ROOT>/<name>/extensions/<hook_point>/_NN_<name>.py. The _NN_ prefix controls execution order.
Example — rename the agent at init (/a0/agents/_example/extensions/agent_init/_10_example_extension.py):
from helpers.extension import Extension
class ExampleExtension(Extension):
async def execute(self, **kwargs):
self.agent.agent_name = "SuperAgent" + str(self.agent.number)
Available hook points mirror the framework's own /a0/extensions/python/<point>/ directories — see a0-development/SKILL.md for the full list.
call_subordinate using the profile's directory name (not the title).If the profile does not appear, check:
^[a-z0-9_-]+$ pattern and is unique.agent.yaml parses as valid YAML._example profile layout/a0/agents/_example/
├── agent.yaml
├── prompts/
│ ├── agent.system.main.specifics.md # role override
│ └── agent.system.tool.example_tool.md # tool usage prompt
├── tools/
│ ├── example_tool.py # new tool
│ └── response.py # redefines core response tool
└── extensions/
└── agent_init/
└── _10_example_extension.py # init-time hook
Copy this shape when in doubt — it demonstrates every customization surface a profile supports.
agent_zero.agent_profile_blueprint.v1 JSON_model_config/config.jsonagent.yaml contains exactly title, description, contextagent.system.tool.<name>.mdcall_subordinate in a fresh conversation