Skip to content
All posts
· 13 min read ·

A2A 1.0 is stable. Compatibility moved into the SDKs.

The core specification has not moved since v1.0.1 in May. Late-July SDK releases fixed legacy cards, signing, v0.3 wire handling, task isolation and push SSRF, showing where A2A interoperability is still being defined in practice.

The latest release of the core A2A specification is still v1.0.1, published May 28. It was a small corrective release: prefer application/a2a+json for the HTTP binding, align transcoding errors, and fix the documented TaskStatus values. The protocol has not added another feature release since.

The implementation layer tells a busier story. Between July 22 and July 28, the official Python, JavaScript and Go SDKs shipped fixes for legacy Agent Cards, v0.3 wire compatibility, signing canonicalization, cross-tenant task access, push-notification SSRF and background-task teardown. These are not speculative roadmap features. They are corrections at the boundaries where independently built agents have to agree.

That distinction matters. A stable specification can have an unstable compatibility surface. A2A has reached the point where the interesting changes are no longer new nouns in the protocol. They are the cases that decide whether two nominally compliant implementations can safely complete a task together.

One protocol, at least four compatibility surfaces

A2A v1.0 deliberately separates its common semantic model from three standard bindings: JSON-RPC, gRPC and HTTP+JSON/REST. The specification requires implementations that expose multiple bindings to offer functionally equivalent operations, results, errors and authentication. It also introduced explicit version negotiation and a compatibility path from v0.3.

That architecture is sound, but it turns conformance into a matrix rather than a checkbox.

Where A2A compatibility is moving SPEC CONTRACT JULY SDK FAULT LINE PUBLIC FIELD

Versioning Major.Minor negotiation Legacy normalization v0.3 REST wire support 905 legacy cards 215 declare 1.0

Signing JCS plus field presence Same payload both ways sign to verify round-trip 42 signed cards out of 3,928 valid

Task isolation auth scope is external Cross-tenant checks per-user task authorization Not card-testable requires active probes

Push and lifecycle SSRF-safe callbacks Safe defaults, clean close durable producer failure Long-running behavior needs lifecycle probes

The late-July release notes map almost exactly onto those four surfaces.

1. Version negotiation is still a dual-parser problem

The versioning rules are stricter than many cards in the wild. Protocol versions use Major.Minor, so 1.0 is valid while patch forms such as 1.0.0 should not be emitted or influence negotiation. Clients send an A2A-Version header; a missing or empty value is treated as v0.3 for backward compatibility.

The JavaScript SDK's v1.0.1 release fixed both the v0.3 context builder and normalization of legacy cards in createFromAgentCard. The Go SDK's v2.4.0 release implemented the v0.3 REST wire format and fixed gRPC compatibility with v0.3 SDKs. Two official implementations had to harden their compatibility layers four months after the 1.0 release.

The public field explains why. In Agenstry's August 1 registry snapshot, 3,928 cards pass structural validation. Only 1,277 expose a value that our crawler classifies as a protocol version. Of those, 905 declare 0.3 or 0.3.0; 215 declare the specification-correct 1.0; and 38 use patch forms 1.0.0 or 1.0.1. The remaining values include older releases and malformed or unrelated version schemes.

This is not a clean measure of protocol traffic. It is a measure of published metadata, and discovery sources can duplicate or lag deployments. But it is enough to reject the assumption that the public ecosystem has converged on v1.0. A production client still needs to read v0.3 and v1.0, while a new server should emit only v1.0.

There is a second warning in the same snapshot: 384 agents produce a conforming live response, while 1,365 answer a probe with the wrong shape. A card parser alone cannot tell you whether the advertised endpoint speaks its claimed binding and version.

2. Signing depends on representation, not just cryptography

A2A card signing uses JSON Web Signatures over a JCS-canonicalized Agent Card. The hard part is not choosing an algorithm. The hard part is deriving exactly the same payload. A field that was omitted is not necessarily equivalent to one present with a default value, and the signatures field itself is excluded from the signed payload.

The JavaScript SDK's July release fixed a direct version of this failure: signing and verification did not always canonicalize the same payload. A signature can be mathematically sound and still fail interoperability because the two sides did not serialize the same semantic object.

Only 42 of the 3,928 valid cards in our snapshot advertise a signature. Low adoption limits the observed blast radius today, but it also makes weak implementations harder to detect. The minimum useful signing test is not "did the SDK produce a JWS?" It is a cross-implementation round trip: sign in one official SDK, verify in another, repeat with optional fields omitted, explicitly defaulted, reordered and unknown fields present.

