# A2A
[](https://hex.pm/packages/a2a)
[](https://hexdocs.pm/a2a)
[](https://github.com/actioncard/a2a-elixir/actions/workflows/ci.yml)
[](LICENSE)
[](CONTRIBUTING.md)
Elixir implementation of the [Agent-to-Agent (A2A) protocol](https://google.github.io/A2A/) — a standard for AI agents to communicate over JSON-RPC 2.0.
A2A gives you behaviour-based agents that run as GenServer processes. Define an agent, serve it over HTTP, or call remote agents — all with idiomatic Elixir patterns.
> **Pre-release**: This library is under active development. The API may change before 1.0.
> [!NOTE]
> This project is developed with _significant_ AI assistance (Claude, Copilot, etc.)
## Features
- **Behaviour-based agents** — `use A2A.Agent` generates a full GenServer with task lifecycle management
- **Multi-turn conversations** — continue tasks with `task_id` for stateful back-and-forth
- **Streaming** — return `{:stream, enumerable}` from agents; SSE over HTTP
- **HTTP serving** — `A2A.Plug` handles agent card discovery, JSON-RPC dispatch, and SSE streaming
- **HTTP client** — `A2A.Client` for discovering and calling remote A2A agents
- **Agent registry** — `A2A.Registry` for skill-based agent discovery
- **Supervision** — `A2A.AgentSupervisor` starts a fleet of agents with one call
- **Pluggable storage** — `A2A.TaskStore` behaviour with built-in ETS implementation
## Quick Start
```elixir
# Define an agent
defmodule MyAgent do
use A2A.Agent,
name: "my-agent",
description: "Does things"
@impl A2A.Agent
def handle_message(message, _context) do
{:reply, [A2A.Part.Text.new("Got: #{A2A.Message.text(message)}")]}
end
end
# Start and call it
{:ok, _pid} = MyAgent.start_link()
{:ok, task} = A2A.call(MyAgent, "hello")
```
Agents return `{:reply, parts}`, `{:input_required, parts}`, or `{:stream, enumerable}` from `handle_message/2`. The runtime handles task creation, state transitions, and history.
## Serving over HTTP
`A2A.Plug` exposes your agent as an A2A-compliant HTTP endpoint with agent card discovery and JSON-RPC dispatch.
```elixir
# Standalone with Bandit
{:ok, _pid} = MyAgent.start_link()
Bandit.start_link(
plug: {A2A.Plug, agent: MyAgent, base_url: "http://localhost:4000"}
)
# Or in a Phoenix router
forward "/a2a", A2A.Plug,
agent: MyAgent, base_url: "http://localhost:4000/a2a"
```
The agent card is served at `GET /.well-known/agent-card.json` by default.
## Calling Remote Agents
`A2A.Client` discovers and communicates with remote A2A agents over HTTP. Requires the `req` optional dependency.
```elixir
# Discover an agent
{:ok, card} = A2A.Client.discover("https://agent.example.com")
# Send a message
client = A2A.Client.new(card)
{:ok, task} = A2A.Client.send_message(client, "Hello!")
# Stream a response
{:ok, stream} = A2A.Client.stream_message(client, "Count to 5")
Enum.each(stream, &IO.inspect/1)
```
All functions also accept a URL string directly: `A2A.Client.send_message("https://agent.example.com", "Hello!")`.
## Multi-Turn & Streaming
Continue an existing task by passing `task_id`:
```elixir
{:ok, task} = A2A.call(MyAgent, "order pizza")
# task.status.state => :input_required
{:ok, task} = A2A.call(MyAgent, "large", task_id: task.id)
```
For streaming agents, return `{:stream, enumerable}` and consume with `A2A.stream/3`:
```elixir
{:ok, task, stream} = A2A.stream(MyAgent, "research topic")
stream |> Stream.each(&process/1) |> Stream.run()
```
## Supervision & Registry
Start a fleet of agents with a shared registry for skill-based discovery. The current registry is a minimal in-memory implementation covering basic lookup and skill-based routing — production use cases with many agents may warrant a custom registry backed by persistent storage.
```elixir
{:ok, _sup} =
A2A.AgentSupervisor.start_link(
agents: [MyApp.PricingAgent, MyApp.RiskAgent, MyApp.SummaryAgent]
)
# Find agents by skill tag
A2A.Registry.find_by_skill(A2A.Registry, "finance")
#=> [MyApp.PricingAgent, MyApp.RiskAgent]
```
## Installation
Add `a2a` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:a2a, "~> 0.1.0"}
]
end
```
### Optional Dependencies
Include only what you need:
```elixir
def deps do
[
{:a2a, "~> 0.1.0"},
# For serving A2A endpoints
{:plug, "~> 1.16"},
{:bandit, "~> 1.5"},
# For calling remote A2A agents
{:req, "~> 0.5"}
]
end
```
## Examples
The [`examples/`](https://github.com/actioncard/a2a-elixir/tree/main/examples) directory contains runnable scripts:
- **[`demo.exs`](https://github.com/actioncard/a2a-elixir/blob/main/examples/demo.exs)** — local agents: simple call, multi-turn, and streaming
- **[`client_server.exs`](https://github.com/actioncard/a2a-elixir/blob/main/examples/client_server.exs)** — full HTTP client/server with Bandit and `A2A.Client`
- **[`supervisor_demo.exs`](https://github.com/actioncard/a2a-elixir/blob/main/examples/supervisor_demo.exs)** — `A2A.AgentSupervisor`, registry, and skill-based routing
Run any example with:
```bash
mix run examples/demo.exs
```
## Development
```bash
# Fetch dependencies
mix deps.get
# Run tests
mix test
# Run the full quality suite (format + credo + dialyzer)
mix quality
# Run checks individually
mix format --check-formatted
mix credo --strict
mix dialyzer
```
Requires Elixir ~> 1.17.
### TCK (Protocol Compliance)
The [A2A TCK](https://github.com/a2aproject/a2a-tck) is the official compliance test suite for the A2A protocol. It runs against a live server and validates protocol conformance.
**Prerequisites:** [uv](https://docs.astral.sh/uv/) (Python package manager)
```bash
# Run mandatory compliance tests (clones TCK on first run)
bin/tck mandatory
# Run all categories
bin/tck all
# Available categories: mandatory, capabilities, quality, features, all
```
To run the server manually (e.g. for debugging):
```bash
# Default port 9999
mix run test/tck/server.exs
# Custom port
A2A_TCK_PORT=8080 mix run test/tck/server.exs
```
The TCK runs on every PR in CI. Reports are uploaded as build artifacts.
## Roadmap
See [SPEC.md](SPEC.md) for protocol coverage and implementation status.
## Links
- [A2A Protocol Specification](https://google.github.io/A2A/)
- [Hex Package](https://hex.pm/packages/a2a)
- [Documentation](https://hexdocs.pm/a2a)
## License
Apache-2.0 — see [LICENSE](LICENSE).