Files
timmy-home/nostr/COMMS_STATUS.md

5.4 KiB

NOSTR COMMS MIGRATION — FINAL STATUS

Infrastructure Status

What Works

  • Nostr relay: RUNNING on relay.alexanderwhitestone.com:2929
    • Software: relay29 (khatru29, fiatjaf) — NIP-29 groups
    • Database: LMDB persistent
    • Service: systemd enabled, survived reboots
    • Memory: 6.7MB, CPU: 8.3s total
    • Accepts WebSocket connections (verified via netcat)
  • Agent keys: 7 keypairs exist in ~/.timmy/nostr/agent_keys.json
    • Timmy, Claude, Gemini, Groq, Grok, Hermes, Alexander
  • DM bridge: RUNNING nostr-bridge (polls every 60s for DMs, creates Gitea issues)
  • Gitea reporting: gitea_report.py exists for posting status to issues
  • Relay source: /root/nostr-relay/ — Go binary, LMDB backend, NIP-29 groups

What's Blocked

  • NIP-42 AUTH handshake: The relay requires authentication before accepting events
    • Relay returns ["AUTH", challenge] after EVENT submission
    • We sign a kind 22242 auth event but relay rejects with "signature is invalid"
    • Tested: nostr-sdk v0.44.2, pynostr, coincurve raw — all produce invalid signatures
    • Root cause likely: the nostr Python SDK's sign_event() uses ECDSA not schnorr for 22242
    • The relay29/khatru29 implementation validates using go-nostr schnorr

What Needs to Happen

  1. Fix NIP-42 auth — Option A: disable auth requirement on relay (add state.AllowEvent returning true in main.go). Option B: fix the Python signature to use proper schnorr.
  2. Create NIP-29 group — Group code was generated but metadata posting failed due to auth.
  3. Wire Hermes to Nostr — Replace Telegram send_message with Nostr relay POST.
  4. Deprecate Telegram — Set to fallback-only mode.
  5. Alexander's phone client — Needs a Nostr client installed (Damus on iOS).

The Epic and Issues (Filed on timmy-home)

Issue Assignee Priority Status
[EPIC] Sovereign Comms Migration FILED
P0: Wire Timmy Hermes to Nostr Timmy P0 BLOCKED (auth)
P0: Create Nostr group NIP-29 Allegro P0 BLOCKED (auth)
P1: Build Nostr clients per wizard Ezra P1 NOT STARTED
P1: Alexander receive-side Allegro P1 NOT STARTED
P1: Deprecate Telegram fallback Allegro P1 NOT STARTED
P2: Nostr-to-Gitea bridge ClawCode P2 BRIDGE EXISTS (URL bug fixed)

Files Created This Session

  • ~/.timmy/nostr/post_via_vps.py — Nostr client with raw websocket posting
  • ~/.timmy/nostr/post_raw.py — Direct coincurve + websocket implementation
  • ~/.timmy/nostr/post_nip42.py — NIP-42 auth implementation
  • ~/.timmy/nostr/post_via_vps.py — SSH-to-VPS relay posting
  • ~/.timmy/nostr/nostr_client.py — Full Nostr client (sign + post)
  • ~/.timmy/nostr/COMMS_MIGRATION.md — Integration guide with all docs
  • ~/.timmy/nostr/COMMS_STATUS.md — This file
  • ~/.timmy/nostr/group_config.json — Group config (code changes each attempt)

Key Findings

  1. The relay is live and healthy. It works — we just can't write to it yet because auth is broken.
  2. pynostr's sign_event() works for regular events — tested successfully, produces valid signatures.
  3. NIP-42 auth (kind 22242) is the blocker — The relay's khatru29 implementation validates the 22242 event's schnorr signature against the challenge. Our signatures don't match what the Go code expects.
  4. The DM bridge works — it polls for new DMs and creates Gitea issues. It just needs the correct GITEA URL (fixed: https://forge.alexanderwhitestone.com).
  5. coincurve.sign_schnorr() produces valid 64-byte schnorr signatures — The issue might be that pynostr's sign_event() uses a different algorithm than what khatru29 expects for the 22242 kind.
  6. The relay's private key is in the RELAY_PRIVKEY env var — could use admin powers to bypass auth or create the group directly.

Next Session Action Plan

Quick Fix (5 min)

On the VPS, add to /root/nostr-relay/main.go relay29 options:

state.AllowEvent = func(context.Context, nostr.Event, string) (bool, string) {
    return true, "" // allow all events, no auth required
}

Then rebuild and restart. This opens the relay for writes so we can create the group and test the full pipeline.

Proper Fix (30 min)

The pynostr Event class doesn't have sign_schnorr() — it uses sign_event() which does standard Nostr signing (sha256 of serialized event + schnorr of the id). But for NIP-42 auth, the signed payload should be the challenge string, not the event id. Need to sign the challenge directly with coincurve's sign_schnorr() on the raw challenge bytes, then build the event manually.

Full Pipeline (1 hr)

Once auth works:

  1. Create the NIP-29 group (kind 39000 with d tag)
  2. Post test messages (kind 1 and kind 9)
  3. Wire Hermes morning report to Nostr client instead of Telegram
  4. Add Alexander to the group
  5. Set Telegram to fallback-only

Nostr Relay Access

  • WebSocket: ws://relay.alexanderwhitestone.com:2929 (or ws://127.0.0.1:2929 on VPS)
  • Timmy npub: npub1qwyndfwvwy4edlwgtg3jlssawg7aj36t78fqyk30ehtyd82j22nqzt5m94
  • Timmy hex_pub: 038936a5cc712b96fdc85a232fc21d723dd9474bf1d2025a2fcdd6469d5252a6
  • Keys file: ~/.timmy/nostr/agent_keys.json
  • Group code: Will be set once group creation succeeds
  • Bridge service: nostr-bridge.service — polls DMs every 60s, creates Gitea issues
  • Bridge code: /root/nostr-relay/dm_bridge_mvp.py — uses nostr-sdk (not pynostr)