nostr-event-builder

Use when constructing Nostr events from natural language descriptions, building kind-specific tag structures, implementing NIP-10 threading for kind:1 replies, creating NIP-22 comments on non-note content, or generating correct event JSON with proper e/p/a tag markers and serialization format.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "nostr-event-builder" with this command: npx skills add accolver/skill-maker/accolver-skill-maker-nostr-event-builder

Nostr Event Builder

Overview

Construct correct Nostr event structures from natural language descriptions. This skill handles the non-obvious parts: choosing the right kind, building proper tag arrays with correct markers, enforcing NIP-10 vs NIP-22 threading rules, and producing valid event JSON ready for signing.

When to Use

  • Developer describes what they want to publish on Nostr
  • Building reply threads (NIP-10 kind:1 replies)
  • Commenting on non-note content (NIP-22 kind:1111 comments)
  • Creating or updating user profiles (kind:0 metadata)
  • Constructing any Nostr event and unsure about tag structure
  • Debugging malformed events (wrong markers, missing tags)

Do NOT use when:

  • Implementing relay WebSocket logic (that's relay protocol, not event building)
  • Working with NIP-19 encoding/decoding (bech32 concerns, not event structure)
  • Building subscription filters (REQ messages, not EVENT messages)

Workflow

1. Identify the Event Kind

Ask: "What is the developer trying to publish?"

IntentKindCategoryKey NIP
Post a short text note1RegularNIP-10
Reply to a kind:1 note1RegularNIP-10
Comment on non-kind:1 content1111RegularNIP-22
Set/update user profile0ReplaceableNIP-01
Update follow list3ReplaceableNIP-02
Delete events5RegularNIP-09
Repost a note6RegularNIP-18
React to an event7RegularNIP-25
Publish a long-form article30023AddressableNIP-23

See references/event-kinds.md for full kind-to-structure mapping.

Critical routing rule:

Is the target a kind:1 note?
  YES → Use kind:1 reply with NIP-10 e-tag markers
  NO  → Use kind:1111 comment with NIP-22 uppercase/lowercase tags

2. Build the Tag Array

Tags are the hardest part. Follow the tag guide for your kind:

For kind:1 replies (NIP-10):

Direct reply to root (no intermediate replies):

{
  "kind": 1,
  "tags": [
    ["e", "<root-event-id>", "<relay-url>", "root", "<root-author-pubkey>"],
    ["p", "<root-author-pubkey>"]
  ],
  "content": "Your reply text"
}

Reply to a reply in a thread:

{
  "kind": 1,
  "tags": [
    ["e", "<root-event-id>", "<relay-url>", "root", "<root-author-pubkey>"],
    [
      "e",
      "<parent-event-id>",
      "<relay-url>",
      "reply",
      "<parent-author-pubkey>"
    ],
    ["p", "<root-author-pubkey>"],
    ["p", "<parent-author-pubkey>"]
  ],
  "content": "Your reply text"
}

For kind:1111 comments (NIP-22):

Top-level comment on a regular event:

{
  "kind": 1111,
  "tags": [
    ["E", "<root-event-id>", "<relay-url>", "<root-author-pubkey>"],
    ["K", "<root-event-kind>"],
    ["P", "<root-author-pubkey>", "<relay-url>"],
    ["e", "<root-event-id>", "<relay-url>", "<root-author-pubkey>"],
    ["k", "<root-event-kind>"],
    ["p", "<root-author-pubkey>", "<relay-url>"]
  ],
  "content": "Your comment text"
}

Top-level comment on an addressable event (kind 30000-39999):

{
  "kind": 1111,
  "tags": [
    ["A", "<kind>:<pubkey>:<d-tag>", "<relay-url>"],
    ["K", "<root-event-kind>"],
    ["P", "<root-author-pubkey>", "<relay-url>"],
    ["a", "<kind>:<pubkey>:<d-tag>", "<relay-url>"],
    ["e", "<event-id>", "<relay-url>"],
    ["k", "<root-event-kind>"],
    ["p", "<root-author-pubkey>", "<relay-url>"]
  ],
  "content": "Your comment text"
}

Comment on a URL or external identifier:

{
  "kind": 1111,
  "tags": [
    ["I", "<url-or-identifier>"],
    ["K", "<identifier-type>"],
    ["i", "<url-or-identifier>"],
    ["k", "<identifier-type>"]
  ],
  "content": "Your comment text"
}

Reply to an existing comment:

{
  "kind": 1111,
  "tags": [
    ["E", "<original-root-event-id>", "<relay-url>", "<root-author-pubkey>"],
    ["K", "<original-root-kind>"],
    ["P", "<root-author-pubkey>"],
    [
      "e",
      "<parent-comment-id>",
      "<relay-url>",
      "<parent-comment-author-pubkey>"
    ],
    ["k", "1111"],
    ["p", "<parent-comment-author-pubkey>"]
  ],
  "content": "Your reply to the comment"
}

See references/tag-guide.md for complete tag semantics.

3. Set the Content Field

Content format depends on the kind:

KindContent Format
0Stringified JSON: {"name":"...","about":"...","picture":"..."}
1Plaintext (no markdown, no HTML)
5Optional deletion reason text
6Stringified JSON of the reposted event
7+ (like), - (dislike), or emoji
1111Plaintext comment
30023Markdown-formatted article body

4. Construct the Complete Event

Assemble the unsigned event object:

{
  "pubkey": "<32-bytes-lowercase-hex-public-key>",
  "created_at": "<unix-timestamp-seconds>",
  "kind": "<integer>",
  "tags": [["..."]],
  "content": "<string>"
}

The id is computed as SHA-256 of the serialized form:

[0, "<pubkey>", <created_at>, <kind>, <tags>, "<content>"]

Serialization rules:

  • UTF-8 encoding, no whitespace/formatting
  • Escape in content: \n, \", \\, \r, \t, \b, \f
  • All other characters verbatim

The sig is a Schnorr signature (secp256k1) of the id.

5. Validate Before Signing

Checklist before the event is ready:

  • kind is correct for the intent
  • All required tags present for this kind
  • e tags have correct markers (root/reply for kind:1)
  • p tags include ALL participants in the thread
  • NIP-10 kind:1 replies only target other kind:1 events
  • NIP-22 kind:1111 comments do NOT target kind:1 events
  • K and k tags present for kind:1111 comments
  • Uppercase tags (E/A/I/K/P) point to root scope in kind:1111
  • Lowercase tags (e/a/i/k/p) point to parent item in kind:1111
  • content format matches the kind's requirements
  • created_at is a Unix timestamp in seconds (not milliseconds)
  • All hex values are 32-byte lowercase

Common Mistakes

MistakeWhy It BreaksFix
Using kind:1 to reply to a kind:30023 articleNIP-10 kind:1 replies MUST only reply to other kind:1 eventsUse kind:1111 (NIP-22 comment) for non-kind:1 targets
Using kind:1111 to reply to a kind:1 noteNIP-22 comments MUST NOT reply to kind:1Use kind:1 with NIP-10 e-tag markers
Missing root marker on e tags in kind:1Clients can't reconstruct the thread treeAlways use marked e tags: ["e", "<id>", "<relay>", "root"]
Only one e tag with reply marker (no root)Direct replies to root need root marker, not replySingle e tag = use root marker only
Missing p tags for thread participantsUsers don't get notified of repliesInclude p tags for ALL pubkeys in the thread
Lowercase e/k/p tags for root scope in kind:1111Root scope MUST use uppercase E/K/P tagsUppercase = root scope, lowercase = parent item
Missing K or k tags in kind:1111Both are REQUIRED by NIP-22Always include ["K", "<root-kind>"] and ["k", "<parent-kind>"]
created_at in millisecondsNostr uses seconds, not millisecondsUse Math.floor(Date.now() / 1000)
Content as object instead of string for kind:0Content must be stringified JSONUse JSON.stringify({name: "...", ...})
Missing d tag on addressable events (30000-39999)Relay can't address the event properlyAlways include ["d", "<identifier>"]
Positional e tags without markersDeprecated; creates ambiguity in thread reconstructionAlways use marked e tags with root/reply

Kind Category Quick Reference

RangeCategoryBehavior
1000-9999, 4-44, 1, 2RegularStored by relays, all kept
10000-19999, 0, 3ReplaceableLatest per pubkey+kind kept
20000-29999EphemeralNot stored by relays
30000-39999AddressableLatest per pubkey+kind+d-tag kept

Example: Complete Event Construction

User says: "I want to reply to my friend's note in an existing thread"

Step 1 — Identify kind: Replying to a kind:1 note → use kind:1 (NIP-10)

Step 2 — Determine thread position: This is a reply to a reply (not the root), so we need both root and reply e tags.

Step 3 — Build the event:

{
  "pubkey": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2",
  "created_at": 1709827200,
  "kind": 1,
  "tags": [
    ["e", "aaa111...", "wss://relay.example.com", "root", "f7234bd4..."],
    ["e", "bbb222...", "wss://relay.example.com", "reply", "93ef2eba..."],
    ["p", "f7234bd4...", "wss://relay.example.com"],
    ["p", "93ef2eba...", "wss://relay.example.com"]
  ],
  "content": "Great point! I totally agree with this take."
}

Step 4 — Validate: Root e tag has root marker ✓, reply e tag has reply marker ✓, p tags include both the root author and the parent author ✓, content is plaintext ✓.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

skill-maker

No summary provided by upstream source.

Repository SourceNeeds Review
General

pr-description

No summary provided by upstream source.

Repository SourceNeeds Review
General

pdf-toolkit

No summary provided by upstream source.

Repository SourceNeeds Review
General

error-handling

No summary provided by upstream source.

Repository SourceNeeds Review