Guide
Building an ARD client
The required surface is one POST endpoint, which is why a useful client fits on one screen.
A client sends POST /search to any registry with a plain-language text query and an optional structured filter, ranks what comes back, verifies any trust manifest, and then connects to the resource over its own protocol. Every conformant registry must expose that endpoint, so one client works against all of them.
What a client has to do
Less than you would expect. There is one required endpoint, and the rest of the specification is about what you may do beyond it.
| Step | What it involves |
|---|---|
| Ask | POST /search with a query object. text is required, filter is optional. |
| Choose | Rank the returned entries. score is semantic relevance only and explicitly not a safety signal, so do not treat it as one. |
| Verify | If an entry carries a trustManifest, check it against the framework it declares before connecting. A client that skips this is the weak link in the chain. |
| Connect | Open the resource over its own protocol, using the artifact at url. ARD is finished at this point. |
The smallest useful client
import json, urllib.request
def discover(text, registry="https://neuronto.com", n=5):
body = json.dumps({"query": {"text": text}, "pageSize": n}).encode()
req = urllib.request.Request(
f"{registry}/search", data=body,
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req, timeout=10) as r:
return json.load(r).get("results", [])
for hit in discover("extract line items from a scanned invoice"):
print(hit["score"], hit["displayName"], hit["url"])
That is a complete ARD client. Point it at a different registry and it still works, because the search interface is the one thing every registry must expose. That guarantee is the reason the required surface is so small.
Filtering
text and filter compose: an entry matches if it is semantically
relevant AND satisfies every constraint. Within one key, values are ORed; across keys, ANDed.
{
"query": {
"text": "book a flight",
"filter": {
"type": ["application/a2a-agent-card+json"],
"tags": ["travel"],
"trustManifest.attestations.type": ["SOC2-Type2"]
}
},
"federation": "auto",
"pageSize": 5
}
Any term an entry carries can be a filter key, including namespaced terms you bind in the
query's @context. A registry that does not index a term you filter on may answer
400.
Federation, and what it does not mean
| Value | Behaviour | Cost |
|---|---|---|
auto (default) | The registry queries its upstreams and merges the results for you. One request, wider corpus. | Latency is whatever the slowest upstream costs, unless the registry bounds it. |
referrals | You get back a list of other registries to query yourself. | More round trips, but you control the fan-out and the timeouts. |
none | That registry's own index only. | Fastest. Often the right default for an interactive UI. |
A claim to be careful with. Federation means a registry may ask others when answering you. It does not mean your entry is copied into them. Each registry crawls independently. What actually reaches all of them is your manifest, sitting on your own domain where any of them can fetch it.
Practical advice
- Cache discovery. The answer to "which invoice parser" does not change between requests. Discover once per session, not once per turn.
- Bound the fan-out. If you use
auto, give the whole call a deadline you are willing to wait for. A federated search is only as fast as its slowest member. - Treat
scoreas relevance. The specification says in normative language that it is not a trust or safety rating. Your allowlist is still your allowlist. - Handle 405 correctly on your own endpoints too. If you build a registry, a POST-only route must answer 405 to a GET, never 404. A 404 tells an SDK client the endpoint does not exist. In our index, 558 of 8,543 introspected endpoints get this wrong.
Which registry to point at
Any of them, and the answer should be configurable rather than compiled in. The examples above
use Neuronto, which is run by the people who write this site and
is named for that reason as much as any other: it serves search at the path the specification
names, answers /explore and /agents, and publishes its own manifest, so a
client written against it is written against the spec rather than against one vendor's quirks.
The probe showing how each registry actually behaves is the honest way
to choose, and it does not flatter everybody equally.
Last reviewed 2026-09-04. Checked against ARD v0.91 (Proposal, 2026-08-26).