Introduction
Agent templates let you define agents as data rather than PHP code. Instead of writing a class that constructs anAgentBuilder with hardcoded capabilities and tools, you describe the agent’s identity, instructions, tool access, and resource budget in a definition file. At runtime, a factory turns that definition into a working AgentLoop and AgentState.
This separation between definition and instantiation makes it possible to manage agents through configuration files, version them alongside your prompts, and let non-developers create or adjust agents without touching PHP. It is also the foundation of the subagent system — when a parent agent spawns a child, it looks up the child’s AgentDefinition in a registry and builds a loop from it on the fly.
AgentDefinition
AgentDefinition is the core data object that describes an agent. It is a final readonly class with the following fields:
Creating Definitions in PHP
Tool Visibility Rules
Thetools and toolsDeny fields work together to control which tools the agent can access:
tools: null(the default) — the agent inherits all tools available in its context. For subagents, this means all tools the parent has.tools: new NameList('read_file', 'bash')— only these named tools are allowed. Any other tools are excluded.toolsDeny: new NameList('write_file')— these tools are removed from whatever set the agent would otherwise have, whether inherited or explicitly allowed.
tools to allow read_file and write_file, and toolsDeny to deny write_file, the agent will only have access to read_file.
ExecutionBudget
TheExecutionBudget class defines resource limits for a single agent execution. All fields are optional — null means unlimited.
AgentDefinition declares a budget, it is translated into UseGuards during loop instantiation.
Definition Files
Agent definitions can be stored in markdown, YAML, or JSON files. Each format maps directly to theAgentDefinition fields.
Markdown Format
Markdown definitions use YAML front matter for structured fields and the document body for the system prompt. This is the most readable format for agents with long or complex system prompts.systemPrompt field.
YAML Format
JSON Format
AgentDefinition objects when loaded.
Loading Definitions
AgentDefinitionLoader
TheAgentDefinitionLoader class parses a single file into an AgentDefinition. It selects the appropriate parser based on the file extension.
.md, .json, .yaml, .yml. The loader throws a RuntimeException if the file cannot be read and an InvalidArgumentException for unsupported extensions.
You can also supply custom parsers by passing an array to the constructor:
AgentDefinitionRegistry
TheAgentDefinitionRegistry is a named collection of agent definitions. It supports programmatic registration, file loading, directory scanning, and auto-discovery.
Programmatic Registration
Loading from Files
Auto-Discovery
TheautoDiscover() method scans up to three standard locations for agent definition files:
userPath, packagePath, then projectPath/.claude/agents. Later registrations overwrite earlier ones with the same name, so user-level definitions take precedence over package defaults.
Querying the Registry
Instantiation Factories
Once you have anAgentDefinition, two factory classes turn it into runnable components: one for the initial AgentState, and one for the AgentLoop that executes it.
DefinitionStateFactory
Creates anAgentState pre-configured with the definition’s system prompt, metadata, and LLM config. It implements the CanInstantiateAgentState contract.
DefinitionLoopFactory
Creates a fully configuredAgentLoop from a definition. This factory implements CanInstantiateAgentLoop and is used internally by SendMessage and other session actions.
- LLM config — if the definition specifies an
llmConfig, aToolCallingDriveris created with that config. - Guards — if the definition declares a non-empty budget,
UseGuardsis applied with the budget’s limits. - Capabilities — each named capability in the definition is resolved from the
AgentCapabilityRegistryand applied to the builder. - Tools — if the definition references named tools, they are resolved from the tool registry and added via
UseTools.
Providing a Tool Registry
When the definition references tools by name (viatools or toolsDeny), you must provide a tool registry that implements CanManageTools:
DefinitionLoopFactory throws an InvalidArgumentException. Unknown tool names also cause an exception, listing which tools could not be found.
Event Propagation
Pass an event handler to propagate events from instantiated loops to a parent dispatcher:AgentCapabilityRegistry
TheAgentCapabilityRegistry maps string names to capability instances. It is the bridge between definition files (which reference capabilities by name) and the PHP capability classes that implement them.
CanProvideAgentCapability, an InvalidArgumentException is thrown.
Opt-in Composer manifest discovery
Installed packages can expose zero-configuration capabilities and tools through theircomposer.json:
$result->errors(). Missing classes, wrong interfaces, and constructors
requiring arguments fail only when that specific registry entry is resolved.
Root-package mappings override vendor mappings. For configured capabilities or
tools, register an application factory directly instead of using the manifest.
Serializing and safely persisting definitions
AgentDefinitionSerializer renders the same canonical definition as Markdown,
YAML, or JSON. Canonicalization normalizes fallback labels and empty optional
values so parsing a serialized definition preserves every meaningful field.
FileAgentDefinitionStore for persistence policy. It accepts an existing
writable root, derives the filename from a validated agent name, writes
atomically, and refuses overwrite unless it is explicitly requested. It never
accepts a caller-provided path.
UseAgentDefinitions exposes list_agents and read_agent by default. Supply
a store explicitly to add write_agent; this is the only mode that grants the
agent filesystem mutation authority:
write_agent validates the complete definition before touching disk, refuses
replacement by default, and refreshes the definition registry after a successful
save. It does not mutate or reload an already-running agent loop.
Using with Subagents
TheAgentDefinitionRegistry implements CanManageAgentDefinitions, making it the standard provider for the UseSubagents capability. When a parent agent calls spawn_subagent, the subagent system looks up the named definition in this registry and builds a child loop from it.
Serialization
AgentDefinition supports round-trip serialization via toArray() and fromArray():
fromArray() method also accepts title as an alias for label to support legacy formats.