Problem
Publishers in production routinely ship adagents.json files where authorized_agents[] entries carry only {url, authorized_for} — no authorization_type, no selector. Examples from the wild include wonderstruck.org and Raptive's published files. These files don't satisfy any branch of the schema's oneOf (every variant requires authorization_type + a matching selector), but the publisher's intent is unambiguous: "this agent is authorized for everything I list."
Today the AdCP ecosystem has three answers to that intent and none are good:
- Strict per the schema (Python SDK's
get_properties_by_agent): resolves to []. Products can't bind to the publisher even though the file looks "valid" to humans.
- Permissive by accident (JS SDK, today): attributes all top-level
properties[] to every listed agent regardless of authorization_type. Works operationally, drifts from the schema, indistinguishable from a buggy implementation.
- Local shim (salesagent): we just added explicit permissive fallback (see salesagent#377). It works but every consumer will reimplement this differently — and the spec hasn't acknowledged what they're working around.
The root cause is that the spec has no first-class way to say "authorize agent X for everything I list" without enumerating it via property_ids / property_tags / inline properties. Publishers reach for the shortest expression of intent, which produces bare entries.
Proposed fix
Add a spec-conformant authorization variant whose meaning is "agent is authorized for every property in the file's top-level properties[] array." Two reasonable shapes:
Option A — new authorization_type value:
{
"url": "https://wonderstruck.sales-agent.scope3.com",
"authorized_for": "Display banners",
"authorization_type": "all_top_level_properties"
}
Schema adds a 7th oneOf variant: {required: [url, authorized_for, authorization_type]} where authorization_type is constrained to the literal "all_top_level_properties". No selector field needed — the top-level properties[] is the implicit selector.
Option B — explicit all_properties: true selector:
{
"url": "https://wonderstruck.sales-agent.scope3.com",
"authorized_for": "Display banners",
"authorization_type": "all_properties",
"all_properties": true
}
Symmetric with the other variants (each variant has a selector field that names the binding). Arguably uglier but consistent.
I think A is cleaner — there's no useful payload beyond the discriminator itself, so a paired selector field is dead weight. Either way, the value of having this is that bare-entry behavior gets a name and a stable spec citation, so SDKs can stop divining intent.
Companion: builder UX
The AAO builder at agenticadvertising.org/publisher should default to producing typed entries. Concretely:
- When a publisher adds an agent to their adagents.json, the wizard should prompt: "Which properties is this agent authorized for? (a) All of them, (b) Specific IDs, (c) By tag, (d) Inline list."
- "(a) All of them" produces the new spec-conformant shape from this proposal.
- Bare-entry output should not be possible from the builder.
Companion: validator
Companion to adcp#4476 (validator currently reports schema-invalid files as valid: true). Once this proposal lands:
- Bare entries become a soft warning: "This entry uses the legacy bare shape. Spec-conformant equivalent:
authorization_type: 'all_top_level_properties'. Still resolves the same way under permissive SDK modes — see adcp-client-python#711."
- Bare entries are no longer flagged as
invalid (since the new variant gives them a clean migration target), but they're not silently passed either.
The combination is: publishers who want "authorize for everything" have a typed expression they can use, the validator nudges legacy files toward it, and SDKs can stop carrying permissive fallbacks indefinitely (we'd close adcp-client-python #711 once both SDKs support the new variant and the long tail of legacy files has migrated).
Cross-references
adcp-client-python #711 — Python SDK permissive resolver (operational stopgap; would be deprecated once this lands)
adcp-client #1721 — JS SDK per-agent resolution gap (related: needs both strict and permissive modes until new variant ships)
- adcp#4476 — strict validator behavior
- salesagent#377 — operator-facing UI model that surfaced the gap
Willing to PR
Happy to PR the schema change and a docs patch if the team agrees on the direction (and lands on A vs B).
Problem
Publishers in production routinely ship
adagents.jsonfiles whereauthorized_agents[]entries carry only{url, authorized_for}— noauthorization_type, no selector. Examples from the wild includewonderstruck.organd Raptive's published files. These files don't satisfy any branch of the schema'soneOf(every variant requiresauthorization_type+ a matching selector), but the publisher's intent is unambiguous: "this agent is authorized for everything I list."Today the AdCP ecosystem has three answers to that intent and none are good:
get_properties_by_agent): resolves to[]. Products can't bind to the publisher even though the file looks "valid" to humans.properties[]to every listed agent regardless ofauthorization_type. Works operationally, drifts from the schema, indistinguishable from a buggy implementation.The root cause is that the spec has no first-class way to say "authorize agent X for everything I list" without enumerating it via
property_ids/property_tags/ inlineproperties. Publishers reach for the shortest expression of intent, which produces bare entries.Proposed fix
Add a spec-conformant authorization variant whose meaning is "agent is authorized for every property in the file's top-level
properties[]array." Two reasonable shapes:Option A — new
authorization_typevalue:{ "url": "https://wonderstruck.sales-agent.scope3.com", "authorized_for": "Display banners", "authorization_type": "all_top_level_properties" }Schema adds a 7th
oneOfvariant:{required: [url, authorized_for, authorization_type]}whereauthorization_typeis constrained to the literal"all_top_level_properties". No selector field needed — the top-levelproperties[]is the implicit selector.Option B — explicit
all_properties: trueselector:{ "url": "https://wonderstruck.sales-agent.scope3.com", "authorized_for": "Display banners", "authorization_type": "all_properties", "all_properties": true }Symmetric with the other variants (each variant has a selector field that names the binding). Arguably uglier but consistent.
I think A is cleaner — there's no useful payload beyond the discriminator itself, so a paired selector field is dead weight. Either way, the value of having this is that bare-entry behavior gets a name and a stable spec citation, so SDKs can stop divining intent.
Companion: builder UX
The AAO builder at
agenticadvertising.org/publishershould default to producing typed entries. Concretely:Companion: validator
Companion to adcp#4476 (validator currently reports schema-invalid files as
valid: true). Once this proposal lands:authorization_type: 'all_top_level_properties'. Still resolves the same way under permissive SDK modes — seeadcp-client-python#711."invalid(since the new variant gives them a clean migration target), but they're not silently passed either.The combination is: publishers who want "authorize for everything" have a typed expression they can use, the validator nudges legacy files toward it, and SDKs can stop carrying permissive fallbacks indefinitely (we'd close
adcp-client-python#711 once both SDKs support the new variant and the long tail of legacy files has migrated).Cross-references
adcp-client-python#711 — Python SDK permissive resolver (operational stopgap; would be deprecated once this lands)adcp-client#1721 — JS SDK per-agent resolution gap (related: needs both strict and permissive modes until new variant ships)Willing to PR
Happy to PR the schema change and a docs patch if the team agrees on the direction (and lands on A vs B).