Skip to main content
A ready-to-run example is available here!
File-based agents let you define specialized sub-agents using Markdown files. Each file declares the agent’s name, description, tools, and system prompt — the same things you’d pass to register_agent() in code, but without writing any Python. This is the fastest way to create reusable, domain-specific agents that can be invoked via delegation.

Agent File Format

An agent is a single .md file with YAML frontmatter and a Markdown body:
The YAML frontmatter configures the agent. The Markdown body becomes the agent’s system prompt.

Frontmatter Fields

<example> Tags

Add <example> tags inside the description to help the orchestrating agent know when to delegate to this agent:
These examples are extracted and stored as when_to_use_examples on the AgentDefinition object. They can be used by routing logic (or prompt-building) to help decide when to delegate to the right sub-agent.

Directory Conventions

Place agent files in these directories, scanned in priority order (first match wins):
my-project/
.agents
agents
code-reviewer.md
tech-writer.md
security-auditor.md
src/
...
Rules:
  • Only top-level .md files are loaded (subdirectories are skipped)
  • README.md files are automatically skipped
  • Project-level agents take priority over user-level agents with the same name
Put agents shared across all your projects in ~/.agents/agents/. Put project-specific agents in {project}/.agents/agents/.

Built-in Agents

The openhands-tools package ships with built-in sub-agents as Markdown files in openhands/tools/preset/subagents/. They can be registered via register_builtins_agents() and become available for delegation tasks. By default, all agents include finish tool and the think tool.

Available Built-in Sub-Agents

When enable_browser=False, browser-dependent agents like web-researcher are not registered.
Deprecated names: The following legacy names are deprecated (since v1.12.0) and will be removed in version 2.0.0:
  • default → use general-purpose
  • default cli mode → use general-purpose
  • explore → use code-explorer
  • bash → use bash-runner

Registering Built-in Sub-Agents

Call register_builtins_agents() to register all built-in sub-agents. This is typically done once before creating a conversation:
Registration order is critical when programmatically registering agents that share a name with a built-in agent. The system is designed to skip registration if a name is already taken. Therefore, if you register your custom agents before the built-in agents are loaded, your custom versions will take precedence.Conversely, if the built-in agents are loaded first, they will take precedence, and any subsequent registration of a custom agent with the same name will be ignored.

Overall Priority

When the same agent name is defined in multiple places, the highest-priority source wins. Registration is first-come first-win.

Auto-Registration

The simplest way to use file-based agents is auto-registration. Call register_file_agents() with your project directory, and all discovered agents are registered into the delegation system:
This scans both project-level and user-level directories, deduplicates by name, and registers each agent as a delegate that can be spawned by the orchestrator.

Manual Loading

For more control, load and register agents explicitly:

Key Functions

load_agents_from_dir()

Scans a directory for .md files and returns a list of AgentDefinition objects:

agent_definition_to_factory()

Converts an AgentDefinition into a factory function (LLM) -> Agent:
The factory:
  • Maps tool names from the frontmatter to Tool objects
  • Appends the Markdown body to the parent system message via AgentContext(system_message_suffix=...)
  • Respects the model field ("inherit" keeps the parent LLM; an explicit model name creates a copy)

load_project_agents() / load_user_agents()

Load agents from project-level or user-level directories respectively:

Using with Delegation

File-based agents are designed to work with the TaskToolSet. Once registered, the orchestrating agent can delegate tasks to them by name through the task tool’s subagent_type parameter:
To learn more about agent delegation, follow our comprehensive guide.

Example Agent Files

Code Reviewer

Technical Writer

Advanced Features

MCP Servers

File-based agents can define MCP server configurations inline, giving them access to external tools without any Python code:
The mcp_servers field uses the same format as the MCP configuration — each key is a server name, and the value contains command and args for launching the server.

Environment Variable Resolution

All string values in MCP server configurations support ${VAR} (and $VAR) environment variable references, which are resolved from os.environ at load time. This lets you forward secrets and dynamic paths without hard-coding them in Markdown:
Environment variable resolution applies recursively to all string fields — command, args, url, headers, env, and any other string values in the server config. If a referenced variable is not set, the placeholder is left unchanged (e.g., ${NONEXISTENT_VAR} stays as-is).

Hooks

File-based agents can define lifecycle hooks that run at specific points during execution:
Hook event types:
  • pre_tool_use — Runs before tool execution (can block with exit code 2)
  • post_tool_use — Runs after tool execution
  • user_prompt_submit — Runs before processing user messages
  • session_start / session_end — Run when conversation starts/ends
  • stop — Runs when agent tries to finish (can block)
Each hook matcher supports:
  • "*" — Matches all tools
  • Exact name — e.g., "terminal" matches only that tool
  • Regex patterns — e.g., "/file_.*/" matches tools starting with file_
For more details on hooks, see the Hooks guide.

Permission Mode

Control how a file-based agent handles action confirmations with the permission_mode field:
Available modes: When permission_mode is omitted (or set to None), the subagent inherits the confirmation policy from its parent conversation.
Permission mode is particularly useful for specialized sub-agents. For example, a “read-only explorer” agent might use never_confirm since it only reads files, while a “deploy” agent might use always_confirm for safety.
For more details on security and confirmation policies, see the Security guide.

Agents in Plugins

Plugins bundle agents, tools, skills, and MCP servers into reusable packages. Learn more about plugins here.
File-based agents can also be bundled inside plugins. Place them in the agents/ directory of your plugin:
my-plugin/
.plugin
plugin.json
agents
code-reviewer.md
tech-writer.md
Plugin agents use the same .md format and are registered automatically when the plugin is loaded. They have higher priority than file-based agents but lower than programmatic register_agent() calls.

Ready-to-run Example

This example is available on GitHub: examples/01_standalone_sdk/42_file_based_subagents.py
This example uses AgentDefinition directly. File-based agents are loaded into the same AgentDefinition objects (from Markdown) and registered the same way.
examples/01_standalone_sdk/42_file_based_subagents.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

Next Steps

  • TaskToolSet - Delegate work to specialized sub-agents
  • Skills - Add specialized knowledge and triggers to agents
  • Plugins - Bundle agents, skills, hooks, and MCP servers together
  • Custom Agent - Create agents programmatically for more control