# car-a2a
Agent2Agent (A2A) v1.0 bridge for [Common Agent Runtime](https://github.com/Parslee-ai/car).
## What it does
Exposes a CAR runtime as an A2A-compliant agent so peer agents — built on any A2A SDK (Python, JavaScript, Java, Go, .NET, or one of the Rust crates) — can discover the runtime via an Agent Card and submit work as A2A Tasks.
A2A is the Linux Foundation's open protocol for agent-to-agent interoperability. The full spec lives at <https://a2a-protocol.org/latest/specification/>.
## Mapping
| Agent Card | Manifest of registered tools + host metadata |
| Task | One-shot wrapper around an `ActionProposal` |
| Message (parts) | Free-form input from the peer; structured `data` parts become tool calls |
| Artifact | One per `ActionResult` returned by the runtime |
| `TaskState` SUBMITTED → WORKING → COMPLETED/FAILED | Lifecycle of `Runtime::execute` |
## Surface
| `A2aDispatcher` | Transport-neutral JSON-RPC dispatcher for the 11 A2A methods |
| `AgentCardSource` | Trait the dispatcher calls to (re)build the agent card on demand |
| `TaskStore` / `InMemoryTaskStore` | Pluggable task persistence |
| `message_to_proposal` | Compile an A2A `Message` into a CAR `ActionProposal` |
| `action_results_to_artifacts` | Convert a `ProposalResult` into A2A `Artifact`s |
## Methods supported
- `message/send`
- `tasks/get`
- `tasks/list`
- `tasks/cancel`
- `tasks/pushNotificationConfig/{set,get,list,delete}`
- `agent/getAuthenticatedExtendedCard`
Out of scope for this prototype:
- `message/stream` and `tasks/resubscribe` (Server-Sent Events)
- gRPC and HTTP+JSON/REST transport bindings
- Outbound A2A client calls — for those, use `a2a-protocol-client` or `a2a-client` from crates.io.
## Status
Prototype. The dispatcher is exercised by unit tests against an in-process `Runtime` and `InMemoryTaskStore`. It is not yet wired into `car-server-core::handler::run_dispatch` or fronted by an HTTP listener — embedders pick the transport.
## Example
```rust,ignore
use std::sync::Arc;
use car_a2a::{A2aDispatcher, AgentCard, InMemoryTaskStore};
use car_engine::Runtime;
let runtime = Arc::new(Runtime::new());
let store = Arc::new(InMemoryTaskStore::new());
let card_factory = Arc::new(|| AgentCard {
name: "CAR runtime".into(),
// ...fill in skills from runtime.tool_schemas() at refresh time
# version: "1.0.0".into(),
# description: String::new(),
# url: String::new(),
# provider: car_a2a::types::AgentProvider { organization: "you".into(), url: None },
# capabilities: car_a2a::AgentCapabilities::default(),
# default_input_modes: vec!["text".into()],
# default_output_modes: vec!["text".into()],
# skills: vec![],
# additional_interfaces: vec![],
# preferred_transport: Some("JSONRPC".into()),
# protocol_version: "1.0".into(),
# security_schemes: Default::default(),
# supports_authenticated_extended_card: false,
# security_requirements: vec![],
# signatures: vec![],
});
let dispatcher = A2aDispatcher::new(runtime, store, card_factory);
// A peer's JSON-RPC request:
let result = dispatcher
.dispatch("agent/getAuthenticatedExtendedCard", serde_json::Value::Null)
.await
.unwrap();
```