4.4 KiB
4.4 KiB
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
- Nostr relay is live and serving WebSocket connections on port 2929
- Event signing via coincurve schnorr works (raw Python)
- pynostr Event class can create and sign events
- websockets library can connect to relay (ws://127.0.0.1:2929 on VPS)
- 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:
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:
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)
# 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:
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:
- Add
~/.timmy/nostr/nostr_sender.py— imports coincurve, websockets - In Hermes tools: replace
send_telegram_message()withsend_nostr_message() - Morning report cron calls the Nostr sender
- 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