Elo — malha P2P de mensagens para agentes de IA. Zero infraestrutura.
Project description
Elo Node — P2P Message Mesh for AI Agents
Zero infrastructure. One process. One TCP port. One ed25519 key.
Elo is a decentralized P2P message mesh for communication between AI agents. No central server, no Kafka, no Redis, no NATS. Just direct TCP between nodes.
pip install elo-node
import asyncio
from elo import Node
async def main():
node = Node("my-agent", port=7878, peers=["TRACKER_IP:7878"])
await node.connect()
await node.register(agents=["analyst"], tools=["web-search"])
@node.on_task
async def handle(task):
return {"result": f"processed by {node.node_id}"}
await node.run()
asyncio.run(main())
Features
- Decentralized P2P — discovery via public tracker or Kademlia DHT
- ed25519 signatures — cryptographic identity, authenticated messages
- Capabilities — publish/subscribe of agent skills across the mesh
- Relay via tracker — nodes behind NAT/Docker communicate through a tracker
- Zero infra — no Kafka, Redis, NATS, or central server
- Native CLI —
python -m elo serve,status,init,id
CLI
python -m elo status # Node ID, hash, keys
python -m elo id # Just the node_id
python -m elo pubkey # Public key (hex + b64)
python -m elo init # Generate persistent identity
python -m elo serve # Start an interactive node
Quick Start
1. Connect to a tracker
⚠️ peers= is required for outbound connections. Without it the node only listens.
node = Node("agent-1", port=7878, peers=["TRACKER_IP:7878"])
await node.connect()
On HELLO handshake with a tracker (v0.4.4+), known peers are automatically exchanged — new nodes are discovered on connect.
2. Register capabilities
await node.register(agents=["ping", "analyst"], tools=["web-search"])
3. Send tasks
# Auto-fallback: direct → InterestTable → QUERY → tracker relay → NO_PEER
result = await node.send_task("", "ping", {"msg": "hello"})
# → Result(status="success", payload={...})
4. Discover peers
# Peers with full handshake
known = node.get_known_peers()
# Broadcast QUERY across the mesh (returns node_id + addresses)
peers = await node.discover_peers_network(timeout=5.0)
# Legacy (local-only, deprecated)
local = await node.discover_peers()
5. Relay through tracker (NAT/Docker)
# Explicit relay for NAT'd nodes
result = await node.send_task_via_tracker(
tracker_node="",
target="sauron-elo",
capability="ping",
payload={"msg": "hello"},
)
Architecture
┌──────────────────┐ TCP/JSON ┌──────────────────┐
│ Node A │◄──────────────►│ Node B │
│ ed25519 key │ │ ed25519 key │
│ Capabilities │ │ Capabilities │
│ Interests │ │ Interests │
└──────────────────┘ └──────────────────┘
│ │
│ Tracker (optional) │
└────────────── DHT ───────────────┘
Each node:
- Generates an ed25519 identity on first run
- Listens on a TCP port
- Announces capabilities (e.g. "analyst", "web-search")
- Discovers other nodes via shared tracker or manual peers
- Exchanges signed messages (tasks, results, events)
Private Tracker
For 3+ nodes or nodes behind NAT/Docker (no public port), use a private tracker:
- Pick an always-online node as tracker (e.g. SAM at
TRACKER_IP:7878) - Run
examples/python/tracker.pyon it - All other nodes connect via
peers=["<tracker-ip>:7878"] - The tracker relays tasks between nodes automatically
# Client node
node = Node("my-node", port=0, peers=["TRACKER_IP:7878"])
Stale peer prevention (v0.4.10)
When a node restarts (Docker, VM reboot) with the same identity but a different port, the tracker previously kept the stale entry — tasks could fail with "Peer not connected".
Fixed in v0.4.10: the tracker now removes any existing peer entry matching the same node_id prefix on HELLO, before registering the new connection. Identity stays persistent (ed25519 key), port stays dynamic — both preserved.
Changelog
| Version | Highlights |
|---|---|
| 0.4.10 | Stale peer fix — tracker removes old entry on reconnection with same identity, different port |
| 0.4.9 | node_id included in discover_peers_network() response |
| 0.4.8 | send_task() routing fix — correctly falls back to tracker relay when target is offline |
| 0.4.7 | Rate limiting, result signing, broadcast loop fix |
| 0.4.6 | Documentation update, __version__ fix |
| 0.4.5 | Multi-response discover, tracker returns all peers on query |
| 0.4.4 | HELLO_ACK with known_peers, send_task auto-fallback tracker |
| 0.4.3 | Relay via tracker, send_task_via_tracker() |
| 0.4.2 | discover_peers() fix, get_known_peers() API |
| 0.4.0 | Initial release |
Compatibility
- Python 3.11+
- Linux, macOS, Windows
Development
git clone https://github.com/andreocc/elo
cd elo/py
pip install -e ".[dev]"
pytest
Related Projects
- Hermes Agent — autonomous agent runtime
- Honcho — persistent memory for agents
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file elo_node-0.5.0.tar.gz.
File metadata
- Download URL: elo_node-0.5.0.tar.gz
- Upload date:
- Size: 28.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77bc857473db275636544755d0691ed744711d83971ed3e3df9747d64761f4e4
|
|
| MD5 |
f106078d731f44e1e2c4dcee78374390
|
|
| BLAKE2b-256 |
77c596d7b0b240842020a4bf8a56f395bbb57f69e9b9442a62491e71ab04f511
|
File details
Details for the file elo_node-0.5.0-py3-none-any.whl.
File metadata
- Download URL: elo_node-0.5.0-py3-none-any.whl
- Upload date:
- Size: 25.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fba00daf9213dac5553d8fe6c107385dfc921aad8973f599bc07dee7b7b3abb0
|
|
| MD5 |
5ccc264b8e5864b69f93f46436b27c63
|
|
| BLAKE2b-256 |
0f34b2fae4a6556d5d9c8fd4199e5b7b7c24ed560de0d658e94e021304cd241e
|