Why an agent publishes a card at all

The alternative to a card is out-of-band integration, and at small scale it works. A human reads your documentation, hardcodes the endpoint and the skill name, ships. That survives three integrations. It does not survive three hundred, and it does not survive a caller that is itself a model choosing at runtime among forty agents.

The card moves that knowledge from integration time to runtime. It is a late-binding mechanism: endpoint, skill names, argument shapes and credential requirements are resolved on the fly from a document at a predictable address, not from a wiki page transcribed into a constant six months ago. Three properties make it work: self-describing at a stable location, so no prior relationship is needed; machine-readable, so a router can choose without a human in the loop; versioned, so change is an observable event rather than a surprise.

The indirection is not free. You have added a network dependency to the critical path of every cold start, and a class of bug in which the implementation is correct and the advertisement is not. You are trading a human coordination problem for a distributed consistency problem, and the rest of this article is about that trade.

Advertisement

Where the card lives, and who is allowed to see it

By convention the card is served from a well-known path at the agent's origin - historically /.well-known/agent.json, more recently /.well-known/agent-card.json. Clients supporting both should try the newer path first and cache the negative result, so no session pays two round trips. covers the resolution rules.

The architectural consequence is that a well-known path is origin-scoped: one host, one agent. A fleet behind a single hostname needs path-scoped cards or a registry that maps an agent identifier to a card URL. What does not work is one card carrying the union of every agent's skills - you then cannot version, sign, or deprecate any of them independently.

Visibility is the other axis. The public card is what anyone may know, served without credentials. Many deployments also serve an extended card behind auth, listing privileged skills only entitled callers should be aware of; the public card advertises the auth scheme and points at it. Two rules follow: the public card must be fetchable unauthenticated, with permissive CORS if browser-resident clients exist, and it should be served from the same origin as the endpoint it advertises. A card on origin A whose endpoint points at origin B has the exact shape of a redirect-to-attacker.

Advertisement

The four layers of a card, and their different change rates

Read the diagram below as four layers rather than a flat bag of keys, because the layers change at different speeds and that mismatch causes most card operations pain.

Identity. Who the agent is, who runs it, where to complain, which terms apply. Changes almost never - a rebrand or a transfer of ownership.

Capability. What it can do, at two granularities: coarse protocol capabilities (streaming, push notifications) and fine business skills with descriptions, tags, and input and output schemas. Changes on roughly every feature release.

Contract. How to reach it - base URL, transport, auth scheme and required scopes, implementation version. Changes on migrations: rare, high blast radius.

Trust. The signature and the material a verifier needs to check it. Changes on key rotation, on a schedule unrelated to the product.

Because all four ship as one document under one ETag, a routine key rotation invalidates every client's cached skill list. That is tolerable when revalidation is cheap and intolerable when clients treat any card change as a reason to re-approve a counterparty. If card changes require human approval, diff the layers, not the bytes.

This section stops at the shape of the document. Key names, which fields are required, and the nested structure of a skill entry belong to .

Agent Ownerpublishes cardWell-Known URL/.well-known/agent.jsonDiscoveryclients fetchCard Contentsname, desc, capabilitiesAuth RequirementsOAuth scopes, mTLSSkills / Toolstyped schemasEndpointsservice address + transportVersioningsemver + compatSigningprovider signs cardRegistrypublic / private catalogCards are how one agent discovers what another can do
A2A agent card architecture: owner publishes at well-known URL, card lists capabilities/skills/endpoints/auth/versioning, signed by provider, registered in catalog.

From card to call - how a client turns an advertisement into an invocation

A client arrives with an intent and a card and must produce a request. Think of it as a three-stage funnel, because each stage fails differently.

Filter is the cheap, deterministic pass over hard constraints: is the transport one I speak, is the version inside my accepted range, can I obtain the scopes it demands, does it stream if my caller needs incremental output. Failures here are disqualified before a model is involved; this stage should never be probabilistic.

Rank is the semantic pass: which surviving skill matches a free-form intent. Here the card's prose is load-bearing. A skill description is prompt input for whatever router reads it, not marketing copy. State what the skill does, what inputs it expects, and what it does not do - negative scope ("text only; does not translate scanned images") eliminates more misroutes than another sentence of positive scope adds. Tags are the cheap prefilter that keeps a model off the hot path when the match is obvious. Scoring, thresholds and tie-breaking belong to skill matching; the card's job is to supply signal good enough to work on.

Bind is validating arguments against the advertised input schema locally, before anything crosses the network. Skipping it turns a client-side type error into a remote task that is accepted, queued, dispatched and only then failed - a round trip and an error path on someone else's system, for a mistake a local check catches in microseconds.

Caching a card, and the invalidation problem underneath it

Fetching the card per request is not viable: it adds a round trip to every interaction and makes the card host a hard availability dependency - if the document is unreachable, every new session fails even though the agent endpoint is healthy. So clients cache, and the moment they do you own an invalidation problem.

Use the HTTP layer rather than inventing a mechanism. Cache-Control: max-age states an intended propagation delay, not a performance knob; ETag with If-None-Match makes revalidation nearly free; stale-while-revalidate turns a slow card host into a background refresh instead of a failed session.

Cache-Control: public, max-age=600, stale-while-revalidate=3600
ETag: "card-2.4.1-9f3c1a"

The TTL tradeoff has real numbers at both ends. Sixty seconds means the card host serves traffic proportional to the session rate of every client in the ecosystem. Twenty-four hours means a day of skew after a deploy. Five to fifteen minutes with conditional revalidation is the usual settling point, and only safe alongside a publishing discipline: within a minor version a card may gain skills, never lose them. Additive-only change makes a stale reader out of date rather than wrong.

The mechanism that actually saves you is event-driven. Any response meaning "unknown skill", "version gone", or "scope no longer accepted" should trigger exactly one forced refetch and one retry, demoting the TTL from a correctness mechanism to a performance one. Single-flight the refetch per origin so a thousand concurrent sessions do not stampede the card host.

Trust - what a signature on a card does and does not prove

Signing a card - typically a detached JWS over a canonicalised serialisation - proves two narrow things: the document came from the holder of a particular key, and it has not been modified since, including by a registry or proxy re-serving a cached copy. The second property matters most once cards are mirrored in catalogs.

It proves nothing else. A signature does not say the agent behaves as described, that its skills are safe to invoke, or that the key belongs to the brand whose name appears in the name field. Signature is provenance; competence is a reputation problem and authorisation is an auth problem, and conflating either with a valid signature is how a verified card ends up authorising something nobody intended.

Key discovery is the hard part, and every option is a trust anchor in disguise. A JWKS on the same origin as the card is circular - whoever controls the origin controls both - so it protects only against tampering in transit. DNS-based discovery moves the anchor to your registrar; a vouching registry moves it to the registry operator. Internal deployments bottom out in an organisational CA; cross-organisation ones usually bottom out in trust-on-first-use with pinning: record origin and key fingerprint at onboarding, alert on change, require human approval. That catches the realistic attack - a hijacked subdomain re-serving a card whose endpoint points somewhere new.

One rule admits no exceptions: a client that falls back to accepting an unsigned card when verification fails has no security property, only a slower failure path. Fail closed, or do not sign. See trust models for how this composes across organisations.