summaryrefslogtreecommitdiffstats
path: root/.claude
diff options
context:
space:
mode:
authorClawd <ai@clawd.bot>2026-02-16 12:12:37 -0800
committerClawd <ai@clawd.bot>2026-02-16 12:12:37 -0800
commit9d20d2281f4698024b7be67d1b86178b4e8e2484 (patch)
treef72986f33904afc36b72dd8bbb7d83802fee0479 /.claude
parent4b7dfe1e7764d8424b1be935c7fea09a102382e8 (diff)
Clean up project structure
- Add README.md - Move benchmark files to benchmarks/ - Move PLAN.md to .claude/ - Add .gitignore
Diffstat (limited to '.claude')
-rw-r--r--.claude/PLAN.md186
1 files changed, 186 insertions, 0 deletions
diff --git a/.claude/PLAN.md b/.claude/PLAN.md
new file mode 100644
index 0000000..39d8318
--- /dev/null
+++ b/.claude/PLAN.md
@@ -0,0 +1,186 @@
1# Minimal Nostr Go Library - Implementation Plan
2
3## Overview
4
5Build a minimal Go library for Nostr split into two modules:
6
7**Module 1: Core** (`nostr-go` root) - 1 external dep
8- Types, signing, serialization
9- `github.com/btcsuite/btcd/btcec/v2` - BIP-340 Schnorr signatures
10
11**Module 2: Relay** (`nostr-go/relay`) - 1 additional dep
12- WebSocket connection, pub/sub
13- `github.com/coder/websocket` - WebSocket library
14- Imports core module
15
16Users who only need types/signing don't pull in websocket dependencies.
17
18## Package Structure
19
20```
21nostr-go/
22├── go.mod # Core module
23├── event.go # Event struct, ID computation, serialization
24├── tags.go # Tag/Tags types and helpers
25├── kinds.go # Event kind constants
26├── filter.go # Filter struct and matching logic
27├── keys.go # Key generation, signing, verification
28├── bech32.go # Bech32 encoding/decoding (our impl, ~150 lines)
29├── nip19.go # npub/nsec/note/nprofile encode/decode
30├── envelope.go # Protocol messages (EVENT, REQ, OK, etc.)
31├── *_test.go
32
33└── relay/
34 ├── go.mod # Relay module (imports core)
35 ├── relay.go # WebSocket connection primitives
36 ├── subscription.go # Subscription handling
37 └── *_test.go
38```
39
40## Core Types
41
42### Event (event.go)
43```go
44type Event struct {
45 ID string `json:"id"` // 64-char hex (SHA256)
46 PubKey string `json:"pubkey"` // 64-char hex (x-only pubkey)
47 CreatedAt int64 `json:"created_at"`
48 Kind int `json:"kind"`
49 Tags Tags `json:"tags"`
50 Content string `json:"content"`
51 Sig string `json:"sig"` // 128-char hex (Schnorr sig)
52}
53```
54
55**Design note**: Starting with hex strings for simplicity. Can evaluate byte arrays (`[32]byte`, `[64]byte`) later if type safety becomes important.
56
57Key methods:
58- `Serialize() []byte` - Canonical JSON for ID computation: `[0,"pubkey",created_at,kind,tags,"content"]`
59- `ComputeID() string` - SHA256 hash of serialized form
60- `Sign(privKeyHex string) error` - Sign with Schnorr, sets PubKey/ID/Sig
61- `Verify() bool` - Verify signature
62
63### Tags (tags.go)
64```go
65type Tag []string
66type Tags []Tag
67```
68Methods: `Key()`, `Value()`, `Find(key)`, `FindAll(key)`, `GetD()`
69
70### Filter (filter.go)
71```go
72type Filter struct {
73 IDs []string `json:"ids,omitempty"`
74 Kinds []int `json:"kinds,omitempty"`
75 Authors []string `json:"authors,omitempty"`
76 Tags map[string][]string `json:"-"` // Custom marshal for #e, #p
77 Since *int64 `json:"since,omitempty"`
78 Until *int64 `json:"until,omitempty"`
79 Limit int `json:"limit,omitempty"`
80}
81```
82Methods: `Matches(event) bool`, custom `MarshalJSON`/`UnmarshalJSON` for tag filters
83
84### Kinds (kinds.go)
85Essential constants only:
86```go
87const (
88 KindMetadata = 0
89 KindTextNote = 1
90 KindContactList = 3
91 KindEncryptedDM = 4
92 KindDeletion = 5
93 KindRepost = 6
94 KindReaction = 7
95)
96```
97Helpers: `IsRegular()`, `IsReplaceable()`, `IsEphemeral()`, `IsAddressable()`
98
99### Envelopes (envelope.go)
100Protocol messages as types with `Label()` and `MarshalJSON()`:
101- Client→Relay: `EventEnvelope`, `ReqEnvelope`, `CloseEnvelope`
102- Relay→Client: `EventEnvelope`, `OKEnvelope`, `EOSEEnvelope`, `ClosedEnvelope`, `NoticeEnvelope`
103- `ParseEnvelope(data []byte) (Envelope, error)`
104
105## Keys & Signing (keys.go)
106
107Using `github.com/btcsuite/btcd/btcec/v2/schnorr`:
108```go
109func GenerateKey() (string, error)
110func GetPublicKey(privKeyHex string) (string, error)
111func (e *Event) Sign(privKeyHex string) error
112func (e *Event) Verify() bool
113```
114
115## NIP-19 Encoding (nip19.go)
116
117Bech32 encoding for human-readable identifiers:
118```go
119func EncodePublicKey(pubKeyHex string) (string, error) // -> npub1...
120func EncodeSecretKey(secKeyHex string) (string, error) // -> nsec1...
121func EncodeNote(eventID string) (string, error) // -> note1...
122
123func DecodePublicKey(npub string) (string, error) // npub1... -> hex
124func DecodeSecretKey(nsec string) (string, error) // nsec1... -> hex
125func DecodeNote(note string) (string, error) // note1... -> hex
126
127// TLV-encoded types (nprofile, nevent, naddr) can be added later
128```
129
130## WebSocket Primitives (relay.go)
131
132Simple design - no complex goroutine orchestration:
133```go
134type Relay struct {
135 URL string
136 conn *websocket.Conn
137 mu sync.Mutex
138}
139
140func Connect(ctx context.Context, url string) (*Relay, error)
141func (r *Relay) Close() error
142func (r *Relay) Send(ctx context.Context, env Envelope) error
143func (r *Relay) Receive(ctx context.Context) (Envelope, error)
144func (r *Relay) Publish(ctx context.Context, event *Event) error
145func (r *Relay) Subscribe(ctx context.Context, id string, filters ...Filter) (*Subscription, error)
146
147type Subscription struct {
148 ID string
149 Events chan *Event
150 EOSE chan struct{}
151}
152func (s *Subscription) Listen() error
153func (s *Subscription) Close() error
154```
155
156## Implementation Order
157
158### Phase 1: Core Module (nostr-go)
1591. **go.mod** - Module definition with btcec/v2 dependency
1602. **event.go, tags.go, kinds.go** - Core types, serialization, ID computation
1613. **keys.go** - Schnorr signing with btcec/v2
1624. **bech32.go** - Bech32 encode/decode (~150 lines)
1635. **nip19.go** - npub/nsec/note encoding
1646. **filter.go** - Filter struct with custom JSON and matching
1657. **envelope.go** - All envelope types and ParseEnvelope
1668. **Core tests**
167
168### Phase 2: Relay Module (nostr-go/relay)
1691. **relay/go.mod** - Module definition with websocket dep, imports core
1702. **relay/relay.go** - WebSocket connection primitives
1713. **relay/subscription.go** - Subscription handling
1724. **Relay tests**
173
174## What's Omitted (v0.1)
175
176- NIP-42 AUTH
177- NIP-04 encrypted DMs
178- Connection pooling / relay pool
179- Automatic reconnection
180- Advanced kinds (10000+)
181
182## Verification
183
1841. Unit tests for each module
1852. Integration test: connect to `wss://relay.damus.io`, publish event, subscribe
1863. Verify signature interop with existing Nostr clients/libraries