Skip to main content

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 CLIpython -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:

  1. Generates an ed25519 identity on first run
  2. Listens on a TCP port
  3. Announces capabilities (e.g. "analyst", "web-search")
  4. Discovers other nodes via shared tracker or manual peers
  5. Exchanges signed messages (tasks, results, events)

Private Tracker

For 3+ nodes or nodes behind NAT/Docker (no public port), use a private tracker:

  1. Pick an always-online node as tracker (e.g. SAM at TRACKER_IP:7878)
  2. Run examples/python/tracker.py on it
  3. All other nodes connect via peers=["<tracker-ip>:7878"]
  4. 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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

elo_node-0.6.0.tar.gz (33.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

elo_node-0.6.0-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file elo_node-0.6.0.tar.gz.

File metadata

  • Download URL: elo_node-0.6.0.tar.gz
  • Upload date:
  • Size: 33.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for elo_node-0.6.0.tar.gz
Algorithm Hash digest
SHA256 39a04dfb7ab60d2c1501d9a77be257b62cb2e4ba5499e1679b472e2aa5e8f383
MD5 46f7189ca19a7574817481b22faa04b0
BLAKE2b-256 d7660495d2cd67bee742ebef6d16118bc9394b8c721914c8f7f43ed1373c1590

See more details on using hashes here.

File details

Details for the file elo_node-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: elo_node-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 30.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for elo_node-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e847cb57d5c93cb5e9721e0165d8d0487690068b892166a3947090f44792f656
MD5 073fc428dd73eeb7d2742d270d82af56
BLAKE2b-256 589fdb0d148a6ed8c53a9a0e8b190a7828ec8ce28b48fba59c6811e2b8248ce7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page