Pre-alpha documentation
Serve A2A 1.0 without leaking wire types.
Expose HTTP+JSON and JSON-RPC/SSE through bounded StateKnot contracts, authorization-first policy, explicit admission, and a durable application interface.
Keep identity ahead of parsing
- Validate shutdown state, Host, Origin, path, content type, and body ceiling.
- Acquire process-local request capacity.
- Authenticate Bearer credentials before parsing the request body.
- Decode and validate the bounded A2A operation.
- Authorize the decoded operation before task or push-config lookup.
- Apply caller-owned, replica-wide quota admission.
- Execute the durable service and bound the unary response or full stream.
Agent Card discovery is the sole public route. It includes cache validators, and startup fails if its capabilities or interface URLs disagree with the mounted service.
One application contract, two bindings
| Surface | HTTP+JSON | JSON-RPC | Durable obligation |
|---|---|---|---|
| Send / get / list | Yes | Yes | Idempotency, tenant-scoped projection, stable cursors |
| Stream / subscribe | SSE | SSE | Snapshot then committed ordered events |
| Cancel | Yes | Yes | Durable intent and race-safe lifecycle fence |
| Push config CRUD | Yes | Yes | Encrypted secrets, egress policy, transactional outbox |
| Extended Agent Card | Yes | Yes | Authenticated caller-scoped projection |
StateKnot owns and bounds Agent Cards, messages, parts, tasks, artifacts, updates, and push configuration. The pinned official SDK remains a private wire adapter. Unknown fields are ignored as ProtoJSON requires; invalid enums, lifecycle combinations, versions, routes, media, and limits fail closed.
Build once at startup
let options = A2aServerHttpOptions::new()
.with_allowed_authorities(["agents.example.com"])?
.with_allowed_origins(["https://console.example.com"])?
.with_limits(1_048_576, 1_024, 512)?
.with_timeouts(Duration::from_secs(30), Duration::from_secs(60))?
.with_maximum_stream_events(16_384)?
.with_bearer_challenge("Bearer realm=\"stateknot-a2a\"")?;
let shutdown = CancellationToken::new();
let server = A2aServer::new(
card,
authenticator,
authorizer,
shared_admission,
durable_task_service,
options,
shutdown.clone(),
)?;
axum::serve(listener, server.router())
.with_graceful_shutdown(shutdown.cancelled_owned())
.await?;
Implement A2aServerAuthenticator, A2aServerAuthorizer,
A2aServerAdmissionControl, and A2aTaskService with
production infrastructure. TLS and trusted proxy termination stay outside this
router; configure the exact authority seen by the application.
Do not substitute process memory for durability
A production task service deduplicates message identity durably, maps opaque task IDs within one tenant, pages from a stable snapshot, streams committed journal evidence, commits cancellation intent, encrypts push credentials, rejects unsafe destinations, and delivers from a transactional at-least-once outbox. The repository's in-memory fixture exists only for deterministic TCK scenarios.
Read the full production checklist and the exact conformance boundary before exposing traffic or publishing compatibility claims.