messaggero
A Rust library for building high-performance multi-agent systems with a protocol designed around two complementary transport modes: a binary fast path for agents running on the same host, and an A2A-compatible HTTP transport for cross-vendor interoperability.
Motivation
Multi-agent AI systems introduce a new class of latency: the overhead of passing tasks, messages, and results between agents. Existing Rust crates either implement the A2A standard over HTTP/JSON-RPC (good for interoperability, slower for local communication) or provide proprietary binary protocols (fast, but isolated from the broader ecosystem). messaggero combines both approaches in a single library.
When two agents run on the same machine, messaggero uses a length-prefixed bincode frame over a Unix domain socket, reducing serialization and transport overhead to the microsecond range. When communicating with external or third-party agents, the same API switches automatically to JSON-RPC 2.0 over HTTP, following the Agent-to-Agent (A2A) protocol specification maintained by the Linux Foundation with support from Google, AWS, Microsoft, and 150+ organizations.
Design Principles
- The
Agenttrait is the only contract an implementor must satisfy. Everything else is opt-in through feature flags and middleware. - The router selects the transport automatically based on how each agent endpoint was registered. The application code is identical regardless of whether the target agent is local or remote.
- Types used on the wire (
TaskRequest,TaskResponse,Message,Part,Artifact,AgentCard) mirror the A2A v1.0 data model. An agent exposed over the A2A transport can be discovered and called by any compliant client. - The middleware pipeline follows a chain-of-responsibility pattern. Logging,
authentication, rate-limiting, and retry logic are composable layers that wrap
any
Agentimplementation without modifying it. - Binary serialization uses bincode exclusively on the fast path.
serde_json::Valueis deliberately absent from wire types to avoiddeserialize_anyincompatibility with non-self-describing formats.
Transport Comparison
| Fast Path | A2A Path | |
|---|---|---|
| Wire format | bincode | JSON-RPC 2.0 |
| Transport | Unix domain socket | HTTP (axum) |
| Overhead | microseconds | milliseconds |
| Interoperability | Rust-to-Rust | Any A2A-compliant agent |
| Discovery | In-process registry | /.well-known/agent.json |
Project Structure
| Path | Role |
|---|---|
src/core/ |
Wire types, Agent trait, middleware pipeline, codec, JSON-RPC types |
src/transport/ |
Fast path server/client, A2A HTTP server/client, router, discovery |
examples/ |
Runnable examples (ping_pong, multi_agent) |
demos/ |
Optional demos (Ollama pipeline, audit logging) — not published to crates.io |
Quick Start
use *;
;
async
Feature Flags
| Flag | Default | Enables |
|---|---|---|
fast |
yes | Unix socket + bincode fast path |
a2a |
yes | HTTP/JSON-RPC A2A-compatible transport |
transport-log |
no | Async transport audit logger (see below) |
full |
no | All of the above |
Transport Audit Logging
The optional transport-log feature provides a non-blocking, rotating JSON log
of every task request processed by the library. It is disabled by default and
has zero overhead when absent (all logging code is compiled out via #[cfg]).
Enabling
[]
= { = "0.1", = ["transport-log"] }
No additional dependencies are required — the timestamp formatting is implemented without third-party crates.
What is logged
A [LogEntry] is written for every task request, on both the server and client side:
| Field | Description |
|---|---|
ts |
ISO-8601 UTC timestamp with microsecond precision |
transport |
"fast" or "a2a" |
direction |
"inbound" (server) or "outbound" (client) |
task_id |
Task UUID from the request/response |
duration_us |
Elapsed microseconds (round-trip for clients, handler time for servers) |
status |
"ok" or "error" |
error |
Error description (only present when status == "error") |
payload_bytes |
Serialised payload size in bytes (when measurable) |
Log file format
Files are written as NDJSON (one JSON object per line) to the configured directory, rotating every 1 000 entries (configurable):
/var/log/myapp/transport/
├── transport-2026-06-08T09-51-00.123456Z.ndjson # 1 000 entries
├── transport-2026-06-08T09-52-01.456789Z.ndjson # current file
Example lines:
How it works
Logging is fully asynchronous: the transport hot path calls
mpsc::Sender::try_send (non-blocking) and a dedicated Tokio task drains the
channel and performs all file I/O. If the channel fills up, entries are
silently dropped — the transport latency is never affected.
Usage
use ;
// Build the logger (spawns the background writer task)
let logger = builder
.log_dir // required
.max_entries // default: 1 000 entries per file
.channel_capacity // default: 4 096 queued entries
.build
.await?;
// Server-side: logs every inbound task (both fast and A2A)
serve
.fast
.http
.with_transport_logger
.run
.await?;
// Router (client-side): logs every outbound dispatch
let router = new.with_transport_logger;
// FastClient (client-side): logs outbound fast-path calls
let client = connect.await?
.with_logger;
// MessaggeroClient (unified client): attach after connecting
let client = connect_fast
.await?
.with_transport_logger;
Examples
# Ping-pong between two agents via fast transport
# Multi-agent pipeline with router and discovery
# Full demo with Ollama (requires ollama + qwen3.5:4b)
Testing
# Run the full test suite (unit + integration + doc tests)
# Run integration tests only
Benchmarks
# Transport throughput + serialization benchmarks
Results are written to target/criterion/ as HTML reports.
Status
Early development. The wire format and public API are not yet stable. The crate follows semantic versioning; breaking changes will be indicated by a major version bump once the 1.0 milestone is reached.
Contributions, issue reports, and protocol feedback are welcome.
License
Licensed under either of:
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.