3. A task ID is an authorization boundary

The core protocol models task state, but intentionally does not define the scope, lifetime or revocation semantics of the authorization obtained during an AUTH_REQUIRED task state. Those controls remain the application's responsibility.

Recent SDK changes show the consequence. Go v2.4.0 added cross-tenant authorization checks when reading task and push-configuration stores. Java v1.1.0.Final added an SPI for per-user task authorization. These are not cosmetic framework hooks. In a multi-tenant A2A server, an opaque task ID must not become a bearer credential that lets one caller retrieve another caller's work, history or callback configuration.

This class of conformance cannot be inferred from an Agent Card. It needs an adversarial active test: create a task as tenant A, then attempt every task and push-config operation as tenant B. Repeat across each advertised binding. Equivalent APIs should fail equivalently, without revealing whether the target task exists.

4. Long-running tasks expose failures that request-response tests miss

The Python SDK's v1.1.2 release added aclose() to drain active background tasks, fixed pending tasks being destroyed during teardown, and persisted an early producer failure as FAILED with its originating message. Go v2.4.0 made push-sender SSRF protection the default and fixed event serialization so messages survive a queue round trip.

These bugs sit beyond a successful sendMessage response. They appear when a worker shuts down, a producer fails before its first event, a queued event is reloaded, or an agent calls a user-supplied webhook. The A2A specification explicitly tells push senders to reject private, loopback and link-local callback targets, because a callback feature is otherwise an SSRF primitive.

A useful verifier therefore has to exercise time, storage and network policy. It should interrupt a stream, restart a worker, replay the task, test callback redirects and DNS rebinding defenses, and confirm that terminal failure remains observable. A green synchronous probe is necessary, but it is not evidence that the task lifecycle is durable or safe.

SDK versions are not protocol versions

The naming now creates an avoidable source of confusion. The protocol's latest release is v1.0.1, but version negotiation still advertises 1.0 because patch numbers do not belong on the wire. Meanwhile the official SDKs have independent release numbers: JavaScript v1.0.1, Python v1.1.2 and Go v2.4.0 in the releases discussed here.

Those three numbers answer different questions:

  • Protocol version: which wire semantics does this interface speak?
  • SDK version: which implementation fixes and APIs are installed?
  • Agent version: which release of the agent's own behavior is deployed?

Registries and observability systems should store them separately. Normalizing 1.0.0 into 1.0 can help route a request, but the raw value should be retained as evidence of an implementation defect. The same applies to the advertised binding, observed content type, negotiated version and actual response shape.

What good A2A verification now requires

The A2A roadmap names the Inspector and Technology Compatibility Kit as the ecosystem's validation efforts. They are the right baseline. The SDK fixes suggest the next layer of tests that production operators need around them:

  1. Dual-read, single-write versioning. Accept the supported v0.3 compatibility surface, emit v1.0, and send A2A-Version explicitly.
  2. Binding equivalence. Run the same task corpus over every advertised binding and compare state transitions, artifacts, errors and authorization behavior.
  3. Cross-SDK signing. Round-trip signed cards across languages with field-presence edge cases, rather than testing one serializer against itself.
  4. Tenant-negative tests. Attempt task, history, subscription and push-config access from a different principal.
  5. Lifecycle and SSRF tests. Restart workers mid-task, persist early failures, follow callback redirects and block internal network targets.
  6. Observed-versus-advertised reporting. Keep a card's claims separate from probe evidence and timestamp both.

This is the encouraging interpretation of the July releases: A2A is no longer changing mainly because its designers are adding concepts. It is changing because implementations are meeting real compatibility and security edges. The less encouraging interpretation is that protocolVersion: "1.0" remains a weak proxy for interoperability.

The next meaningful A2A milestone is not another headline version. It is when legacy traffic falls below v1.0 traffic, wrong-shape responses stop outnumbering conforming ones, and the SDK bugs above become permanent cross-language TCK cases. That is when "supports A2A" starts to mean the same thing on both sides of a task.

Sources

Cite this post

@misc{agenstry-a2a-sdk-compatibility-2026,
  author       = {Semler, Damiën},
  title        = {A2A 1.0 is stable. Compatibility moved into the SDKs.},
  howpublished = {Agenstry research blog},
  year         = {2026},
  month        = {aug},
  url          = {https://agenstry.com/blog/a2a-compatibility-moved-into-sdks}
}
← Back to blog Agenstry