# 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`
