feat(spec): add Deployment official extension (resolves #64) - #96
feat(spec): add Deployment official extension (resolves #64)#96marianogonzalez wants to merge 1 commit into
Conversation
Implement the deployment-metadata proposal from issue Agent-Card#64 as an official extension keyed by https://ai-catalog.org/extensions/deployment, rather than a native entry field. An entry's extensions map may carry a non-empty instances[] array describing the concrete deployments of a single logical artifact, enabling policy-aware instance selection while the entry keeps one identity. Each instance carries a required instanceId and url, plus optional environment, releaseChannel (release maturity track, e.g. stable/beta/LTS/ EDGE, orthogonal to environment), region, dataResidency, compliance, and description. Identifiers use the current urn:air format (ADR-0015). - spec: Official Extensions entry, Deployment Metadata Extension section, informative CDDL, and privacy note - adr: ADR-0021 documenting the official-extension decision - docs: new deployment-metadata example (+ nav), creating/consuming guides Signed-off-by: marianogonzalez <mariano.gonzalez@salesforce.com>
| ] | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
I would consider using the ai-catalog spec itself to solve this problem for example:
{
"identifier": "urn:air:acme-corp.com:agent:invoice-processor",
"type": "application/ai-catalog+json",
"tags": ["finance", "a2a"],
"data": {
"entries": [
{
"id": "urn:air:acme-corp.com:agent:invoice-processor-us",
"type": "application/a2a-agent-card+json",
"url": "https://api.acme-corp.com/agents/invoice",
"extensions": {
"https://ai-catalog.org/extensions/deployment": {
"environment": "production",
"region": "us-east-1"
}
},
{
"id": "urn:air:acme-corp.com:agent:invoice-processor-prod-eu",
"type": "application/a2a-agent-card+json",
"url": "https://eu-api.acme-corp.com/agents/invoice",
"extensions": {
"https://ai-catalog.org/extensions/deployment": {
"region": "eu-west-1",
"dataResidency": ["EU"],
"compliance": ["GDPR"],
"instanceId": "invoice-prod-eu",
"environment": "production"
}
}
},
{
"id": "urn:air:acme-corp.com:agent:invoice-processor-staging-eu",
"type": "application/a2a-agent-card+json",
"url": "https://staging-api.acme-corp.com/agents/invoice",
"extensions": {
"https://ai-catalog.org/extensions/deployment": {
"instanceId": "invoice-staging",
"environment": "staging",
"region": "us-east-1",
"releaseChannel": "beta"
}
}
}
]
}
}
I think on the concept of a default URL or something like that today in the ai-catalog-cli we have logic which is:
If ID resolves to type ai-catalog+json and the user hasn't requested a specific type:
prompt the user to provide `--type` to give their preference
if catalog contains more than one entry of --type:
prompt the user with the list of available entries to pick from
So you gracefully degrade from:
ai-catalog-cli pull urn:air:acme-corp.com:agent:invoice-processor
to
ai-catalog-cli pull --type application/a2a-agent-card+json urn:air:acme-corp.com:agent:invoice-processor
to
ai-catalog-cli pull urn:air:acme-corp.com:agent:invoice-processor-staging-eu
This removes any implict "default" and the client must pick explicitly.
If you want a "generic" or default then you could go for either adding a default entry to the catalog, or you could have a top level catalog which includes the "default" entries for different types and add a nested catalog for when you want to go to more specific endpoints.
The key point is that once a client has selected urn:air:acme-corp.com:agent:invoice-processor-staging-eu you can alway re-discover the same catalog entry.
There was a problem hiding this comment.
Thank you for your feedback @Tehsmash . In my original proposal, this was indeed part of the entry rather than an extension. At the time, I received feedback that it should be instead be modeled as an extension in order to keep the specification simple.
More than happy to switch back if that's the consensus. We must be careful not to introduce any backwards compatibility issues in the process though
There was a problem hiding this comment.
What I described is still an extension, its just that it uses the catalog entries as the list, then added deployment metadata on each specific entry.
Summary
This PR resolves #64
(structured deployment metadata) by adding an official extension —
https://ai-catalog.org/extensions/deployment— rather than a nativeinstancesfield on the Catalog Entry as the original proposal suggested.A Catalog Entry conflates identity ("what the artifact is") with instance
("where it lives"). The same logical agent or server is routinely deployed
many times — across environments (development, staging, production), across
release channels (stable, beta, LTS, edge), and across regions (
us-east-1,eu-west-1) whose data-residency and compliance constraints differ. Theentry's
identifierand top-levelurlcapture the artifact and its defaultentry point but cannot express these deployments. The extension lets a
publisher enumerate them on an entry so a consumer can deterministically
select an instance that satisfies its policy — an EU client targeting a GDPR
instance in
eu-west-1, a test harness targetingstaging, or a clientopting into a
betarelease channel — while the entry keeps a single logicalidentity.
Because the extension is additive and unrecognized
extensionskeys areignored, it needs no
specVersionchange — a catalog carrying it remainsa conformant
1.0document.Changes Included
adr/0022-deployment-metadata-extension.md(new) — records thedecision to implement Spec Proposal: Deployment metadata #64 as an official extension rather than a native
entry field, consistent with the closed-core philosophy of
ADR-0012.
specification/ai-catalog.md:metadata.(a REQUIRED, non-empty
instances[]array), the Instance object(
instanceIdandurlREQUIRED;environment,releaseChannel,region,dataResidency,compliance,descriptionOPTIONAL),selection semantics with a no-unsafe-fallback rule, and an example.
disclosure and unsigned producer assertions.
(
docs/examples/deployment-metadata.md), an authoring section inCreating a Catalog, an instance-selection section in Consuming
Catalogs, plus cross-links and a nav entry.
Reconciling the original proposal
The proposal in #64 predates several current conventions; the extension uses
today's forms:
urn:ai:…urn:air:{publisher}:{namespace}:{name}(ADR-0015)instancesfield on the entryextensionsentry (keeps the core schema closed)complianceas a bare string ("GDPR")complianceas a string array, matchingdataResidencyand allowing multiple regimesenvironment(dev/staging/production) kept distinct from a newreleaseChanneltrack (stable/beta/LTS/edge), since canary is a release strategy, not an environment tierDesign notes
same
identifier; instances are deployments, not distinct artifacts. Theentry's top-level
urlremains the default entry point, and one instanceurlSHOULD equal it so the default is represented among the instances.environmentandreleaseChannelare orthogonal.environmentdescribes where a version runs;
releaseChanneldescribes the maturitytrack of the deployed version. Keeping them separate avoids overloading
environmentwith release-strategy values.dataResidencyandcomplianceare unsigned producer assertions unless carried in a signedTrust Manifest; a consumer that needs assurance MUST corroborate them via
attestations, not via this extension.
an instance matching its policy; if none matches it SHOULD treat the
artifact as unavailable for that request rather than fall back to a
non-conforming instance — an EU-only client never silently uses a non-EU
deployment.
Interoperability impact
No change to interoperability expectations for existing catalogs. The core
schema, CDDL for core types, conformance levels, and
specVersionare allunchanged; a consumer that does not implement the extension ignores it without
error, exactly as for any unrecognized
extensionskey.Non-goals
is discovery metadata only; the entry's
urland each instanceurlremainordinary references.
extension per ADR-0012 / ADR-0022.
compliance/dataResidencyas enforceable guarantees —they are producer assertions, verified (when needed) through the Trust
Manifest.
Validation
uv run --locked python tools/build_spec.py specification/ai-catalog.md dist/index.html --config specification/respec-config.json— passes.uv run --python 3.12 --locked --group docs mkdocs build --strict— passes, no broken links.