138 lines
4.4 KiB
Markdown
138 lines
4.4 KiB
Markdown
# Nostr Comms Pipeline — Integration Guide
|
|
|
|
## Status
|
|
- Nostr relay: **RUNNING** on relay.alexanderwhitestone.com:2929 (relay29/khatru29, NIP-29)
|
|
- Agent keys: **EXISTING** for timmy, claude, gemini, groq, grok, hermes, alexander
|
|
- Bridge: **RUNNING** nostr-bridge on Allegro VPS
|
|
- Group: **NOT YET CREATED** (khatru29 requires NIP-42 auth for writes)
|
|
|
|
## Architecture
|
|
|
|
```
|
|
Timmy Hermes Gateway → Nostr Client → Relay:2929 ← Alexander Phone (Damus)
|
|
↑
|
|
Other Wizards ← nostr_client.py
|
|
```
|
|
|
|
## What Works Right Now
|
|
1. Nostr relay is live and serving WebSocket connections on port 2929
|
|
2. Event signing via coincurve schnorr works (raw Python)
|
|
3. pynostr Event class can create and sign events
|
|
4. websockets library can connect to relay (ws://127.0.0.1:2929 on VPS)
|
|
5. Relay requires NIP-42 AUTH handshake for writes (khatru29 default)
|
|
|
|
## What's Blocked
|
|
- NIP-42 auth event signing: the relay returns `["AUTH", challenge]` but our signed 22242 events are rejected with "signature is invalid"
|
|
- The nostr-sdk Python bindings (v0.44.2) have incompatible API vs what the code expects
|
|
- pynostr's Event.sign() doesn't exist (uses pk.sign_event() instead)
|
|
- coincurve.sign_schnorr() works but the auth event format might not match what khatru29 expects
|
|
|
|
## How to Fix NIP-42 Auth (Next Session)
|
|
|
|
### Option 1: Disable AUTH requirement on the relay (quick but insecure)
|
|
On 167.99.126.228, add to relay29 options:
|
|
```go
|
|
relay.RequireNIP07Auth = false
|
|
// or
|
|
state.AllowEvent = func(context.Context, nostr.Event, string) (bool, string) {
|
|
return true, "" // allow all
|
|
}
|
|
```
|
|
|
|
### Option 2: Fix the auth event properly
|
|
The auth event (kind 22242) needs:
|
|
- content: the challenge string (NOT empty string)
|
|
- tags: [["relay", "relay.alexanderwhitestone.com:2929"]]
|
|
- The event is signed with the user's nsec
|
|
|
|
Python code that should work:
|
|
```python
|
|
from nostr.key import PrivateKey
|
|
pk = PrivateKey.from_nsec(nsec)
|
|
|
|
# Create auth event with challenge as CONTENT
|
|
evt = Event(
|
|
public_key=pk.hex(),
|
|
created_at=int(time.time()),
|
|
kind=22242,
|
|
content=challenge, # <-- this is the key
|
|
tags=[["relay", "relay.alexanderwhitestone.com:2929"]]
|
|
)
|
|
pk.sign_event(evt)
|
|
|
|
# Send as AUTH event (full event object, not just ID)
|
|
await ws.send(json.dumps(["AUTH", {
|
|
"id": evt.id,
|
|
"pubkey": evt.public_key,
|
|
"created_at": evt.created_at,
|
|
"kind": evt.kind,
|
|
"tags": evt.tags,
|
|
"content": evt.content,
|
|
"sig": evt.signature
|
|
}]))
|
|
```
|
|
|
|
### Option 3: Use the relay's admin key to create the group
|
|
The relay has an admin private key in the RELAY_PRIVKEY env var.
|
|
Can create the group via the relay's Go code by adding an admin-only endpoint.
|
|
|
|
## Group Creation (Once Auth Works)
|
|
|
|
```bash
|
|
# On the VPS, run this Python script
|
|
python3 -c "
|
|
import asyncio, json, time
|
|
import websockets
|
|
from nostr.key import PrivateKey
|
|
from nostr.event import Event
|
|
|
|
pk = PrivateKey.from_nsec('timmy-nsec-here')
|
|
|
|
async def create_group(code):
|
|
evt = Event(
|
|
public_key=pk.hex(),
|
|
created_at=int(time.time()),
|
|
kind=39000,
|
|
tags=[['d', code], ['name', 'Timmy Time'], ['about', 'The Timmy household']],
|
|
content=''
|
|
)
|
|
pk.sign_event(evt)
|
|
print(f'Group event: {evt.id[:16]}')
|
|
print(f'Group code: {code}')
|
|
|
|
asyncio.run(create_group('b082d1'))
|
|
"
|
|
```
|
|
|
|
## Adding Members to the Group
|
|
|
|
After the group is created, add members via kind 9 events with "h" tag:
|
|
```python
|
|
evt = Event(
|
|
public_key=pk.hex(),
|
|
created_at=int(time.time()),
|
|
kind=9,
|
|
tags=[['h', group_code], ['p', member_pubkey_hex]],
|
|
content='Welcome to Timmy Time'
|
|
)
|
|
pk.sign_event(evt)
|
|
```
|
|
|
|
## Wiring Hermes to Nostr
|
|
|
|
To replace Telegram sends with Nostr:
|
|
1. Add `~/.timmy/nostr/nostr_sender.py` — imports coincurve, websockets
|
|
2. In Hermes tools: replace `send_telegram_message()` with `send_nostr_message()`
|
|
3. Morning report cron calls the Nostr sender
|
|
4. Fallback: if Nostr relay unreachable, use Telegram
|
|
|
|
## Current Credentials
|
|
|
|
| Agent | npub | hex_pub |
|
|
|-------|------|---------|
|
|
| Timmy | npub1qwyndfwvwy4edlwgtg3jlssawg7aj36t78fqyk30ehtyd82j22nqzt5m94 | 038936a5cc712b96fdc85a232fc21d723dd9474bf1d2025a2fcdd6469d5252a6 |
|
|
| Claude | npub1s8rew66kl357hj20qth5uympp9yvj5989ye2grw0r9467eafe9ds7s2ju7 | 81c7976b56fc69ebc94f02ef4e13610948c950a72932a40dcf196baf67a9c95b |
|
|
| Gemini | npub1sy4sqms6559arup5lxquadzahevcyy5zu028d8rw9ez4h957j6yq3usedv | 812b006e1aa50bd1f034f981ceb45dbe59821282e3d4769c6e2e455b969e9688 |
|
|
|
|
Keys file: `~/.timmy/nostr/agent_keys.json`
|