AFM Specification v0.3.0¶
1. Introduction¶
AFM (Agent-Flavored Markdown) is a markdown-based format to define AI agents. It allows agents to be written in text once and reused across different platforms.
This document details the AFM file format, its syntax, and the schema for defining an agent.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.
1.1. Key Goals of AFM¶
AFM unifies agent definition through a text-based standard:
-
No Code: AFM enables defining an agent's instructions, tools, and configuration in a simple, declarative, text-based format, moving away from complex, imperative code. The markdown-based syntax is intuitive for both developers and non-technical stakeholders to read, write, and understand.
-
Portable: By defining agents declaratively in text rather than code, AFM enables the same agent definition to be interpreted and deployed across diverse platforms and tools.
-
Unified: AFM provides a clean, declarative model that works seamlessly for both developers writing code and those using visual, low-code interfaces. The same AFM file can power both experiences.
-
Adaptable: AFM is designed to be flexible and extensible, allowing the standard to evolve as AI technologies and requirements change.
2. Core Concepts¶
AFM defines the following core concepts:
- Agent: The primary entity defined by an AFM file, representing an AI agent.
- Role: The agent's purpose and responsibilities.
- Instructions: Directives governing the agent's behavior.
- Details: Metadata describing the agent (name, version, author, etc.).
- Model: The AI model powering the agent.
- Tools: External tools and services available to the agent.
- Interface: How the agent is invoked and its input/output contract.
Agent Memory
Given the lack of standardization, AFM does not prescribe a standard for agent memory yet.
3. File Extension¶
An agent definition file MUST use the .afm.md or .afm extension.
4. Syntax Overview¶
4.1. Basic Structure¶
An AFM file is structured into two main sections: the front matter and the agent declaration.
- Front Matter: Contains metadata about the agent.
- Markdown Body: Contains the agent's definition.
4.2. Front Matter¶
The front matter is a YAML block at the top of the file, enclosed by --- lines. Refer to the YAML specification for more details on YAML syntax.
This section contains metadata about the agent. These metadata fields are OPTIONAL and can be used to provide additional context or configuration for the agent.
| Section | Description |
|---|---|
| Agent Details | Information about the agent, such as its name, description, version, and author. |
| Agent Model | Defines the AI model that powers the agent. |
| Agent Interfaces | Defines how the agent is invoked and its input/output signature. |
| Agent Tools | Defines external tools available to the agent (e.g., via MCP). |
| Agent Execution | Runtime execution configuration like iteration limits. |
Refer to the AFM Schema for a complete list of fields and their meanings.
4.3. Markdown Body¶
This section contains the detailed instructions that guide the agent's behavior.
Users can use markdown syntax to format the text, including headings, lists, links, and code blocks.
The Markdown body MUST contain the following headings, with corresponding content.
# Role: Defines the agent's purpose and responsibilities. This section describes what the agent does and the context in which it operates. This content typically forms the opening context of the system prompt.# Instructions: Provides directives that shape the agent's behavior, capabilities, and operational guidelines. This section contains the core logic and rules that govern how the agent processes inputs and generates outputs.
4.4. Example¶
Basic AFM File Example
Here is a simple example of an AFM file:
---
spec_version: "0.3.0"
name: "Math Tutor"
description: "An AI assistant that helps with math problems"
version: "1.0.0"
max_iterations: 20
interfaces:
- type: consolechat
tools:
mcp:
- name: "math_operations"
transport:
type: "http"
url: "${env:MATH_MCP_SERVER}"
---
# Role
You are an experienced math tutor capable of assisting students with mathematics problems, providing explanations, step-by-step
solutions, and practice exercises.
# Instructions
You are a knowledgeable and patient math tutor who helps students understand mathematical concepts. Provide clear, step-by-step
explanations for math problems, using simple language and avoiding jargon unless explaining it.
When solving problems, show all work and explain each step. Use the available math operations tools when performing calculations.
Explain mathematical concepts with real-world examples when possible. Be encouraging and supportive of students' efforts, ask clarifying
questions if a problem is not clearly stated, provide multiple approaches to solving problems when applicable, help students identify
and correct their mistakes.
5. Schema Definitions¶
This section defines the schema for the Front Matter. For clarity, the schema is divided into several subsections, each detailing a specific aspect of the Agent.
5.1. Agent Details¶
This section defines the schema for agent-specific metadata. It is OPTIONAL but recommended for clarity and organization.
AFM implementations SHALL use this section to display the agent's metadata in user interfaces to provide better user experience for end users.
5.1.1. Schema Overview¶
The agent metadata fields are specified in the YAML front matter of an AFM file:
spec_version: string # AFM specification version (e.g., "0.3.0")
name: string # The name of the agent
description: string # Brief description of the agent's purpose and functionality
version: string # Semantic version (e.g., "1.0.0")
author: string # Single author in format "Name <Email>"
authors: # Takes precedence over the 'author' field if both exist
- string # Multiple authors, each in format "Name <Email>"
provider: object # Agent provider
name: string # Name of the organization
url: string # URL to the organization's website
icon_url: string # URL to an icon representing the agent
license: string # License under which the agent is released
5.1.2. Field Definitions¶
Each field serves a specific purpose in defining and organizing the agent:
| Key | Type | Required | Description |
|---|---|---|---|
spec_version |
string |
No | Version of the AFM specification this file conforms to (e.g., "0.3.0"). This is OPTIONAL but recommended for compatibility. AFM implementations MAY use this field to validate compatibility and provide warnings for mismatched spec versions. |
name |
string |
No | Identifies the agent in human-readable form. Default: inferred from the filename of the AFM file. AFM implementations SHALL use this field to display the agent's name in user interfaces. |
description |
string |
No | Provides a concise summary of what the agent does. Default: inferred from the markdown body # Role section.AFM implementations SHALL use this field to display the agent's description in user interfaces. |
version |
string |
No | Semantic version of the agent definition (MAJOR.MINOR.PATCH). Default: "0.0.0". AFM implementations SHALL use this field to display the agent's version in user interfaces. |
author |
string |
No | Single author in format Name <Email>.Credits the creator of the agent definition. If both author and authors fields are provided, authors takes precedence. |
authors |
string[] |
No | Multiple authors, each in format Name <Email>.Credits the creators of the agent definition. Takes precedence over author if both exist. |
icon_url |
string |
No | URL to an icon representing the agent. This is OPTIONAL but recommended for visual representation in user interfaces. AFM implementations SHALL use this field to display the agent's icon in user interfaces. |
provider |
object |
No | Information about the organization providing the agent. This is OPTIONAL but recommended for attribution. See the Provider Object below for details. |
license |
string |
No | License under which the agent definition is released. This is OPTIONAL but recommended for clarity. |
| Key | Type | Required | Description |
|---|---|---|---|
name |
string |
No | Name of the organization providing the agent. |
url |
string |
No | URL to the organization's website. |
5.1.3. Example Usage¶
The following example demonstrates a valid agent metadata section as specified in Section 5.1. This YAML front matter illustrates the use of recommended and optional fields for agent definition:
---
spec_version: "0.3.0"
name: "Math Tutor"
description: "An AI assistant that helps with math problems"
version: "1.2.0"
authors:
- "Jane Smith <jane@example.com>"
- "John Doe <john@example.com>"
provider:
name: "Example AI Solutions"
url: "https://example.com"
icon_url: "https://example.com/icons/math-tutor.png"
license: "MIT"
---
5.2. Agent Model¶
This section specifies the AI model or language model that powers the agent. It is OPTIONAL and defines how to access and authenticate with the model service.
5.2.1. Field Definitions¶
| Key | Type | Required | Description |
|---|---|---|---|
name |
string |
No | Model identifier or name. |
provider |
string |
No | The organization or service providing the model (e.g., "openai", "anthropic"). |
url |
string |
No | The URL endpoint for the model service. |
authentication |
object |
No | Authentication configuration for accessing the model. See Section 5.6 for the schema. |
5.2.2. Schema Overview¶
model:
name: string # Optional model name or identifier
provider: string # Optional model provider (e.g., "openai", "anthropic")
url: string # Optional model service endpoint URL
authentication: object # Optional authentication configuration
5.2.3. Example Usage¶
model:
name: "gpt-4-turbo"
provider: "openai"
url: "https://api.openai.com/v1/chat/completions"
authentication:
type: "api-key"
api_key: "${env:OPENAI_API_KEY}"
5.3. Agent Interfaces¶
This section defines how an agent can be interacted with or triggered. An agent can have multiple interfaces, allowing it to be accessed in different ways. It is OPTIONAL and specifies how the agent receives inputs and produces outputs.
If the interfaces field is not explicitly defined in the front matter, AFM implementations MUST assume a default interface of type consolechat. In this default mode, the agent SHALL be invoked as a command-line chat interface: it MUST accept a single string input (user message) and MUST produce a single string output (agent reply).
Users can override these defaults by specifying the interfaces field in the front matter as an array of interface definitions. AFM implementations SHALL use these definitions to generate the agent's callable interfaces and to ensure consistent behavior across different platforms.
5.3.1. Interface Types¶
The interface.type field MUST be one of the following values:
| Value | Description |
|---|---|
consolechat |
The agent is exposed as a command-line/terminal chat interface for interactive console-based conversations. |
webchat |
The agent is exposed as a web-based chat interface, accessible through browsers with a conversational UI. |
webhook |
The agent is exposed as a webhook endpoint and supports subscription details (e.g., WebSub hub integration). |
Each interface type defines how the agent is triggered and interacted with. Implementations MAY support all three types as described above.
5.3.2. Schema Overview¶
interfaces:
- type: consolechat | webchat | webhook
prompt: string # For webhook type: template string for constructing the user prompt for the agent run
signature:
input: object # JSON Schema object defining input parameters
output: object # JSON Schema object defining output parameters
# Optional, depending on type:
exposure: # For webchat/webhook types only
http: object # Configuration for exposing as an HTTP endpoint.
subscription: # For webhook type
protocol: string # e.g., "websub"
hub: string # Subscription hub URL
topic: string # Topic to subscribe to
callback: string # Callback URL for receiving events (optional, for dynamic registration)
secret: string # Secret for verifying webhook payloads (optional)
authentication: object # Authentication configuration for the subscription (optional)
5.3.3. Field Definitions¶
The interfaces field is an array where each element represents an interface definition. Each interface object has the following fields:
Interface Object:
| Key | Type | Required | Description |
|---|---|---|---|
type |
string |
Yes | The agent's interface type. Must be one of: - webchat: Web-based chat interface- consolechat: Command-line/terminal chat interface- webhook: Webhook endpoint with subscription support |
prompt |
string |
No | (webhook only) A template string for constructing the user prompt for an agent run from webhook data. Supports variable substitution with HTTP context prefixes: - ${http:payload.fieldname} to access webhook payload fields- ${http:header.headername} to access HTTP headersWhen provided, this templated prompt is used as the user prompt to the agent instead of passing the raw payload. When omitted, the implementation determines how to construct the agent prompt from the webhook payload. |
signature |
object |
No | Defines the agent's input and output parameters. If omitted, defaults to string input and string output for consolechat and webchat types. See Signature Object. |
exposure |
object |
No | Configuration for how a webchat or webhook agent is exposed via HTTP. Not applicable to consolechat. See Exposure Object. |
subscription |
object |
No | (webhook only) Subscription configuration. See Subscription Object. |
Signature Object¶
Defines the data contract for the agent. The input and output fields MUST conform to the JSON Schema specification, but are expressed in YAML syntax. This allows for:
- Simple signatures (e.g., a single string, number, boolean, or array)
- Complex, structured objects with named properties
- Full expressiveness of JSON Schema for validation and documentation
Examples:
Single string input/output (default):
Complex object with properties:
signature:
input:
type: object
properties:
user_prompt:
type: string
description: "The user's query or request"
context:
type: object
description: "Additional context for the request"
required: [user_prompt]
output:
type: object
properties:
response:
type: string
description: "The agent's response to the user prompt"
confidence:
type: number
description: "Confidence score for the response"
required: [response]
Array input/output:
Default Behavior:
Default signature behavior:
-
For
consolechatandwebchattypes: the defaultsignatureis string input and string output. -
For
webhooktype: theinputfield MAY be omitted, as the webhook provider determines the input payload structure.
AFM implementations SHALL use this definition to generate the agent's callable interface and to ensure consistent behavior across different platforms.
Subscription Object (webhook only):
| Key | Type | Required | Description |
|---|---|---|---|
protocol |
string |
Yes | The subscription protocol (e.g., websub). |
hub |
string |
No | The hub to subscribe at (optional if subscription is registered manually). |
topic |
string |
No | The topic to subscribe to (optional if subscription is registered manually). |
callback |
string |
No | The callback URL where events should be delivered (optional, for dynamic or self-registration). |
authentication |
object |
No | Optional authentication configuration for the webhook subscription. See Section 5.6 for the schema. |
secret |
string |
No | A secret used to sign or verify webhook payloads (optional, for security). |
Exposure Object¶
Applies to agents of type webchat and webhook, and defines how the corresponding services are exposed.
| Key | Type | Required | Description |
|---|---|---|---|
http |
object |
No | Defines how to expose the agent via a standard HTTP endpoint. |
HTTP Object:
| Key | Type | Required | Description |
|---|---|---|---|
path |
string |
No | The URL path segment for the agent's HTTP endpoint (e.g., /math-tutor). If not specified, implementations SHOULD use /chat for webchat interfaces and /webhook for webhook interfaces. |
HTTP Exposure Configuration
The http object is applicable for agents of type webchat or webhook. It defines how the agent is exposed via a standard HTTP endpoint, allowing other systems to interact with it over the web.
Default Paths:
webchat: If noexposure.http.pathis specified, implementations SHOULD default to/chatwebhook: If noexposure.http.pathis specified, implementations SHOULD default to/webhook
AFM does not define the HTTP methods (GET, POST, etc.) for the agent's endpoint. This is left to the implementation to decide based on the agent's functionality and requirements.
5.3.4. Example Usages¶
Web chat agent (default simple string):
Web chat agent (custom with structured input/output):
interfaces:
- type: webchat
signature:
input:
type: object
properties:
message:
type: string
description: "The user's chat message"
context:
type: object
description: "Additional context for the conversation"
required: [message]
output:
type: object
properties:
reply:
type: string
description: "The agent's chat reply"
confidence:
type: number
description: "Confidence score for the response"
required: [reply]
exposure:
http:
path: "/webchat"
Console chat agent:
Webhook agent (with prompt templating):
interfaces:
- type: webhook
prompt: |
A new ${http:payload.event} event was received from ${http:header.User-Agent}.
Event Details:
- Type: ${http:payload.event}
- Timestamp: ${http:payload.timestamp}
- Source: ${http:payload.source}
Payload:
${http:payload.data}
Please analyze this webhook event and provide a summary of the action taken.
signature:
output:
type: object
properties:
result:
type: string
description: "The agent's response to the webhook event"
required: [result]
subscription:
protocol: "websub"
hub: "https://example.com/websub-hub"
topic: "https://example.com/events/agent"
callback: "https://myagent.example.com/webhook-callback"
secret: "${env:WEBHOOK_SECRET}"
exposure:
http:
path: "/webhook-handler"
5.4. Tools¶
This section defines the tools the agent can access and use.
5.4.1. Schema Overview¶
The tools fields are specified in the YAML front matter of an AFM file:
5.4.2. Field Definitions¶
| Key | Type | Required | Description |
|---|---|---|---|
tools |
object |
No | Container for protocol-specific tool connection configurations. |
tools.mcp |
array |
No | List of MCP servers to connect to. See Section 6.1 for detailed schema. |
5.4.3. Example Usage¶
Here's a simple example of tools in an AFM file:
tools:
mcp:
- name: "github_api"
transport:
type: "http"
url: "https://api.githubcopilot.com/mcp/"
authentication:
type: "bearer"
token: "${env:GITHUB_TOKEN}"
5.5. Agent Execution¶
This section defines execution control and runtime behavior settings for the agent. These settings are OPTIONAL and help AFM implementations manage agent execution safely and efficiently.
5.5.1. Schema Overview¶
5.5.2. Field Definitions¶
| Key | Type | Required | Description |
|---|---|---|---|
max_iterations |
integer |
No | Maximum number of iterations the agent can perform in a single run. This helps prevent infinite loops or runaway execution. Default: Implementation-specific (typically unlimited or a high value like 100). AFM implementations SHOULD respect this limit and gracefully terminate agent execution when the limit is reached. |
5.5.3. Example Usage¶
5.6. Authentication¶
This section defines the generic client authentication schema that is used across different parts of the AFM specification, including MCP server connections and webhook subscriptions.
The authentication object is OPTIONAL.
5.6.1. Schema Overview¶
authentication:
type: string # Authentication scheme (bearer, jwt, oauth2, api-key, basic, etc.)
# Additional fields depend on the type
# Examples:
# - For bearer: token
# - For basic: username, password
5.6.2. Field Definitions¶
| Key | Type | Required | Description |
|---|---|---|---|
type |
string |
Yes | Authentication scheme (e.g., bearer, basic, jwt, oauth2).Determines which additional fields are required or supported. |
* |
Various | Varies | Additional fields are authentication-type specific. See examples below for common patterns. Values SHOULD use variable substitution to reference credentials securely. |
5.6.3. Example Usage¶
# Bearer token authentication
authentication:
type: bearer
token: "${env:API_TOKEN}"
# Basic authentication
authentication:
type: basic
username: "${env:API_USERNAME}"
password: "${env:API_PASSWORD}"
6. Protocol Specifications¶
This section details the protocols that agents use to communicate with external systems and other agents, as referenced in the schema above.
6.1. Model Context Protocol (MCP)¶
The Model Context Protocol (MCP) enables agents to connect to external tools and data sources.
6.1.1. Schema Overview¶
mcp:
- name: string # Unique identifier for the server connection
transport:
type: string # Transport mechanism (must be "http")
url: string # URL for the MCP server
authentication: # Optional authentication configuration
type: string # Authentication scheme (bearer, jwt, oauth2, etc.)
tool_filter: # Optional
allow: [string] # Whitelist of tools
deny: [string] # Blacklist of tools
6.1.2. Field Definitions¶
The mcp field is an array where each element represents an MCP server connection. Each server entry must have a unique name that identifies the connection.
MCP Server Object:
| Key | Type | Required | Description |
|---|---|---|---|
name |
string |
Yes | A unique, human-readable identifier for the connection. |
transport |
object |
Yes | An object defining the transport mechanism. See Transport Object below. |
tool_filter |
object |
No | Filter configuration for tools from this server. See Tool Filter Object below. |
| Key | Type | Required | Description |
|---|---|---|---|
type |
string |
Yes | Transport mechanism. Must be http. |
url |
string |
Yes | The URL of the MCP server. |
authentication |
object |
No | Authentication configuration for the connection. See Section 5.6 for the schema. |
HTTP Transport Only
AFM currently supports only the streamable HTTP transport for MCP connections, but may support other transports in the future.
| Key | Type | Required | Description |
|---|---|---|---|
allow |
string[] |
No | A whitelist of tools to expose from this server, using just the tool name (e.g., create_issue, read_file). If specified, only these tools are available. |
deny |
string[] |
No | A blacklist of tools to hide from this server, using just the tool name (e.g., write_file). Applied after allow filtering. |
Filter Precedence
When both allow and deny are specified, the tools in the allow list are made available and then the deny list is applied to remove specific tools from that filtered set. If only deny is specified, all tools from the server are available except those in the deny list.
6.1.3. Example Implementation¶
This example defines tool connections to remote MCP servers with authentication and tool filtering. Note the use of variable substitution for sensitive and/or variable input.
tools:
mcp:
- name: "github_mcp_server"
transport:
type: "http"
url: "${env:GITHUB_MCP_URL}"
authentication:
type: "bearer"
token: "${env:GITHUB_OAUTH_TOKEN}"
tool_filter:
allow:
- "issues.create"
- "repos.list"
- name: "database_server"
transport:
type: "http"
url: "${env:DATABASE_MCP_URL}"
authentication:
type: "bearer"
token: "${env:DATABASE_API_KEY}"
tool_filter:
allow:
- "query"
- "search"
deny:
- "delete"
- "drop_table"
7. Variable Substitution¶
AFM files MAY use ${...} syntax for variable substitution.
This specification defines three standard variable prefixes:
- The
env:prefix (e.g.,${env:API_TOKEN}) is specification-defined and MUST resolve to an environment variable, generally at agent load time (i.e., variable resolution forenv:occurs before the agent is made available for use). - The
http:payloadprefix (e.g.,${http:payload.field}) is specification-defined for webhook interfaces and MUST resolve to the corresponding field in the incoming webhook payload at runtime. Variable resolution forhttp:payloadoccurs at runtime for each webhook invocation. - The
http:headerprefix (e.g.,${http:header.User-Agent}) is specification-defined for webhook interfaces and MUST resolve to the corresponding HTTP header value from the incoming webhook request at runtime. Header names are case-insensitive.
Implementations MAY define and support additional variable substitution conventions beyond those specified here. Common examples include file: and secret:, but these are implementation-defined and MAY vary between AFM implementations. The timing and semantics of resolution for these prefixes are determined by the implementation.
7.1. Variable Prefixes¶
The following table summarizes variable prefixes and their status:
| Prefix | Context | Description | Example | Spec Status |
|---|---|---|---|---|
env: |
Static | Environment variable | ${env:API_TOKEN} |
Spec-defined |
http:payload |
Runtime (webhook) | Access webhook payload fields | ${http:payload.event} or ${http:payload['nested.field']} |
Spec-defined |
http:header |
Runtime (webhook) | Access HTTP request headers | ${http:header.User-Agent} or ${http:header.X-GitHub-Event} |
Spec-defined |
file: |
Static | Value from external config file | ${file:api.baseUrl} |
Implementation-defined |
secret: |
Static | Value from secrets manager | ${secret:MODEL_API_KEY} |
Implementation-defined |
Static vs Runtime Resolution:
- Static variables (
env:,file:,secret:): Resolved once when the agent is loaded or initialized - Runtime variables (
http:payload,http:header): Resolved dynamically for each webhook invocation using request-specific data
7.2. Example Usage¶
Static variable substitution:
authentication:
type: "bearer"
token: "${env:API_TOKEN}" # Environment variable
transport:
url: "${file:api.baseUrl}" # From external config file
model:
authentication:
type: "bearer"
token: "${secret:MODEL_API_KEY}" # From secrets manager
Runtime variable substitution (webhook prompts):
interfaces:
- type: webhook
prompt: |
New GitHub ${http:payload.action} event on repository ${http:payload.repository.full_name}
Event: ${http:header.X-GitHub-Event}
Sender: ${http:payload.sender.login}
Details:
${http:payload}
7.3. Webhook Variable Access Patterns¶
When using http:payload and http:header in webhook prompts:
Payload Field Access (Specification Requirements):
- Implementations MUST support dot notation for nested object access (e.g.,
${http:payload.field.nested}resolves to the value of thenestedproperty within thefieldobject). - Implementations MUST support bracket notation for field names containing special characters or dots (e.g.,
${http:payload['field.with.dots']}resolves to the value of thefield.with.dotsproperty). - Implementations MUST support array access by index (e.g.,
${http:payload.items[0]}resolves to the first element of theitemsarray). - Implementations MUST support combined access for complex paths (e.g.,
${http:payload.users[0].name}or${http:payload['special-field'][0]}resolves to thenameproperty of the first element in theusersarray, or the first element of thespecial-fieldarray, respectively). - Implementations MUST support root access, where
${http:payload}resolves to the entire payload as a JSON string.
Header Access (Specification Requirements):
- Implementations MUST treat header names as case-insensitive (e.g.,
${http:header.Content-Type}and${http:header.content-type}MUST resolve to the same value). - Implementations MUST support access to headers with special characters (e.g.,
${http:header.X-GitHub-Event}resolves to the value of theX-GitHub-Eventheader).
Error Handling: Implementations SHOULD handle missing or invalid variable references gracefully by using meaningful defaults or failing with clear error messages.
8. Future Work¶
This section outlines potential future enhancements to the AFM specification, including:
- Extending tool support to include MCP tools with STDIO transport, OpenAPI-based tools for existing services, and functions as tools
- First-class support for multi-agent interaction via the Agent-to-Agent (A2A) protocol
- Support for an Agent memory abstraction covering common memory patterns
- Support for Agent Identity
- Support for additional interface types (e.g., scheduled execution, REST API)