Category: Standards Track
November 2025
This document defines the JSON Agents - Portable Agent Manifest (PAM), a JSON-based standard for describing AI agents and agent graphs in a portable, schema-driven format.
This specification is distributed for public implementation, review, and discussion.
Distribution is unlimited.
Copyright © 2025 JSON Agents.
All Rights Reserved.
JSON Agents defines the Portable Agent Manifest (PAM) — a universal, JSON-native format for representing AI agents, their capabilities, tools, runtimes, and governance metadata.
PAM provides a single, interoperable structure that allows agents to be described, validated, and exchanged across frameworks, platforms, and ecosystems without code translation.
PAM is derived entirely from established JSON and JSON Schema standards and designed for compatibility, governance, and multi-agent orchestration.
- Introduction
- Requirements and Conventions
- Terminology
- Design Overview
- Top-Level Manifest Structure
- Core Profile (
core) - Exec Profile (
exec) - Gov Profile (
gov) - Graph Profile (
graph) - Extensions and Namespaces
- Conformance
- Security Considerations
- Example Manifests
- Registry Considerations
- IANA Considerations
- URI Scheme Definition
- References
Appendix A. Normative JSON Schema
Appendix B. Policy Expression Language
The agent ecosystem has evolved through a patchwork of incompatible manifest formats — each framework defining unique metadata structures, tool schemas, and governance models.
This fragmentation prevents portability, interoperability, and consistent validation.
JSON Agents introduces the Portable Agent Manifest (PAM) as a shared schema for defining AI agents declaratively.
The goal is to make agents:
- Framework-agnostic
- Interoperable across runtimes
- Governable at scale
- Composable into networks
PAM defines:
- A top-level JSON structure for agent manifests.
- Four modular profiles:
core— identity, capabilities, tools, context.exec— runtime and environment.gov— security, policies, observability.graph— multi-agent orchestration and routing.
- Validation through JSON Schema.
- A reserved extension model for innovation.
PAM does not define:
- A transport or API protocol.
- Prompt formatting or reasoning algorithms.
- Scheduling, execution order, or model architecture.
The key words MUST, SHOULD, and MAY are to be interpreted as described in RFC 2119.
- Manifests MUST conform to RFC 8259, ECMA-404, and ISO/IEC 21778.
- Encoding MUST be UTF-8.
- Validation MUST be compatible with JSON Schema 2020-12.
| Term | Definition |
|---|---|
| Agent | A logical AI entity capable of processing input, invoking tools, and generating output. |
| Manifest | A JSON document describing an agent or network of agents. |
| Profile | A modular subset of the specification (e.g., core, exec, gov, graph). |
| Capability | A declared function or skill the agent provides. |
| Tool | An external callable resource (API, function, system, or plugin). |
| Runtime | The environment in which the agent executes. |
| Policy | A declarative constraint governing behavior. |
| Security | Configuration related to sandboxing and access control. |
| Graph | A collection of interconnected agents and message routes. |
| Message Envelope | A structured format for messages passed between agents. |
| Extension | A namespaced addition to the standard manifest fields. |
Manifests MAY declare one or more profiles:
"profiles": ["core", "exec", "gov", "graph"]If omitted, core is assumed.
Each profile adds semantic layers:
- Core: Base identity and capabilities.
- Exec: Runtime execution context.
- Gov: Governance, security, and observability.
- Graph: Multi-agent orchestration.
A manifest describes a template. Implementations MAY instantiate one or more live agents based on it.
A conforming manifest MUST include at least:
{
"manifest_version": "1.0",
"profiles": ["core"],
"agent": {},
"capabilities": [],
"tools": [],
"modalities": {},
"context": {}
}Top-level fields:
| Field | Type | Description |
|---|---|---|
manifest_version |
string | Identifies specification version. |
profiles |
array | Declares active profiles. |
agent |
object | Agent metadata. |
capabilities |
array | Agent functions. |
tools |
array | External callable resources. |
modalities |
object | Input/output formats. |
context |
object | Memory and windowing hints. |
"agent": {
"id": "ajson://example/echo",
"name": "Echo Agent",
"description": "Echoes back text.",
"version": "1.0.0",
"license": "Apache-2.0"
}"capabilities": [
{ "id": "echo", "description": "Echo input text." }
]"tools": [
{
"id": "tool://search",
"name": "Search API",
"type": "http",
"endpoint": "https://api.example.com/search",
"input_schema": { "type": "object" },
"output_schema": { "type": "object" }
}
]"modalities": {
"input": ["text"],
"output": ["text", "json"]
}"context": { "window": 4096, "persistent": false }"runtime": {
"type": "python",
"entrypoint": "main:run",
"env": { "MODE": "production" },
"resources": { "cpu_cores_min": 1, "memory_mb_min": 512 }
}"security": {
"sandbox": "container",
"network_zone": "trusted"
}"policies": [
{
"id": "deny-external-http",
"effect": "deny",
"action": "tool.call",
"where": "tool.endpoint !~ 'internal'"
}
]"observability": {
"log_level": "info",
"metrics_enabled": true
}"graph": {
"nodes": [
{ "id": "router", "ref": "ajson://example/router" },
{ "id": "faq", "ref": "ajson://example/faq" }
]
}"graph": {
"edges": [
{ "from": "router", "to": "faq", "condition": "message.intent == 'faq'" }
]
}"graph": {
"message_envelope": {
"schema": "https://jsonagents.org/json/schema/message-envelope.json"
}
}"extensions": {
"vendor.example/routing": { "shadow_mode": true }
}"x-internal": { "notes": "for testing only" }Implementations MUST ignore unrecognized extensions.
A manifest is conformant if:
- It validates against the JSON Agents schema.
- Declared profiles match included sections.
- No unknown non-extension fields are present.
- Manifests MUST NOT embed secrets.
- Evaluators MUST NOT execute manifest content.
- Policy failures SHOULD fail closed.
{
"manifest_version": "1.0",
"agent": { "id": "ajson://example/minimal", "name": "Minimal" }
}{
"manifest_version": "1.0",
"profiles": ["core", "exec", "gov", "graph"],
"agent": { "id": "ajson://example/router", "name": "Router" },
"runtime": { "type": "node", "entrypoint": "dist/router.js" },
"security": { "sandbox": "process" },
"graph": {
"nodes": [
{ "id": "router", "ref": "ajson://example/router" },
{ "id": "faq", "ref": "ajson://example/faq" }
],
"edges": [
{ "from": "router", "to": "faq", "condition": "message.intent == 'faq'" }
]
}
}Implementations MAY maintain public registries for:
- Capabilities
- Tool types
- Profiles
- Envelope schemas
JSON Agents manifests SHOULD use the media type:
application/agents+json
This media type is intended for registration with IANA and follows the structured syntax suffix convention defined in RFC 6838.
The recommended file extension for JSON Agents manifests is:
.agents.json
This extension clearly identifies agent manifest files while maintaining compatibility with standard JSON tooling.
Servers and clients MAY use standard HTTP content negotiation to request or serve JSON Agents manifests:
Accept: application/agents+json
Content-Type: application/agents+jsonThe ajson:// URI scheme provides a standardized method for uniquely identifying and referencing agent manifests, capabilities, and other JSON Agents resources.
The ajson:// URI scheme follows the generic URI syntax defined in RFC 3986:
ajson-uri = "ajson://" authority path [ "?" query ] [ "#" fragment ]
authority = [ userinfo "@" ] host [ ":" port ]
path = "/" segment *( "/" segment )
segment = *pchar
Examples:
ajson://jsonagents.org/examples/router-hub
ajson://example.com/agents/summarizer/v2.1.0
ajson://registry.internal/capabilities/routing
ajson://localhost:8080/test/agent#metadata
The authority SHOULD represent:
- A DNS domain under the manifest publisher's control, OR
- A well-known registry service, OR
localhostfor local/development manifests
The path MUST:
- Begin with a forward slash (
/) - Uniquely identify the resource within the authority's namespace
- Use URL-safe characters (RFC 3986)
The path MAY include:
- Organizational hierarchy (e.g.,
/org/team/agent) - Version information (e.g.,
/agent/v1.2.3) - Resource type indicators (e.g.,
/capabilities/summarization)
The fragment identifier MAY be used to reference:
- Specific sections within a manifest (e.g.,
#runtime) - Individual capabilities (e.g.,
#capability/summarization) - Graph nodes (e.g.,
#node/router)
Implementations SHOULD resolve ajson:// URIs through one of the following methods:
-
HTTPS Transformation (RECOMMENDED):
ajson://example.com/agents/router → https://example.com/.well-known/agents/router.agents.json -
Direct Registry Lookup: Query a configured registry service using the full URI as an identifier.
-
Local Cache: Check local manifest cache before attempting network resolution.
Implementations using HTTPS transformation SHOULD:
- Map
ajson://tohttps://with.well-known/agents/path prefix - Append
.agents.jsonextension if not present - Follow HTTP redirects (3xx status codes)
- Cache responses according to HTTP caching headers
function resolve(ajsonURI):
1. Parse URI into components (authority, path, fragment)
2. Check local cache for authority + path
3. If cached and not expired, return cached manifest
4. Transform to HTTPS well-known URI
5. Perform HTTP GET with Accept: application/agents+json
6. Validate response against json-agents.json schema
7. Cache response if valid
8. If fragment present, extract referenced component
9. Return resolved manifest or component
Implementations MUST handle resolution failures gracefully:
| Condition | Behavior |
|---|---|
| Network unavailable | Use cached version if available, otherwise fail |
| 404 Not Found | Return resolution error with original URI |
| Invalid manifest | Return validation error with details |
| Timeout | Retry with exponential backoff, max 3 attempts |
A conformant registry service MUST:
- Accept
ajson://URIs as identifiers - Store and serve valid JSON Agents manifests
- Implement versioning for manifest updates
- Provide discovery endpoints for browsing
- Support content negotiation (JSON/YAML)
Example registry interface:
GET /resolve?uri=ajson://example.com/agents/router
Accept: application/agents+json
Response:
200 OK
Content-Type: application/agents+json
{
"manifest_version": "1.0",
...
}Registries SHOULD provide metadata endpoints:
GET /metadata?uri=ajson://example.com/agents/router
Response:
{
"uri": "ajson://example.com/agents/router",
"versions": ["1.0.0", "1.0.1", "1.1.0"],
"latest": "1.1.0",
"published": "2025-11-09T12:00:00Z",
"deprecated": false
}URIs MAY encode version information:
- Immutable:
ajson://example.com/agent/v1.2.3(exact version) - Mutable:
ajson://example.com/agent(latest version) - Major:
ajson://example.com/agent/v1(latest v1.x.x)
For production deployments, manifests SHOULD reference immutable versioned URIs to ensure reproducibility.
- All resolution over networks MUST use TLS 1.2 or higher
- Certificate validation MUST be performed
- HTTPS redirects MUST NOT downgrade to HTTP
Implementations SHOULD:
- Verify manifest signatures if
signaturesfield is present - Validate Content-Type header matches expected media type
- Reject manifests with invalid schemas
- Implement Content Security Policy for web-based resolvers
Implementations MUST:
- Validate URI syntax before resolution attempts
- Reject URIs with embedded credentials (userinfo)
- Sanitize path components to prevent directory traversal
- Implement rate limiting for resolution requests
- Use cryptographic hashes for cache keys
- Implement cache-control header validation
- Provide cache invalidation mechanisms
- Log resolution attempts for audit trails
- Do not include sensitive information in URIs
- Implement access control for private manifests
- Consider DNS privacy implications
- Provide opt-out for telemetry/analytics
The ajson:// URI scheme is intended for registration with IANA under the Uniform Resource Identifier (URI) Schemes registry.
Scheme Name: ajson
Status: Provisional
Applications/Protocols: JSON Agents Portable Agent Manifest
Contact: JSON Agents Working Group
Change Controller: JSON Agents Steering Committee
- RFC 8259 — The JavaScript Object Notation (JSON) Data Interchange Format
- ECMA-404 — The JSON Data Interchange Syntax
- ISO/IEC 21778:2017 — JSON Data Interchange Syntax
- JSON Schema 2020-12
- JSON-LD 1.1
- RFC 6838 — Media Type Specifications and Registration Procedures
- RFC 3986 — Uniform Resource Identifier (URI): Generic Syntax
- RFC 2119 — Key words for use in RFCs to Indicate Requirement Levels
See schema/json-agents.json for the normative schema definition.
This appendix defines the expression language used in policy.where clauses for declarative access control and behavior constraints.
The policy expression language is:
- Simple: Minimal syntax for common use cases
- Safe: No code execution or side effects
- Deterministic: Same input always produces same result
- JSONPath-like: Familiar to developers using JSON query languages
expression = comparison | logical_expr | literal
comparison = accessor operator value
logical_expr = expression logical_op expression
| "(" expression ")"
| "not" expression
accessor = identifier *("." identifier | "[" index "]")
identifier = ALPHA *(ALPHA | DIGIT | "_")
index = DIGIT+ | STRING
operator = "==" | "!=" | ">" | "<" | ">=" | "<="
| "~" | "!~" | "in" | "not in"
| "contains" | "starts_with" | "ends_with"
logical_op = "&&" | "||" | "and" | "or"
value = STRING | NUMBER | BOOLEAN | NULL | array
array = "[" [value *("," value)] "]"
STRING = "'" *CHAR "'"
NUMBER = ["-"] DIGIT+ ["." DIGIT+]
BOOLEAN = "true" | "false"
NULL = "null"| Operator | Description | Example |
|---|---|---|
== |
Equality | tool.type == 'http' |
!= |
Inequality | tool.type != 'system' |
> |
Greater than | message.priority > 5 |
< |
Less than | context.window < 8192 |
>= |
Greater or equal | runtime.memory_mb_min >= 512 |
<= |
Less or equal | runtime.cpu_cores_min <= 4 |
| Operator | Description | Example |
|---|---|---|
~ |
Regex match | tool.endpoint ~ '^https://internal\\.corp' |
!~ |
Regex non-match | tool.endpoint !~ 'external' |
contains |
Substring test | message.payload contains 'urgent' |
starts_with |
Prefix test | agent.id starts_with 'ajson://internal' |
ends_with |
Suffix test | tool.endpoint ends_with '.internal.corp' |
| Operator | Description | Example |
|---|---|---|
in |
Membership test | tool.type in ['http', 'function'] |
not in |
Non-membership | tool.type not in ['system', 'plugin'] |
| Operator | Description | Example |
|---|---|---|
&& / and |
Logical AND | tool.type == 'http' && tool.auth.method == 'none' |
|| / or |
Logical OR | message.priority > 8 || message.urgent == true |
not |
Logical NOT | not (tool.type in ['system', 'plugin']) |
From highest to lowest:
- Parentheses:
( ) - Unary:
not - Comparison:
==,!=,>,<,>=,<= - String/Collection:
~,!~,in,not in,contains,starts_with,ends_with - Logical AND:
&&,and - Logical OR:
||,or
Expressions evaluate against a context object containing:
{
"tool": { // Current tool being invoked
"id": "...",
"type": "...",
"endpoint": "...",
...
},
"message": { // Current message envelope
"from": "...",
"to": "...",
"payload": {...},
"intent": "...",
...
},
"agent": { // Current agent manifest
"id": "...",
"name": "...",
...
},
"runtime": { // Runtime context
"environment": "production",
"timestamp": "2025-11-10T00:00:00Z",
...
}
}{
"id": "deny-http-no-auth",
"effect": "deny",
"action": "tool.call",
"where": "tool.type == 'http' && tool.auth.method == 'none'"
}{
"id": "deny-external-endpoints",
"effect": "deny",
"action": "tool.call",
"where": "tool.endpoint !~ '^https://.*\\.internal\\.corp'"
}{
"id": "audit-sensitive-messages",
"effect": "audit",
"action": "message.send",
"where": "(message.payload contains 'password' || message.payload contains 'api_key') && not (message.to starts_with 'ajson://internal')"
}{
"id": "allow-safe-tools",
"effect": "allow",
"action": "tool.call",
"where": "tool.type in ['function', 'http'] && tool.id in ['tool://safe/search', 'tool://safe/summarize']"
}- Comparisons between incompatible types evaluate to
false - String comparisons are case-sensitive
- Numbers are compared numerically
- Booleans compare by value (
true>false)
- Accessing non-existent fields returns
null null == nullevaluates totruenullcompared to any non-null value evaluates tofalse
&&: If left operand isfalse, right operand is not evaluated||: If left operand istrue, right operand is not evaluated
- MUST NOT execute arbitrary code
- MUST limit recursion depth (recommended: 10 levels)
- MUST prevent regex denial-of-service (ReDoS)
- SHOULD implement expression complexity limits
- Evaluate expressions in constant or linear time when possible
- Cache compiled expressions
- Optimize common patterns (e.g., simple equality)
- Syntax errors SHOULD fail policy evaluation (fail-closed)
- Runtime errors (e.g., type mismatch) MAY log warnings
- Invalid regex patterns MUST fail at compile time
Future versions MAY add:
- Functions:
length(),upper(),lower(),trim() - Array operations:
map(),filter(),any(),all() - Temporal operators:
before,after,within - Quantifiers:
exists,forall
Extensions MUST maintain backward compatibility with this grammar.