Skip to content

Design: index-time federation via a change feed of identifiers (GET /changes) #96

Description

@kperry-godaddy

Problem

ARD federates only at query time (§5.4): a hub fans a search out to every upstream and merges (auto) or refers the client to them (referrals). Latency is the slowest upstream, a complete answer needs every upstream with nothing to mark a partial one, score values share no scale so hubs merge by rank (#87), every query costs N upstream queries, and Explore never federates (§5.3.3). In #88, each of four public registries answered auto from its own catalogue. Nothing lets a registry learn what another holds before a query arrives. Crawling (§5.2) gives one index, but a crawler cannot know which publisher domains exist or when they changed.

Proposal

One optional endpoint, GET /changes: an ordered, cursor-driven, replayable feed of the identifiers a registry added, updated, or removed, and nothing else. A consumer that learns an identifier fetches the entry from the identifier's authority and confirms every delete there. For a domain identifier that means resolving the URN's publisher domain and crawling its §5.1 sources exactly as §5.2 ingestion does today; the feed only says which domain to visit and when, never what the entry contains. The feed says what exists and what changed; the authority says what it says. A registry emits only what it fetched and admitted itself, so loops converge without a hop list. Optional, 501 like Explore.

Wire shape

GET {base}/changes?cursor=0192f3a1-7c4e-7d21-9f0a-1b2c3d4e5f60&limit=500
{
  "changes": [
    { "cursor": "0192f3a1-7c50-…", "op": "upsert", "time": "2026-09-11T14:02:12Z", "identifier": "urn:air:acme.com:server:weather" },
    { "cursor": "0192f3a1-7c52-…", "op": "delete", "time": "2026-09-11T14:02:13Z", "identifier": "urn:air:example.com:weather-server" }
  ],
  "cursor": "0192f3a1-7c52-…",
  "more": false,
  "retention": "P30D"
}

Cursors are opaque (equality only). Delivery is at-least-once, latest change per identifier. retention is a window that must contain the whole frontier, so a new consumer with no cursor replays it once and holds every live identifier, with no snapshot endpoint and no 410 mid-replay. A delete is a hint: when the confirming fetch fails, the consumer keeps the entry and re-checks with back-off, so a delete cannot be timed to an outage.

Identifiers whose authority is not a domain

The same feed can carry AGNTCY Agent Directory records and Agent Name Service registrations if the URN form selects how to resolve and verify. Two reserved first segments, no schema change:

  • urn:air:<fqdn>:…, domain: a §5.1 source on the domain
  • urn:air:<agentHost>:ans:<mcp|a2a|http-api>, ANS: _ans-badge.<agentHost> resolves to a live transparency-log badge; the card is at the sealed metaDataUrl
  • urn:air:<registry-fqdn>:cid:<cid>, content: the original record hashes to the CID; signature verified

A registry that forwards an entry keeps its identifier; a registry that assigns one uses its own domain or a publisher domain it has verified. Otherwise the same agent gets a different identifier in each system. One gap: §4.5.1 requires trustManifest.identity to match the URN's publisher domain, and in urn:air:<registry-fqdn>:cid:… that domain is the registry's while the signer is the record's publisher. Either §4.5.1 gains a clause for this form, or the registry puts its own identity in trustManifest.identity. Whatever wording settles #94 should say which reading applies here.

Prior work

DNS NOTIFY and IXFR (RFC 1996, 1995): a hint, confirmed with and transferred from the primary. The AGNTCY Agent Directory announces records to a DHT and syncs them between instances, with no durable withdrawal signal. The Agent Name Service's transparency log exposes an event stream. CouchDB _changes and sitemap pings share the shape.

Questions

  1. Is a feed of identifiers, with no entry payload, the right v1?
  2. Optional with 501 like Explore, required for public registries, or optional in the core and SHOULD for public registries?
  3. Retention: a sliding window with the frontier re-emitted inside it, indefinite retention with no 410, or producer's choice? What floor for the window?
  4. How long does an entry outlive an authority that stays unreachable? §5.2 says nothing for crawled entries today, and the feed inherits whatever ARD answers.
  5. Operators of existing registries (Reference implementation: Neuronto — federated ARD registry (federation: auto + RRF) #87, Field data: urn:ai: vs urn:air: at scale, media-type fragmentation, and live-registry conformance #88, Open-source reference implementation: MCP Gateway Registry (Apache-2.0) — both Catalog Publisher and Registry #40, How should /.well-known/ai-catalog.json behave when backed by a live, permissioned registry (not a static file)? #79): would you implement it, and what does your index lack today?

Related: #63, #45, #47, #24, #78, #89, #91, #92, #93, #94, PR #74; Agent-Card/ai-catalog #102; agntcy/dir #1678.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions