Files
timmy-config/docs/nostr_agent_research.md
Alexander Whitestone c0603a6ce6 docs: Nostr agent-to-agent encrypted comms research + working demo
Proven: encrypted DM sent through relay.damus.io and nos.lol, fetched and decrypted.
Library: nostr-sdk v0.44 (pip install nostr-sdk).
Path to replace Telegram: keypairs per wizard, NIP-17 gift-wrapped DMs.
2026-04-04 12:48:57 -04:00

193 lines
6.7 KiB
Markdown

# Nostr Protocol for Agent-to-Agent Communication - Research Report
## 1. How Nostr Relays Work for Private/Encrypted Messaging
### Protocol Overview
- Nostr is a decentralized protocol based on WebSocket relays
- Clients connect to relays, publish signed events, and subscribe to event streams
- No accounts, no API keys, no registration - just secp256k1 keypairs
- Events are JSON objects with: id, pubkey, created_at, kind, tags, content, sig
### NIP-04 (Legacy Encrypted DMs - Kind 4)
- Uses shared secret via ECDH (secp256k1 Diffie-Hellman)
- Content encrypted with AES-256-CBC
- Format: `<encrypted_base64>?iv=<iv_base64>`
- P-tag reveals recipient pubkey (metadata leak)
- Widely supported by all relays and clients
- GOOD ENOUGH for agent communication (agents don't need metadata privacy)
### NIP-44 (Modern Encrypted DMs)
- Uses XChaCha20-Poly1305 with HKDF key derivation
- Better padding, authenticated encryption
- Used with NIP-17 (kind 1059 gift-wrapped DMs) for metadata privacy
- Recommended for new implementations
### Relay Behavior for DMs
- Relays store kind:4 events and serve them to subscribers
- Filter by pubkey (p-tag) to get DMs addressed to you
- Most relays keep events indefinitely (or until storage limits)
- No relay authentication needed for basic usage
## 2. Python Libraries for Nostr
### nostr-sdk (RECOMMENDED)
- `pip install nostr-sdk` (v0.44.2)
- Rust bindings via UniFFI - very fast, full-featured
- Built-in: NIP-04, NIP-44, relay client, event builder, filters
- Async support, WebSocket transport included
- 3.4MB wheel, no compilation needed
### pynostr
- `pip install pynostr` (v0.7.0)
- Pure Python, lightweight
- NIP-04 encrypted DMs via EncryptedDirectMessage class
- RelayManager for WebSocket connections
- Good for simple use cases, more manual
### nostr (python-nostr)
- `pip install nostr` (v0.0.2)
- Very minimal, older
- Basic key generation only
- NOT recommended for production
## 3. Keypair Generation & Encrypted DMs
### Using nostr-sdk (recommended):
```python
from nostr_sdk import Keys, nip04_encrypt, nip04_decrypt, nip44_encrypt, nip44_decrypt, Nip44Version
# Generate keypair
keys = Keys.generate()
print(keys.public_key().to_bech32()) # npub1...
print(keys.secret_key().to_bech32()) # nsec1...
# NIP-04 encrypt/decrypt
encrypted = nip04_encrypt(sender_sk, recipient_pk, "message")
decrypted = nip04_decrypt(recipient_sk, sender_pk, encrypted)
# NIP-44 encrypt/decrypt (recommended)
encrypted = nip44_encrypt(sender_sk, recipient_pk, "message", Nip44Version.V2)
decrypted = nip44_decrypt(recipient_sk, sender_pk, encrypted)
```
### Using pynostr:
```python
from pynostr.key import PrivateKey
key = PrivateKey() # Generate
encrypted = key.encrypt_message("hello", recipient_pubkey_hex)
decrypted = recipient_key.decrypt_message(encrypted, sender_pubkey_hex)
```
## 4. Minimum Viable Setup (TESTED & WORKING)
### Full working code (nostr-sdk):
```python
import asyncio
from datetime import timedelta
from nostr_sdk import (
Keys, ClientBuilder, EventBuilder, Filter, Kind,
nip04_encrypt, nip04_decrypt, Tag, NostrSigner, RelayUrl
)
RELAYS = ["wss://relay.damus.io", "wss://nos.lol"]
async def main():
# Generate 3 agent keys
timmy = Keys.generate()
ezra = Keys.generate()
bezalel = Keys.generate()
# Connect Timmy to relays
client = ClientBuilder().signer(NostrSigner.keys(timmy)).build()
for r in RELAYS:
await client.add_relay(RelayUrl.parse(r))
await client.connect()
await asyncio.sleep(3)
# Send encrypted DM: Timmy -> Ezra
msg = "Build complete. Deploy approved."
encrypted = nip04_encrypt(timmy.secret_key(), ezra.public_key(), msg)
builder = EventBuilder(Kind(4), encrypted).tags([
Tag.public_key(ezra.public_key())
])
output = await client.send_event_builder(builder)
print(f"Sent to {len(output.success)} relays")
# Fetch as Ezra
ezra_client = ClientBuilder().signer(NostrSigner.keys(ezra)).build()
for r in RELAYS:
await ezra_client.add_relay(RelayUrl.parse(r))
await ezra_client.connect()
await asyncio.sleep(3)
dm_filter = Filter().kind(Kind(4)).pubkey(ezra.public_key()).limit(10)
events = await ezra_client.fetch_events(dm_filter, timedelta(seconds=10))
for event in events.to_vec():
decrypted = nip04_decrypt(ezra.secret_key(), event.author(), event.content())
print(f"Received: {decrypted}")
asyncio.run(main())
```
### TESTED RESULTS:
- 3 keypairs generated successfully
- Message sent to 2 public relays (relay.damus.io, nos.lol)
- Message fetched and decrypted by recipient
- NIP-04 and NIP-44 both verified working
- Total time: ~10 seconds including relay connections
## 5. Recommended Public Relays
| Relay | URL | Notes |
|-------|-----|-------|
| Damus | wss://relay.damus.io | Popular, reliable |
| nos.lol | wss://nos.lol | Fast, good uptime |
| Nostr.band | wss://relay.nostr.band | Good for search |
| Nostr Wine | wss://relay.nostr.wine | Paid, very reliable |
| Purplepag.es | wss://purplepag.es | Good for discovery |
## 6. Can Nostr Replace Telegram for Agent Dispatch?
### YES - with caveats:
**Advantages over Telegram:**
- No API key or bot token needed
- No account registration
- No rate limits from a central service
- End-to-end encrypted (Telegram bot API is NOT e2e encrypted)
- Decentralized - no single point of failure
- Free, no terms of service to violate
- Agents only need a keypair (32 bytes)
- Messages persist on relays (no need to be online simultaneously)
**Challenges:**
- No push notifications (must poll or maintain WebSocket)
- No guaranteed delivery (relay might be down)
- Relay selection matters for reliability (use 2-3 relays)
- No built-in message ordering guarantee
- Slightly more latency than Telegram (~1-3s relay propagation)
- No rich media (files, buttons) - text only for DMs
**For Agent Dispatch Specifically:**
- EXCELLENT for: status updates, task dispatch, coordination
- Messages are JSON-friendly (put structured data in content)
- Can use custom event kinds for different message types
- Subscription model lets agents listen for real-time events
- Perfect for fire-and-forget status messages
**Recommended Architecture:**
1. Each agent has a persistent keypair (stored in config)
2. All agents connect to 2-3 public relays
3. Dispatch = encrypted DM with JSON payload
4. Status updates = encrypted DMs back to coordinator
5. Use NIP-04 for simplicity, NIP-44 for better security
6. Maintain WebSocket connection for real-time, with polling fallback
### Verdict: Nostr is a STRONG candidate for replacing Telegram
- Zero infrastructure needed
- More secure (e2e encrypted vs Telegram bot API)
- No API key management
- Works without any server we control
- Only dependency: public relays (many free ones available)