Skip to content

Commit f186819

Browse files
committed
feat: add examples, AI discoverability, and architecture assets
- Add llms.txt and .cursorrules for AI coding assistant discoverability - Add 5 runnable examples: hello-world (Python+TS), CrewAI, LangGraph, MCP bridge, skill discovery - Add architecture SVG diagram and terminal demo SVG animation - Enhance README with comparison table, badges, emoji features, public roadmap, and examples index
1 parent bc6940f commit f186819

17 files changed

Lines changed: 724 additions & 0 deletions

File tree

.cursorrules

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# AgentAnycast
2+
3+
AgentAnycast is a decentralized P2P runtime for the A2A (Agent-to-Agent) protocol.
4+
5+
## Architecture
6+
- Sidecar model: Go daemon (libp2p) handles P2P networking, Python/TypeScript SDKs communicate via gRPC over Unix socket
7+
- Security: Noise_XX end-to-end encryption, Ed25519 keys, DID:key identity
8+
- NAT traversal: AutoNAT + DCUtR + Circuit Relay v2
9+
- Discovery: DHT (Kademlia) + Relay skill registry
10+
11+
## Quick Usage
12+
13+
Python:
14+
```python
15+
from agentanycast import Node, AgentCard, Skill
16+
17+
card = AgentCard(name="MyAgent", skills=[Skill(id="echo", description="Echo")])
18+
async with Node(card=card) as node:
19+
@node.on_task
20+
async def handle(task):
21+
await task.complete(artifacts=[{"parts": [{"text": "Hello!"}]}])
22+
await node.serve_forever()
23+
```
24+
25+
TypeScript:
26+
```typescript
27+
import { Node } from "agentanycast";
28+
const node = new Node({ card: { name: "MyAgent", skills: [{ id: "echo", description: "Echo" }] } });
29+
await node.start();
30+
node.onTask(async (task) => { await task.complete([{ parts: [{ text: "Hello!" }] }]); });
31+
await node.serveForever();
32+
```
33+
34+
## Three addressing modes
35+
- `peer_id="12D3KooW..."` — direct P2P
36+
- `skill="translate"` — anycast routing by capability
37+
- `url="https://..."` — HTTP bridge to standard A2A agents
38+
39+
## Framework adapters
40+
- CrewAI: `from agentanycast.adapters.crewai import serve_crew`
41+
- LangGraph: `from agentanycast.adapters.langgraph import serve_graph`
42+
- MCP: `from agentanycast.mcp import mcpToolToSkill, skillToMcpTool`
43+
44+
## Repos
45+
- agentanycast-python: Python SDK (pip install agentanycast)
46+
- agentanycast-ts: TypeScript SDK (npm install agentanycast)
47+
- agentanycast-node: Go daemon
48+
- agentanycast-relay: Relay server
49+
- agentanycast-proto: Protobuf definitions

docs/assets/architecture.svg

Lines changed: 118 additions & 0 deletions
Loading

docs/assets/demo.svg

Lines changed: 86 additions & 0 deletions
Loading

examples/01-hello-world/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Hello World
2+
3+
The simplest AgentAnycast example — two agents communicating over encrypted P2P.
4+
5+
## Python
6+
7+
```bash
8+
pip install agentanycast
9+
10+
# Terminal 1 — start the echo agent
11+
python server.py
12+
13+
# Terminal 2 — send it a message (copy PeerID from Terminal 1)
14+
python client.py 12D3KooW... "Hello, world!"
15+
```
16+
17+
## TypeScript
18+
19+
```bash
20+
npm install agentanycast tsx
21+
22+
# Terminal 1 — start the echo agent
23+
npx tsx server.ts
24+
25+
# Terminal 2 — send it a message (copy PeerID from Terminal 1)
26+
npx tsx client.ts 12D3KooW... "Hello, world!"
27+
```
28+
29+
## What Happens
30+
31+
1. The server starts a P2P node and registers the "echo" skill
32+
2. The client connects to the server by PeerID
33+
3. The message is sent over Noise_XX encrypted P2P
34+
4. The server echoes it back as an A2A artifact
35+
36+
Python and TypeScript agents can talk to each other — they share the same protocol.

examples/01-hello-world/client.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""Send a task to an echo agent.
2+
3+
Run:
4+
python client.py <PEER_ID> "Hello, world!"
5+
"""
6+
7+
import asyncio
8+
import sys
9+
from agentanycast import Node, AgentCard, Message, Part
10+
11+
12+
async def main():
13+
if len(sys.argv) < 3:
14+
print("Usage: python client.py <PEER_ID> <MESSAGE>")
15+
sys.exit(1)
16+
17+
peer_id, text = sys.argv[1], sys.argv[2]
18+
19+
card = AgentCard(name="Client")
20+
async with Node(card=card) as node:
21+
print(f"Sending to {peer_id}: {text!r}")
22+
23+
msg = Message(role="user", parts=[Part(text=text)])
24+
handle = await node.send_task(msg, peer_id=peer_id)
25+
result = await handle.wait(timeout=30)
26+
27+
reply = result.artifacts[0].parts[0].text
28+
print(f"Response: {reply}")
29+
30+
31+
if __name__ == "__main__":
32+
asyncio.run(main())

examples/01-hello-world/client.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Send a task to an echo agent.
3+
*
4+
* Run:
5+
* npx tsx client.ts <PEER_ID> "Hello, world!"
6+
*/
7+
8+
import { Node } from "agentanycast";
9+
10+
const [peerId, text] = process.argv.slice(2);
11+
if (!peerId || !text) {
12+
console.error("Usage: npx tsx client.ts <PEER_ID> <MESSAGE>");
13+
process.exit(1);
14+
}
15+
16+
const node = new Node({
17+
card: { name: "Client", skills: [] },
18+
});
19+
await node.start();
20+
21+
console.log(`Sending to ${peerId}: ${JSON.stringify(text)}`);
22+
23+
const handle = await node.sendTask(
24+
{ role: "user", parts: [{ text }] },
25+
{ peerId },
26+
);
27+
const result = await handle.wait(30_000);
28+
29+
const reply = result.artifacts[0]?.parts[0]?.text ?? "";
30+
console.log(`Response: ${reply}`);
31+
32+
await node.stop();

examples/01-hello-world/server.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""Minimal echo agent — the simplest possible AgentAnycast server.
2+
3+
Run:
4+
pip install agentanycast
5+
python server.py
6+
"""
7+
8+
import asyncio
9+
from agentanycast import Node, AgentCard, Skill, IncomingTask, Part
10+
from agentanycast.task import Artifact
11+
12+
13+
async def main():
14+
card = AgentCard(
15+
name="Echo Agent",
16+
description="Echoes back any message it receives.",
17+
skills=[Skill(id="echo", description="Echo the input")],
18+
)
19+
20+
async with Node(card=card) as node:
21+
print(f"Echo Agent started!")
22+
print(f" PeerID: {node.peer_id}")
23+
print(f" Skills: [echo]")
24+
print(f"\nWaiting for tasks... (Ctrl+C to stop)\n")
25+
26+
@node.on_task
27+
async def handle(task: IncomingTask):
28+
text = task.messages[-1].parts[0].text
29+
print(f" Received: {text!r}")
30+
await task.complete(
31+
artifacts=[Artifact(name="echo", parts=[Part(text=f"Echo: {text}")])]
32+
)
33+
print(f" Replied: Echo: {text!r}")
34+
35+
await node.serve_forever()
36+
37+
38+
if __name__ == "__main__":
39+
asyncio.run(main())

0 commit comments

Comments
 (0)