Context
PR #2183 ("feat(delegate): File-based agent definitions with markdown + YAML frontmatter") introduces a new file-based subagent definition mechanism (Markdown + YAML frontmatter) and centralizes agent discovery/registration logic under openhands.sdk.subagent.
As discussed in the PR comment:
The implementation is understandable, but today you have to read quite a bit of code to learn the intended behavior. We should document the design intent + invariants so both humans and agentic contributors can reason about it without reverse-engineering the loader.
What should be documented (design assumptions / invariants)
(Concrete items that are easy to accidentally break during refactors)
-
Discovery locations & file rules
- Project-level directories:
{project}/.agents/agents/*.md then {project}/.openhands/agents/*.md
- User-level directories:
~/.agents/agents/*.md then ~/.openhands/agents/*.md
- Only top-level
*.md files are scanned; subdirectories are ignored; README.md is skipped.
- Errors parsing a single file should be non-fatal (logged, continue scanning).
-
Resolution / precedence order ("who wins")
- Programmatic
register_agent() must never be overwritten.
- Plugin-provided agents (
Plugin.agents) have higher priority than file-based agents.
- Project-level file agents override user-level file agents.
- Within each level,
.agents/ overrides .openhands/.
- SDK built-in agents are the lowest priority (registered only if absent).
-
Schema & semantics of Markdown agents
- YAML frontmatter keys:
name, description, tools, model (default inherit), color.
- Unknown frontmatter keys are retained as
metadata.
- Body Markdown becomes the agent's
system_prompt (currently applied as an AgentContext.system_message_suffix).
tools accepts either a string or a list; tool names are mapped to Tool(name=...).
<example>...</example> tags inside description are extracted for triggering.
Proposals (2–3 options) for documenting the design
Proposal A: Add a scoped AGENTS.md next to the implementation (best for agentic contributors)
Create openhands-sdk/openhands/sdk/subagent/AGENTS.md (or .../delegate/AGENTS.md) that:
- states the precedence model and scanning rules as a small table
- states the intended invariants ("first wins", "never overwrite register_agent")
- links to the public user docs page (Proposal B)
Why: OpenHands-style agent runs will automatically pick this up, reducing code archaeology.
Proposal B: Add a short "Subagents / delegation design" page to the docs repo (best for humans)
In https://github.com/OpenHands/docs (sdk section), add a page focused on:
- where agent definition files live
- exact precedence rules
- minimal examples for Markdown frontmatter
- how this interacts with plugins (
Plugin.agents) and programmatic registration
Why: Keeps user-facing + maintainer-facing understanding in one canonical place.
Proposal C: Add an ADR (Architecture Decision Record) + keep invariants executable
Add an ADR in-repo (e.g., docs/adr/XXXX-file-based-subagents.md) capturing:
- motivation and non-goals
- invariants above
- rationale for the chosen precedence order
Additionally, ensure tests explicitly encode the precedence order so docs and behavior cannot drift.
Acceptance criteria
- A future contributor can answer "where does this agent come from and why did it win" without reading
LocalConversation + subagent/* code.
- The precedence rules are written down in one place, with links from code to docs.
Context
PR #2183 ("feat(delegate): File-based agent definitions with markdown + YAML frontmatter") introduces a new file-based subagent definition mechanism (Markdown + YAML frontmatter) and centralizes agent discovery/registration logic under
openhands.sdk.subagent.As discussed in the PR comment:
The implementation is understandable, but today you have to read quite a bit of code to learn the intended behavior. We should document the design intent + invariants so both humans and agentic contributors can reason about it without reverse-engineering the loader.
What should be documented (design assumptions / invariants)
(Concrete items that are easy to accidentally break during refactors)
Discovery locations & file rules
{project}/.agents/agents/*.mdthen{project}/.openhands/agents/*.md~/.agents/agents/*.mdthen~/.openhands/agents/*.md*.mdfiles are scanned; subdirectories are ignored;README.mdis skipped.Resolution / precedence order ("who wins")
register_agent()must never be overwritten.Plugin.agents) have higher priority than file-based agents..agents/overrides.openhands/.Schema & semantics of Markdown agents
name,description,tools,model(defaultinherit),color.metadata.system_prompt(currently applied as anAgentContext.system_message_suffix).toolsaccepts either a string or a list; tool names are mapped toTool(name=...).<example>...</example>tags insidedescriptionare extracted for triggering.Proposals (2–3 options) for documenting the design
Proposal A: Add a scoped
AGENTS.mdnext to the implementation (best for agentic contributors)Create
openhands-sdk/openhands/sdk/subagent/AGENTS.md(or.../delegate/AGENTS.md) that:Why: OpenHands-style agent runs will automatically pick this up, reducing code archaeology.
Proposal B: Add a short "Subagents / delegation design" page to the docs repo (best for humans)
In https://github.com/OpenHands/docs (sdk section), add a page focused on:
Plugin.agents) and programmatic registrationWhy: Keeps user-facing + maintainer-facing understanding in one canonical place.
Proposal C: Add an ADR (Architecture Decision Record) + keep invariants executable
Add an ADR in-repo (e.g.,
docs/adr/XXXX-file-based-subagents.md) capturing:Additionally, ensure tests explicitly encode the precedence order so docs and behavior cannot drift.
Acceptance criteria
LocalConversation+subagent/*code.