# klieo-a2a

Durable A2A v1.0 protocol layer atop klieo-bus traits.

Part of the [klieo](https://crates.io/crates/klieo) Rust agent framework.

## Quickstart — laptop-dev

```toml
[dependencies]
klieo-a2a = { version = "2", features = ["test-fixtures"] }
```

```rust
use std::sync::Arc;
use klieo_a2a::{A2aDispatcher, handler::EchoHandler};

# fn run() {
let dispatcher = A2aDispatcher::local(Arc::new(EchoHandler::default()));
# let _ = dispatcher; }
```

`A2aDispatcher::local(handler)` bakes in `AllowAnonymous` + a fresh
in-process `MemoryBus` pubsub. Gated behind the `test-fixtures`
feature (CWE-1188): production builds without the feature cannot reach
the permissive authenticator. For production wire your own
`Authenticator` via `A2aDispatcher::builder()` (see HTTP/SSE section
below).

## Cargo features

| Feature | Default | Purpose |
|---|---|---|
| `http` | off | HTTP/SSE transport per A2A v1.0 §9.4.2 (single `POST /a2a` endpoint). See HTTP/SSE section below. |
| `conformance` | off | Exposes `pub mod conformance` — the conformance test suite + harness `cargo-klieo` consumes. |
| `test-fixtures` | off | Exposes `EchoHandler` (no-auth in-mem) for the conformance suite. Activates `klieo-auth-common/test-fixtures` so `AllowAnonymous` is reachable. **Never** in production. |

## Status

`2.x` — stable. See [`docs/SEMVER.md`](https://github.com/mohrimic/klieo/blob/main/docs/SEMVER.md).

## HTTP/SSE transport

`klieo-a2a` ships an HTTP/SSE transport behind the `http`
cargo feature. Single `POST /a2a` endpoint per A2A v1.0
§9.4.2 with JSON-or-SSE response negotiation based on
JSON-RPC method.

```toml
[dependencies]
klieo-a2a = { version = "2", features = ["http"] }
klieo-auth-common = "2"
```

```rust
use klieo_auth_common::AllowAnonymous;
use klieo_a2a::handler::EchoHandler;
use klieo_a2a::http::A2aHttpServer;
use klieo_a2a::task_store::A2aTaskStore;
use klieo_a2a::A2aDispatcher;
use std::sync::Arc;
use tokio_util::sync::CancellationToken;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let dispatcher = Arc::new(
        A2aDispatcher::builder()
            .handler(Arc::new(my_handler()))
            .authenticator(Arc::new(AllowAnonymous))
            .with_in_process_pubsub()
            .build()?,
    );
    let kv = my_kv_store();
    let task_store = Arc::new(
        A2aTaskStore::new(kv, klieo_a2a::task_store::DEFAULT_BUCKET.into())
            .with_event_sink(dispatcher.event_sink()),
    );
    let cancel = CancellationToken::new();

    let server = Arc::new(A2aHttpServer::new(dispatcher, task_store, cancel));
    server.serve_http("127.0.0.1:8080".parse()?).await?;
    Ok(())
}
```

**Streaming methods.** `SendStreamingMessage` and
`SubscribeToTask` return `text/event-stream`; all other
methods return `application/json`.

**Security boundary.** The HTTP layer adds no authentication
beyond what the configured `Authenticator` enforces on the
JSON-RPC payload. Bind `127.0.0.1` and front with an
auth-enforcing reverse proxy for any non-localhost
deployment. Plain HTTP only — terminate TLS at the proxy.

See [`docs/adr/adr-013-a2a-http-sse-transport.md`](../../docs/adr/adr-013-a2a-http-sse-transport.md)
for the design rationale and out-of-scope items.

## License

MIT — see [`LICENSE`](https://github.com/mohrimic/klieo/blob/main/LICENSE).
