Example: Nested Catalogs¶
This example shows how an enterprise organizes a large artifact inventory using nested catalogs. The root catalog provides an overview; each department maintains its own sub-catalog.
Root catalog¶
The root catalog is served at /.well-known/ai-catalog.json:
{
"specVersion": "1.0",
"host": {
"displayName": "Acme Enterprise AI",
"identifier": "did:web:acme-corp.com",
"documentationUrl": "https://docs.acme-corp.com/ai"
},
"entries": [
{
"identifier": "urn:air:acme-corp.com:a2a:assistant",
"version": "3.0.0",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/assistant.json",
"description": "General-purpose corporate assistant agent."
},
{
"identifier": "urn:air:acme-corp.com:catalog:finance",
"displayName": "Finance Services",
"type": "application/ai-catalog+json",
"url": "https://acme-corp.com/catalogs/finance.json",
"description": "Financial agents, MCP servers, and datasets.",
"tags": ["finance", "trading", "compliance"]
},
{
"identifier": "urn:air:acme-corp.com:catalog:engineering",
"displayName": "Engineering Tools",
"type": "application/ai-catalog+json",
"url": "https://acme-corp.com/catalogs/engineering.json",
"description": "CI/CD agents, code review tools, and DevOps servers.",
"tags": ["engineering", "devops", "ci-cd"]
}
]
}
Finance sub-catalog¶
The Finance team owns and hosts finance.json. It can be updated independently of the root:
{
"specVersion": "1.0",
"host": {
"displayName": "Acme Finance Team",
"identifier": "did:web:finance.acme-corp.com"
},
"entries": [
{
"identifier": "urn:air:acme-corp.com:a2a:finance",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/finance.json",
"tags": ["finance", "trading"]
},
{
"identifier": "urn:air:acme-corp.com:mcp:finance",
"type": "application/mcp-server-card+json",
"url": "https://api.acme-corp.com/mcp/server-card",
"tags": ["finance", "mcp"]
},
{
"identifier": "urn:air:acme-corp.com:data:market-2026q1",
"displayName": "Market Dataset Q1 2026",
"type": "application/parquet",
"url": "https://data.acme-corp.com/market-2026q1.parquet",
"tags": ["dataset", "finance"]
}
]
}
How it works¶
Direct entries (like urn:air:acme-corp.com:a2a:assistant) appear directly in the root catalog. Clients see them without any additional fetching. The displayName is omitted for A2A entries since the agent card itself carries a canonical name.
Nested catalog entries (like urn:air:acme-corp.com:catalog:finance) have type: "application/ai-catalog+json" and set displayName since catalogs don't embed their own name. Clients follow the url to fetch the sub-catalog and process it as another AI Catalog.
Dataset entries set displayName since Parquet files don't carry a human-readable name.
Independent ownership: each sub-catalog has its own host object. The Finance team updates their catalog without touching the root.
Mix and match: a catalog can contain both direct entries and nested catalog references in the same entries array.
Client traversal¶
A client that wants all artifacts walks the tree:
- Fetch root at
/.well-known/ai-catalog.json - Find entries with
type: "application/ai-catalog+json"→ these are sub-catalogs - Fetch each sub-catalog URL
- Repeat (up to depth limit of 4)
- Collect all non-catalog entries
See Consuming Catalogs — Handling nested catalogs for implementation details including cycle detection.