Nostr Protocol Expert
Purpose
This skill provides expert-level assistance with the Nostr protocol, a simple, open protocol for global, decentralized, and censorship-resistant social networks. The protocol is built on relays and cryptographic keys, enabling direct peer-to-peer communication without central servers.
When to Use
Activate this skill when:
-
Implementing Nostr clients or relays
-
Working with Nostr events and messages
-
Handling cryptographic signatures and keys (schnorr signatures on secp256k1)
-
Implementing any Nostr Implementation Possibility (NIP)
-
Building social networking features on Nostr
-
Querying or filtering Nostr events
-
Discussing Nostr protocol architecture
-
Implementing WebSocket communication with relays
Core Concepts
The Protocol Foundation
Nostr operates on two main components:
-
Clients - Applications users run to read/write data
-
Relays - Servers that store and forward messages
Key principles:
-
Everyone runs a client
-
Anyone can run a relay
-
Users identified by public keys
-
Messages signed with private keys
-
No central authority or trusted servers
Events Structure
All data in Nostr is represented as events. An event is a JSON object with this structure:
{ "id": "<32-bytes lowercase hex-encoded sha256 of the serialized event data>", "pubkey": "<32-bytes lowercase hex-encoded public key of the event creator>", "created_at": "<unix timestamp in seconds>", "kind": "<integer identifying event type>", "tags": [ ["<tag name>", "<tag value>", "<optional third param>", "..."] ], "content": "<arbitrary string>", "sig": "<64-bytes lowercase hex of the schnorr signature of the sha256 hash of the serialized event data>" }
Event Kinds
Standard event kinds (from various NIPs):
-
0
-
Metadata (user profile)
-
1
-
Text note (short post)
-
2
-
Recommend relay
-
3
-
Contacts (following list)
-
4
-
Encrypted direct messages
-
5
-
Event deletion
-
6
-
Repost
-
7
-
Reaction (like, emoji reaction)
-
40
-
Channel creation
-
41
-
Channel metadata
-
42
-
Channel message
-
43
-
Channel hide message
-
44
-
Channel mute user
-
1000-9999
-
Regular events
-
10000-19999
-
Replaceable events
-
20000-29999
-
Ephemeral events
-
30000-39999
-
Parameterized replaceable events
Tags
Common tag types:
-
["e", "<event-id>", "<relay-url>", "<marker>"]
-
Reference to an event
-
["p", "<pubkey>", "<relay-url>"]
-
Reference to a user
-
["a", "<kind>:<pubkey>:<d-tag>", "<relay-url>"]
-
Reference to a replaceable event
-
["d", "<identifier>"]
-
Identifier for parameterized replaceable events
-
["r", "<url>"]
-
Reference/link to a web resource
-
["t", "<hashtag>"]
-
Hashtag
-
["g", "<geohash>"]
-
Geolocation
-
["nonce", "<number>", "<difficulty>"]
-
Proof of work
-
["subject", "<subject>"]
-
Subject/title
-
["client", "<client-name>"]
-
Client application used
Key NIPs Reference
For detailed specifications, refer to references/nips-overview.md.
Core Protocol NIPs
NIP-01: Basic Protocol Flow
The foundation of Nostr. Defines:
-
Event structure and validation
-
Event ID calculation (SHA256 of serialized event)
-
Signature verification (schnorr signatures)
-
Client-relay communication via WebSocket
-
Message types: EVENT, REQ, CLOSE, EOSE, OK, NOTICE
NIP-02: Contact List and Petnames
Event kind 3 for following lists:
-
Each p tag represents a followed user
-
Optional relay URL and petname in tag
-
Replaceable event (latest overwrites)
NIP-04: Encrypted Direct Messages
Event kind 4 for private messages:
-
Content encrypted with shared secret (ECDH)
-
p tag for recipient pubkey
-
Deprecated in favor of NIP-44
NIP-05: Mapping Nostr Keys to DNS
Internet identifier format: name@domain.com
-
.well-known/nostr.json endpoint
-
Maps names to pubkeys
-
Optional relay list
NIP-09: Event Deletion
Event kind 5 to request deletion:
-
Contains e tags for events to delete
-
Relays should delete referenced events
-
Only works for own events
NIP-10: Text Note References (Threads)
Conventions for e and p tags in replies:
-
Root event reference
-
Reply event reference
-
Mentions
-
Marker types: "root", "reply", "mention"
NIP-11: Relay Information Document
HTTP endpoint for relay metadata:
-
GET request to relay URL
-
Returns JSON with relay information
-
Supported NIPs, software, limitations
Social Features NIPs
NIP-25: Reactions
Event kind 7 for reactions:
-
Content usually "+" (like) or emoji
-
e tag for reacted event
-
p tag for event author
NIP-42: Authentication
Client authentication to relays:
-
AUTH message from relay
-
Client responds with event kind 22242
-
Proves key ownership
NIP-50: Search
Query filter extension for full-text search:
-
search field in REQ filters
-
Implementation-defined behavior
Advanced NIPs
NIP-19: bech32-encoded Entities
Human-readable identifiers:
-
npub : public key
-
nsec : private key (sensitive!)
-
note : note/event ID
-
nprofile : profile with relay hints
-
nevent : event with relay hints
-
naddr : replaceable event coordinate
NIP-44: Encrypted Payloads
Improved encryption for direct messages:
-
Versioned encryption scheme
-
Better security than NIP-04
-
ChaCha20-Poly1305 AEAD
NIP-65: Relay List Metadata
Event kind 10002 for relay lists:
-
Read/write relay preferences
-
Optimizes relay discovery
-
Replaceable event
Client-Relay Communication
WebSocket Messages
From Client to Relay
EVENT - Publish an event:
["EVENT", <event JSON>]
REQ - Request events (subscription):
["REQ", <subscription_id>, <filters JSON>, <filters JSON>, ...]
CLOSE - Stop a subscription:
["CLOSE", <subscription_id>]
AUTH - Respond to auth challenge:
["AUTH", <signed event kind 22242>]
From Relay to Client
EVENT - Send event to client:
["EVENT", <subscription_id>, <event JSON>]
OK - Acceptance/rejection notice:
["OK", <event_id>, <true|false>, <message>]
EOSE - End of stored events:
["EOSE", <subscription_id>]
CLOSED - Subscription closed:
["CLOSED", <subscription_id>, <message>]
NOTICE - Human-readable message:
["NOTICE", <message>]
AUTH - Authentication challenge:
["AUTH", <challenge>]
Filter Objects
Filters select events in REQ messages:
{ "ids": ["<event-id>", ...], "authors": ["<pubkey>", ...], "kinds": [<kind number>, ...], "#e": ["<event-id>", ...], "#p": ["<pubkey>", ...], "#a": ["<coordinate>", ...], "#t": ["<hashtag>", ...], "since": <unix timestamp>, "until": <unix timestamp>, "limit": <max number of events> }
Filtering rules:
-
Arrays are ORed together
-
Different fields are ANDed
-
Tag filters: #<single-letter> matches tag values
-
Prefix matching allowed for ids and authors
Cryptographic Operations
Key Management
-
Private Key: 32-byte random value, keep secure
-
Public Key: Derived via secp256k1
-
Encoding: Hex (lowercase) or bech32
Event Signing (schnorr)
Steps to create a signed event:
-
Set all fields except id and sig
-
Serialize event data to JSON (specific order)
-
Calculate SHA256 hash → id
-
Sign id with schnorr signature → sig
Serialization format for ID calculation:
[ 0, <pubkey>, <created_at>, <kind>, <tags>, <content> ]
Event Verification
Steps to verify an event:
-
Verify ID matches SHA256 of serialized data
-
Verify signature is valid schnorr signature
-
Check created_at is reasonable (not far future)
-
Validate event structure and required fields
Implementation Best Practices
For Clients
-
Connect to Multiple Relays: Don't rely on single relay
-
Cache Events: Reduce redundant relay queries
-
Verify Signatures: Always verify event signatures
-
Handle Replaceable Events: Keep only latest version
-
Respect User Privacy: Careful with sensitive data
-
Implement NIP-65: Use user's preferred relays
-
Proper Error Handling: Handle relay disconnections
-
Pagination: Use limit , since , until for queries
For Relays
-
Validate Events: Check signatures, IDs, structure
-
Rate Limiting: Prevent spam and abuse
-
Storage Management: Ephemeral events, retention policies
-
Implement NIP-11: Provide relay information
-
WebSocket Optimization: Handle many connections
-
Filter Optimization: Efficient event querying
-
Consider NIP-42: Authentication for write access
-
Performance: Index by pubkey, kind, tags, timestamp
Security Considerations
-
Never Expose Private Keys: Handle nsec carefully
-
Validate All Input: Prevent injection attacks
-
Use NIP-44: For encrypted messages (not NIP-04)
-
Check Event Timestamps: Reject far-future events
-
Implement Proof of Work: NIP-13 for spam prevention
-
Sanitize Content: XSS prevention in displayed content
-
Relay Trust: Don't trust single relay for critical data
Common Patterns
Publishing a Note
const event = { pubkey: userPublicKey, created_at: Math.floor(Date.now() / 1000), kind: 1, tags: [], content: "Hello Nostr!", } // Calculate ID and sign event.id = calculateId(event) event.sig = signEvent(event, privateKey) // Publish to relay ws.send(JSON.stringify(["EVENT", event]))
Subscribing to Notes
const filter = { kinds: [1], authors: [followedPubkey1, followedPubkey2], limit: 50 } ws.send(JSON.stringify(["REQ", "my-sub", filter]))
Replying to a Note
const reply = { kind: 1, tags: [ ["e", originalEventId, relayUrl, "root"], ["p", originalAuthorPubkey] ], content: "Great post!", // ... other fields }
Reacting to a Note
const reaction = { kind: 7, tags: [ ["e", eventId], ["p", eventAuthorPubkey] ], content: "+", // or emoji // ... other fields }
Development Resources
Essential NIPs for Beginners
Start with these NIPs in order:
-
NIP-01 - Basic protocol (MUST read)
-
NIP-19 - Bech32 identifiers
-
NIP-02 - Following lists
-
NIP-10 - Threaded conversations
-
NIP-25 - Reactions
-
NIP-65 - Relay lists
Testing and Development
-
Relay Implementations: nostream, strfry, relay.py
-
Test Relays: wss://relay.damus.io, wss://nos.lol
-
Libraries: nostr-tools (JS), rust-nostr (Rust), python-nostr (Python)
-
Development Tools: NostrDebug, Nostr Army Knife, nostril
-
Reference Clients: Damus (iOS), Amethyst (Android), Snort (Web)
Key Repositories
-
NIPs Repository: https://github.com/nostr-protocol/nips
-
Awesome Nostr: https://github.com/aljazceru/awesome-nostr
-
Nostr Resources: https://nostr.how
Reference Files
For comprehensive NIP details, see:
-
references/nips-overview.md - Detailed descriptions of all standard NIPs
-
references/event-kinds.md - Complete event kinds reference
-
references/common-mistakes.md - Pitfalls and how to avoid them
Quick Checklist
When implementing Nostr:
-
Events have all required fields (id, pubkey, created_at, kind, tags, content, sig)
-
Event IDs calculated correctly (SHA256 of serialization)
-
Signatures verified (schnorr on secp256k1)
-
WebSocket messages properly formatted
-
Filter queries optimized with appropriate limits
-
Handling replaceable events correctly
-
Connected to multiple relays for redundancy
-
Following relevant NIPs for features implemented
-
Private keys never exposed or transmitted
-
Event timestamps validated
Official Resources
-
NIPs Repository: https://github.com/nostr-protocol/nips
-
Nostr Website: https://nostr.com
-
Nostr Documentation: https://nostr.how
-
NIP Status: https://nostr-nips.com