Discovery Files

Discovery files are documents a domain owner publishes at a fixed /.well-known/ path to declare which agents may act for that domain; AdCP defines two, adagents.json and brand.json, and AAMP defines none.

A discovery file is a document a domain owner publishes at a fixed /.well-known/ path to declare which agents may act for that domain. An agent card, served from the same /.well-known/ prefix, is the reverse: an agent’s statement about itself. AdCP defines two discovery files, and AAMP defines none.

FileHosted bySchema titleAnswers
adagents.jsonPublisher domains, and data provider domainsAdCP Agents AuthorizationWhich agents may sell this inventory, or resell these signals?
brand.jsonBrand and house domainsBrand DiscoveryWho is this brand, and who speaks for it?

Other strings share the namespace and none has a schema. /.well-known/adcp/sales and /adcp/signals are agent endpoints that appear only in examples. adcp-ownership.txt carries the domain-control challenge: the registry issues a single-use nonce, echoed back from that path inside fifteen minutes, or the same proof runs through a _adcp-owner.{domain} DNS TXT record. Neither of the two schemas has changed across the stable 3.1.x releases.

What a buyer computes from the two files

The two files are read against each other, and validation “checks both sides”: the publisher’s adagents.json (does it authorise this agent with the claimed delegation_type?) and the operator’s brand.json (does it declare this property with a matching relationship?). The result is a five-state signal with one documented buyer action per state.

StateMeaningBuyer action
inlineThe seller is the brand owner, no delegation involvedProceed
mutual_assertionBoth sides published matching declarationsProceed
one_sided_brandThe seller’s brand.json claims a publisher that hasn’t reciprocated“Do not treat as authorization. Any domain can claim any publisher unilaterally.”
one_sided_houseThe publisher’s adagents.json names a seller whose brand.json doesn’t acknowledge itHold for human review
standaloneNeither side publishes, bearer-token trust only, which is where a silent domain puts every buyerOut-of-band authorisation, or refuse

AdCP credits the mutual-assertion pattern to ads.txt and sellers.json, and what it adds is the second side: an entry in a publisher’s adagents.json counts as authorisation only when the named agent’s own brand.json declares the same property back.

The string mutual_assertion appears in no published schema, in 3.1.13 or earlier. The five states live in three .mdx documents and nowhere else, and docs/trust.mdx labels the model an RFC linked to a GitHub issue rather than settled specification. Two conformant implementations can compute different verdicts about the same publisher without either violating a schema.

The two cross-checked enums are different lengths. delegation_type has three values: direct, delegated, ad_network. relationship has those three plus owned, which the schema documents as having “no adagents.json delegation_type counterpart”, and no rule says what a validator does with the leftover. AAMP’s trust status is a typed field on the wire; AdCP’s five states are not in any schema.

The five brand.json variants

#VariantUse when
1Authoritative Location RedirectThe canonical document is hosted elsewhere
2House RedirectThe brand domain rolls up into a house
3Brand AgentAn MCP agent serves brand identity
4House PortfolioA house publishes its brands
5Brand Canonical DocumentA brand self-publishes its own identity

A canonical document is the schema’s brand definition: id and names required, the rest optional, plus house_domain for a brand in a house. Variant 4 wraps that definition in brands[], inline or by pointer, and adds house-level trademarks and authorized_operators.

Variants 1 to 3 are mutually exclusive with each other and with 4 and 5. Variants 4 and 5 compose: brand_refs[] points down from the house, house_domain points back up, and each side must name the other. Nesting stops there — “A brand cannot itself declare brand_refs[]” — so a house that lists its brands inline keeps editorial control: “If Converse wants to update its logo, someone edits Nike, Inc.’s file”.

Both redirect variants take an optional redirect_reason with seven values, four of which “suggest the resolved target is in transition and consumers SHOULD shorten cache TTL until stable”.

The schema’s own top-level description lists four of the five. Brand Canonical Document is missing from it, and the same sentence says the file is hosted “on house domains” when variant 5 puts it at the brand’s own /.well-known/brand.json. A reader working from that description rather than from the definitions under it will miss a valid variant.

adagents.json: six authorisation variants over one base

A pointer file carries authoritative_location; an inline file carries the catalog arrays, contact, catalog_etag and authorized_agents[].

Entries in authorized_agents[] are discriminated on authorization_type: four variants scope inventory (property_ids, property_tags, inline_properties, publisher_properties), two scope data (signal_ids, signal_tags). All six inherit url, authorized_for, signing_keys, encryption_keys and last_updated from core/authorized-agent-base.json, “centralized to prevent drift across all authorization-type variants”. Because the publisher rather than the agent publishes those keys, a buyer can check an agent’s signature against the domain’s own declaration.

authorized_agents: [] carries no authorisation meaning. Validators “MUST NOT read it as deny-all, authorize-all, or a revocation, MUST NOT treat its presence as an error, and MUST still consume the catalog arrays.” The registry emits exactly this shape: its writes are “an identity-only write surface: the stored document always carries authorized_agents: []”. A validator that reads an empty array as deny-all rejects every publisher the registry has written.

Fetching carries its own risk: one deploy at an authoritative location changes authorisation for every publisher in the network. AdCP’s managed-networks guidance writes the fetch rules at MUST: the response is capped at 5 MB for the pointer and a recommended 20 MB for the dereferenced file, redirects are refused, and both hops carry short timeouts. On a transient 5xx the cached file is served rather than failing closed, a deliberate availability choice.

Discovery files in AAMP

AAMP defines no domain-hosted authorisation file and no brand identity file. It does use /.well-known/ for the agent’s own card, the opposite direction of assertion. The nearest approach is a docstring: iab-agentic-primitives documents a registry endpoint answering “whether a publisher domain authorizes a given agent URL, per the publisher’s /.well-known/authorized-agents.txt file.” No schema or field list for that file is published, and the test double “does not fetch the publisher’s authorized-agents.txt”.

Authority sits in a different place in each stack. AdCP’s discovery path starts at a file the domain owner publishes and moves on to a runtime capability call, and the authorisation entry carries the agent’s signing_keys and encryption_keys. AAMP’s starts at a registry query and moves on to an agent card fetch, with no key attestation in the discovery path, so the registry operator holds the position the domain owner holds in AdCP.