A secure, LLM-first messaging protocol for agent-to-agent communication over QUIC.
Spec · Messages · Wire Format · IPC · Contributing
Every existing communication channel between AI agents was designed for humans:
- Chat protocols carry rich media, typing indicators, read receipts, and presence — none of which LLMs need, all of which cost tokens.
- HTTP/REST is stateless, unaware of sessions, and burdened with redundant headers.
- Platform-specific APIs lock agents into proprietary gateway layers.
AXON is purpose-built for agents talking to agents. It's structured, authenticated, resumable, and context-budget-aware — designed so that agents on the same local network (or across a VPN) can collaborate without wasting tokens on protocol overhead.
- Context-budget-aware — Every message costs tokens. The protocol minimizes unnecessary context consumption.
- Structured-first — No natural language overhead. Payloads are JSON, machine-parseable.
- Resumable — Agents restart frequently. AXON handles reconnection and peer rediscovery automatically.
- Minimal round-trips — Prefer rich single exchanges over chatty back-and-forth.
- Zero-trust locally — Agents authenticate even on LAN. Different agents have different access levels.
Agent ←→ [Unix Socket IPC] ←→ AXON Daemon ←→ [QUIC/UDP] ←→ AXON Daemon ←→ [Unix Socket IPC] ←→ Agent
Each machine runs a lightweight daemon (<5 MB RSS, negligible CPU when idle). Agents connect to it over a Unix socket and exchange structured JSON messages. The daemon handles everything else:
- Identity — Ed25519 keypair generated on first run.
identity.keystores a base64-encoded 32-byte seed. Agent ID derived from the public key. Self-signed X.509 cert for QUIC/TLS 1.3. - Discovery — mDNS on LAN (zero-config) or static peers in
config.tomlfor VPN/Tailscale setups. - Transport — QUIC with TLS 1.3 and forward secrecy.
- Security — Mutual TLS peer pinning — unknown peers rejected at the transport layer.
cd axon
cargo build --releaseThe binary is at axon/target/release/axon. Add it to your PATH or run it directly.
axon daemonStarts on port 7100, creates ~/.axon/ with a fresh Ed25519 identity, enables mDNS discovery, and listens for IPC on ~/.axon/axon.sock.
Use --state-root <DIR> (aliases: --state, --root) to override the state directory, or set AXON_ROOT.
If machines are on the same local network, mDNS handles everything automatically:
# Machine A # Machine B
axon daemon axon daemonWithin seconds they discover each other. Verify:
axon peersWhen mDNS isn't available, configure static peers:
# On each machine, get the identity:
axon identity
# → { "agent_id": "ed25519.a1b2c3d4...", "public_key": "base64..." }Create ~/.axon/config.toml on each machine with the other's info:
[[peers]]
agent_id = "ed25519.<peer-agent-id>"
addr = "<peer-host-or-ip>:7100"
pubkey = "<peer-public-key>"Then start:
axon daemon --disable-mdns# Send a request to another agent (bidirectional, waits for response)
axon send <agent_id> "What is the capital of France?"
# Fire-and-forget notification (unidirectional, JSON payload)
axon notify <agent_id> '{"state":"ready"}'
# Force literal text payload (even if it looks like JSON)
axon notify --text <agent_id> '{"state":"ready"'
# List peers
axon peers
# Daemon status
axon status
# Daemon identity (IPC)
axon whoami
# Local identity (state root files, no daemon required)
axon identity
# Diagnose local state (read-only report)
axon doctor
# Apply safe local repairs
axon doctor --fix
# Allow identity regeneration if key material is unrecoverable
axon doctor --fix --rekey
# See all commands
axon --help- Global state-root override is available on all commands:
--state-root <DIR>(aliases:--state,--root)- fallback order: CLI flag ->
AXON_ROOT->~/.axon
- Exit codes:
0: success1: local/runtime failure after argument parsing (I/O, daemon socket connect/decode, etc.)2: CLI parse/usage failure (Clap) or daemon/application-level failure reply ("ok": false)
- IPC inbound event delivery:
- connected clients receive inbound broadcast events
- per-client delivery uses bounded queues; lagging clients are disconnected instead of silently dropped
- Global verbosity override:
--verbose/-vsets default logging todebug(otherwise default isinfo)- if
RUST_LOGis explicitly set, it takes precedence over--verbose
- Doctor command behavior:
axon doctorruns local health checks and returns a JSON report (checks,fixes_applied,ok)axon doctor --fixapplies safe local repairs;--rekey(requires--fix) allows identity reset when key data is unrecoverable- returns exit code
2when unresolved check failures remain (ok: false)
axon examples # prints a full annotated example interaction| Kind | Stream | Purpose |
|---|---|---|
request |
Bidirectional | Send a request, get a response or error |
response |
Bidirectional | Reply to a request |
message |
Unidirectional | Fire-and-forget |
error |
Bidirectional or Unidirectional | Error reply or unsolicited error |
See spec/MESSAGE_TYPES.md for message kinds and stream mapping, and spec/WIRE_FORMAT.md for the normative wire format.
All settings are optional. AXON uses sensible defaults; you only need config.toml to configure static peers or override defaults.
Located at ~/.axon/config.toml by default (or <state_root>/config.toml when overridden).
| Key | Type | Default | Description |
|---|---|---|---|
name |
String |
(none) | Optional display name for this agent. |
port |
u16 |
7100 |
QUIC listen port. CLI --port overrides this. |
[[peers]]
agent_id = "ed25519.<hex>"
addr = "10.0.0.5:7100" # IP:port
# or
addr = "my-peer.example.net:7100" # hostname:port
pubkey = "<base64-encoded-ed25519-public-key>"Hostname peers are resolved at startup/config load time (IPv4 preferred). Unresolvable peers are skipped with warning logs.
These are compile-time constants and cannot be changed via configuration.
| Constant | Value | Location | Description |
|---|---|---|---|
MAX_MESSAGE_SIZE |
65536 (64 KB) |
message/envelope.rs |
Maximum encoded envelope size. Messages exceeding this are rejected. |
REQUEST_TIMEOUT |
30s |
transport/mod.rs |
Timeout for bidirectional request/response exchanges. |
STALE_TIMEOUT |
60s |
peer_table.rs |
Discovered (non-static, non-cached) peers with no activity for this duration are removed. |
MAX_IPC_LINE_LENGTH |
64 KB |
ipc/server.rs |
Maximum length of a single IPC command line. Overlong lines are rejected with command_too_large. |
MAX_CONNECTIONS |
128 |
daemon/mod.rs |
Maximum simultaneous QUIC peer connections. |
KEEPALIVE |
15s |
daemon/mod.rs |
QUIC keepalive interval. |
IDLE_TIMEOUT |
60s |
daemon/mod.rs |
QUIC idle timeout. Connections with no traffic for this duration are closed. |
INBOUND_READ_TIMEOUT |
10s |
daemon/mod.rs |
Maximum time to wait for data on an inbound QUIC stream. |
MAX_IPC_CLIENTS |
64 |
daemon/mod.rs |
Maximum simultaneous IPC client connections. |
MAX_CLIENT_QUEUE |
1024 |
daemon/mod.rs |
Per-IPC-client outbound message queue depth; overflow disconnects lagging clients. |
RECONNECT_MAX_BACKOFF |
30s |
daemon/mod.rs |
Maximum backoff between reconnection attempts. Backoff starts at 1s and doubles. |
| Save interval | 60s |
daemon/mod.rs |
How often the daemon persists known_peers.json to disk. |
| Stale cleanup interval | 5s |
daemon/mod.rs |
How often the daemon checks for and removes stale discovered peers. |
| Reconnect interval | 1s |
daemon/mod.rs |
How often the daemon checks for peers needing reconnection. |
| Initial reconnect backoff | 1s |
daemon/reconnect.rs |
First reconnect attempt delay after a connection failure. Doubles up to RECONNECT_MAX_BACKOFF. |
| Document | Description |
|---|---|
spec/SPEC.md |
Protocol architecture — QUIC, Ed25519, discovery, lifecycle |
spec/MESSAGE_TYPES.md |
Message kinds and stream mapping |
spec/WIRE_FORMAT.md |
Normative wire format for interoperable implementations |
spec/IPC.md |
IPC protocol — Unix socket commands |
CONTRIBUTING.md |
Development guide, module map, testing requirements |
rubrics/ |
Evaluation rubrics — quality, documentation, alignment |
SECURITY.md |
Security policy and vulnerability reporting |