Update A2A Protocol Specification
Follow these steps to update the TCK after an A2A protocol specification change.
Step 1: Capture the current state
Before updating, record what we have now so we can diff later.
- Read
specification/version.jsonto note the current commit hash. - Save copies of the key spec files for diffing:
specification/specification.mdspecification/a2a.proto
Step 2: Download the updated specification
Ask the user if they want to update from the main branch or pass a tag or a commit cheksum
Run:
make spec
This executes scripts/update_spec.sh, which downloads the latest spec files from the upstream a2aproject/A2A GitHub repository and updates specification/version.json.
If updating from a fork or a different branch, pass arguments:
./scripts/update_spec.sh --org <org> --branch <branch>
Step 3: Regenerate gRPC stubs and JSON schema
Skip this step if specification/a2a.proto did not change (diff shows no proto changes).
gRPC stubs
Run:
make proto
This executes scripts/generate_grpc_stubs.sh, which uses buf to regenerate specification/generated/a2a_pb2.py and specification/generated/a2a_pb2_grpc.py from the updated a2a.proto.
If buf is not installed, first run ./scripts/install_buf.sh.
After regenerating, check the protobuf version in the generated stubs (head -5 specification/generated/a2a_pb2.py) and verify it is compatible with the protobuf runtime version installed in the project (see pyproject.toml). If the gencode version is newer than the runtime allows, pin the plugin versions in specification/buf.gen.yaml to a compatible release (e.g., buf.build/protocolbuffers/python:v30.2).
JSON schema
Ask the user for the path to their local googleapis checkout, then run:
PATH="$HOME/go/bin:$PATH" GOOGLEAPIS_DIR=<path-to-googleapis> make jsonschema
This regenerates specification/a2a.json from the updated a2a.proto. It requires:
protoc-gen-jsonschema, installed viago install github.com/bufbuild/protoschema-plugins/cmd/protoc-gen-jsonschema@latestGOOGLEAPIS_DIRset to the user's local googleapis checkout
IMPORTANT: Never edit specification/a2a.json manually — always regenerate it from the proto.
Step 4: Analyze specification changes
Compare the old and new versions of the specification to identify changes:
Diff
specification/specification.mdto find:- New operations or endpoints
- Changed request/response schemas
- New or modified MUST/SHOULD/MAY requirements
- Removed or deprecated features
Diff
specification/a2a.prototo find:- New or changed message types
- New or changed RPC methods
- New or changed fields
Summarize the changes for the user before proceeding.
Step 5: Update transport bindings and requirements
Based on the spec diff, update the relevant files in tck/requirements/:
base.py- Core enums (OperationType, HTTP methods, error codes) and base classescore_operations.py- Core operation requirements (CORE-OPS-*)binding_grpc.py- gRPC-specific requirements (GRPC-*)binding_jsonrpc.py- JSON-RPC-specific requirements (JSONRPC-*)binding_http_json.py- HTTP+JSON-specific requirements (HTTP_JSON-*)data_model.py- Data model requirementsstreaming.py- Streaming requirementspush_notifications.py- Push notification requirementsagent_card.py- Agent card requirementsauth.py- Authentication requirementsversioning.py- Versioning requirementsinterop.py- Interoperability requirements
For each spec change:
- If a new requirement is added, create a new requirement entry with the appropriate ID prefix and level (MUST/SHOULD/MAY).
- If a requirement is modified, update the existing entry.
- If a requirement is removed, remove the entry and note it.
Summarize the changes for the user before proceeding.
Step 6: Update transport clients and validators
If the spec changes affect transport-level behavior:
- Transport clients are in
tck/transport/ - Response validators are in
tck/validators/tck/validators/error_info.py— shared ErrorInfo validation for JSON-RPC and HTTP+JSON (ProtoJSON@typeformat)tck/validators/grpc/error_validator.py— gRPC ErrorInfo extraction (binary protobuf)tck/validators/http_json/error_validator.py— AIP-193 error format parsingtck/validators/jsonrpc/error_validator.py— JSON-RPC error code validationtck/validators/error_binding.py— cross-transport expected-error validation
Step 7: Update or add conformance tests
Tests are in tests/compatibility/:
core_operations/- Cross-transport parametrized testsgrpc/- gRPC-specific testsjsonrpc/- JSON-RPC-specific testshttp_json/- HTTP+JSON-specific testsagent_card/- Agent card tests (discovery, caching, signing)
Each test class uses markers from tests/compatibility/markers.py (@grpc, @jsonrpc, @http_json, @core, @must, @should, @may).
Tests use helpers from tests/compatibility/_test_helpers.py:
get_client()— get transport client with skip-on-missing handlingrecord()— record result to compatibility collectorfail_msg()— format assertion message with requirement context
Tests record results with:
compatibility_collector.record(requirement_id, transport, level, passed, errors)
When writing tests, prefer using transport clients (client.get_task(), client.cancel_task(), etc.) over raw HTTP calls. Only use raw httpx calls when the test needs custom headers (e.g., A2A-Version), invalid methods, malformed payloads, or wrong Content-Type.
Step 8: Validate
Run the linter and unit tests:
make lint
make unit-test
Fix any issues before proceeding. Common failures after a spec update:
- Proto package namespace changes (e.g.,
a2a.v1tolf.a2a.v1) can break unit tests that assert on fully-qualified proto type names. Search for hardcoded package names intests/unit/. - Proto package namespace changes also affect
$refvalues in the regenerated JSON schema (e.g.,a2a.v1.Task.jsonschema.json→lf.a2a.v1.Task.jsonschema.json). The$refmapping intck/validators/json_schema.pymust support the new prefix, otherwise nested schema validation silently passes (refs resolve to permissive fallbacks). - Protobuf runtime version mismatches (see Step 3).
Step 9: Audit requirements
Before committing, audit all requirement files to verify:
- Each requirement's
sectionfield matches the correct section in the updated specification. - Each requirement's
spec_urlanchor resolves to the right heading. - No requirements reference sections or content that was removed or renamed.
- Any new MUST/SHOULD/MAY requirements in the spec have corresponding entries.
To verify anchors programmatically, note that GitHub strips dots and special characters from heading text when generating anchors. For example, heading #### 3.1.1. Send Message produces anchor #311-send-message (not #3.1.1.-send-message). The SPEC_BASE constant in base.py is specification/specification.md#, and the _spec_url_to_href() function in html_formatter.py converts these to absolute GitHub URLs using the commit hash from version.json.
Highlight any new, modified, or removed requirements for the user.
Step 10: Summarize
Present the user with a summary of:
- The old and new spec commit hashes (from
specification/version.json) - What changed in the specification
- What was updated in the TCK (requirements, tests, transport code)
- Any areas that need manual review or additional test coverage