Skip to content

Add comprehensive Nostr client integration guide#16

Open
rabble wants to merge 2 commits intomainfrom
updated_docs
Open

Add comprehensive Nostr client integration guide#16
rabble wants to merge 2 commits intomainfrom
updated_docs

Conversation

@rabble
Copy link
Copy Markdown

@rabble rabble commented May 22, 2025

Summary

  • Added comprehensive documentation for Nostr clients integrating with NIP-29 group relays
  • Clear instructions for creating hierarchical group structures using domains/subdomains

Changes

  • Created NOSTR_CLIENT_INTEGRATION.md with:
    • Connection and authentication instructions
    • Complete group operation examples
    • Detailed domain/subdomain/sub-group setup instructions
    • Step-by-step code examples for creating group hierarchies
    • Best practices for client implementation
    • Security considerations

Key Features Documented

  • How to create domains (e.g., company)
  • How to create subdomains (e.g., company/engineering)
  • How to create sub-groups (e.g., company/engineering/frontend)
  • Permission inheritance in hierarchical structures
  • Group discovery and navigation
  • Complete working examples

This guide will help Nostr client developers properly implement group functionality with hierarchical organization support.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive integration guide for Nostr clients to interact with NIP-29 compliant group relays, including connection/authentication steps, group operations, hierarchical group management, domain-specific features, best practices, example flows, security considerations, and a testing checklist.
    • Introduced detailed implementation notes for the groups_relay middleware, covering architecture, event types, permission models, data structures, configuration, deployment, testing, security, performance, monitoring, and future enhancements.

- Document NIP-29 group relay integration for clients
- Explain domain/subdomain/sub-group hierarchical structure
- Provide step-by-step examples for creating group hierarchies
- Include code examples for all group operations
- Add best practices and security considerations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 22, 2025

Walkthrough

Two new documentation files have been added. NOSTR_CLIENT_INTEGRATION.md provides a detailed integration guide for Nostr clients to interact with NIP-29 compliant group relays, covering connection, authentication, group operations, hierarchical group management, event kinds, best practices, security, and testing. relay_nip29_notes.md offers an in-depth technical blueprint for the groups_relay middleware, detailing architecture, event types, data structures, configuration, deployment, testing, security, performance, monitoring, limitations, and future plans. No code files were modified.

Changes

File(s) Change Summary
NOSTR_CLIENT_INTEGRATION.md Added a comprehensive integration guide for Nostr clients, including connection, group management, event kinds, best practices, security, and testing details.
relay_nip29_notes.md Added detailed design and implementation notes for groups_relay middleware with NIP-29 support, covering architecture, event types, data structures, configuration, deployment, testing, security, performance, monitoring, limitations, and future enhancements.

Poem

🐇
A guide for Nostr, crisp and bright,
Shows clients how to link just right.
With groups and roles and steps so clear,
Hierarchies form, permissions appear.
Through relays swift, messages fly—
Now rabbits code and clients try!
🌱


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (5)
NOSTR_CLIENT_INTEGRATION.md (5)

55-63: Use unique subscription IDs to prevent overrides.

The examples reuse the same "<subscription-id>" for both content and metadata subscriptions. Reusing the same ID causes the second REQ to replace the first. Use distinct identifiers for each subscription.

 // Subscribe to a specific group's content
-relay.send(JSON.stringify([
-  "REQ",
-  "<subscription-id>",
+const groupContentSub = "group-content";
+relay.send(JSON.stringify([
+  "REQ",
+  groupContentSub,
   {
     "kinds": [9, 10, 11, 12, 39000, 39001, 39002],
     "#h": ["<group-id>"]
   }
 ]));

 // Subscribe to all groups metadata
-relay.send(JSON.stringify([
-  "REQ",
-  "<subscription-id>",
+const metadataSub = "groups-metadata";
+relay.send(JSON.stringify([
+  "REQ",
+  metadataSub,
   {
     "kinds": [39000]
   }
 ]));

Also applies to: 65-72


105-115: Include full event envelope for join requests.

The join examples omit mandatory fields (id, pubkey, created_at, sig) and the relay.send call. For consistency and correctness, show the complete event and how to send it.

-const joinRequest = {
-  "kind": 9021,
-  "tags": [
-    ["h", "<group-id>"],
-    ["relay", "wss://groups.example.com"]
-  ],
-  "content": "Optional message"
-};
-
-```
+const joinRequest = {
+  id: "<event-id>",
+  pubkey: "<your-pubkey>",
+  created_at: <timestamp>,
+  kind: 9021,
+  tags: [
+    ["h", "<group-id>"],
+    ["relay", "wss://groups.example.com"]
+  ],
+  content: "Optional message",
+  sig: "<signature>"
+};
+
+relay.send(JSON.stringify(["EVENT", joinRequest]));
+```

Also applies to: 117-127


17-18: Link to the NIP-29 specification for clarity.

Adding a direct reference helps readers dive deeper into the protocol details.

-NIP-29 defines relay-based groups where the relay acts as the authority for group management.
+NIP-29 defines relay-based groups where the relay acts as the authority for group management. [Read the spec ↗](https://github.com/nostr-protocol/nips/blob/master/29.md)

178-178: Standardize “sub-groups” spelling to “subgroups” and “sub-group” to “subgroup”/“subteam”.

Use consistent, unhyphenated terminology throughout.

-3. Creating Sub-groups
+3. Creating Subgroups

-Groups in NIP-29 can be organized hierarchically using a forward-slash (`/`) naming convention to create domains, subdomains, and sub-groups.
+Groups in NIP-29 can be organized hierarchically using a forward-slash (`/`) naming convention to create domains, subdomains, and subgroups.

-| Deep sub-group | `acme/engineering/frontend/react` | Specific technology or sub-team |
+| Deep subgroup   | `acme/engineering/frontend/react` | Specific technology or subteam |

Also applies to: 235-235, 325-325

🧰 Tools
🪛 LanguageTool

[misspelling] ~178-~178: This word is normally spelled as one.
Context: ...tion to create domains, subdomains, and sub-groups. This is achieved through the group ID ...

(EN_COMPOUNDS_SUB_GROUPS)


180-190: Specify a language for the ASCII diagram code block.

Markdown lint flags fences missing a language. Mark it as text for better rendering.

-```
+```text
 company                          # Top-level domain group
 ├── company/engineering          # Subdomain under company
 │   ├── company/engineering/frontend    # Subgroup under engineering
 │   ├── company/engineering/backend     # Subgroup under engineering
 │   └── company/engineering/qa          # Subgroup under engineering
 ├── company/marketing            # Another subdomain
 │   ├── company/marketing/social        # Subgroup under marketing
 │   └── company/marketing/content       # Subgroup under marketing
 └── company/hr                   # Another subdomain
-```
+```text

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

180-180: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

</details>

</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**


<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between b47c905ee8a18f40f5d7696313b1a32075728887 and 0ad58e9da4cf00ab6c14487a1a1f10fc1ec615aa.

</details>

<details>
<summary>📒 Files selected for processing (1)</summary>

* `NOSTR_CLIENT_INTEGRATION.md` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🪛 LanguageTool</summary>

<details>
<summary>NOSTR_CLIENT_INTEGRATION.md</summary>

[misspelling] ~178-~178: This word is normally spelled as one.
Context: ...tion to create domains, subdomains, and sub-groups. This is achieved through the group ID ...

(EN_COMPOUNDS_SUB_GROUPS)

---

[misspelling] ~235-~235: This word is normally spelled as one.
Context: ...# 3. Creating Sub-groups  Create deeper sub-groups following the same pattern:  ```javascr...

(EN_COMPOUNDS_SUB_GROUPS)

---

[duplication] ~255-~255: Possible typo: you repeated a word.
Context: ...any/engineering` does NOT automatically create `company` 3. **Create from top to bottom** - Create parent gr...

(ENGLISH_WORD_REPEAT_RULE)

---

[misspelling] ~325-~325: This word is normally spelled as one.
Context: ...ng/frontend` | Team or project | | Deep sub-group | `acme/engineering/frontend/react` | S...

(EN_COMPOUNDS_SUB_GROUP)

---

[misspelling] ~325-~325: This word is normally spelled as one.
Context: ...rontend/react` | Specific technology or sub-team |  #### 2. Automatic Parent Group Membe...

(EN_COMPOUNDS_SUB_TEAM)

---

[style] ~448-~448: Consider using only “public” to avoid wordiness.
Context: ...ost - `12` - Public comment - `10010` - General public content - `9021` - Join request - `9022...

(GENERAL_XX)

</details>

</details>
<details>
<summary>🪛 markdownlint-cli2 (0.17.2)</summary>

<details>
<summary>NOSTR_CLIENT_INTEGRATION.md</summary>

180-180: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (3)</summary>

* GitHub Check: Test
* GitHub Check: Code Coverage
* GitHub Check: Test

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +31 to +49
// Connect to the group relay
const relay = new WebSocket('wss://groups.example.com');

// For private groups, authenticate using NIP-42
relay.send(JSON.stringify([
"AUTH",
{
"id": "<event-id>",
"pubkey": "<your-pubkey>",
"created_at": <timestamp>,
"kind": 22242,
"tags": [
["relay", "wss://groups.example.com"],
["challenge", "<challenge-from-relay>"]
],
"content": "",
"sig": "<signature>"
}
]));
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure WebSocket is open before sending messages.

In the initial connection example, relay.send(...) is called immediately after creating the WebSocket, which may throw if the socket isn’t yet open. Wrap the authentication send inside relay.onopen or wait for readyState === WebSocket.OPEN.

Apply this diff:

 const relay = new WebSocket('wss://groups.example.com');
-// For private groups, authenticate using NIP-42
-relay.send(JSON.stringify([
-  "AUTH",
-  {
-    "id": "<event-id>",
-    "pubkey": "<your-pubkey>",
-    "created_at": <timestamp>,
-    "kind": 22242,
-    "tags": [
-      ["relay", "wss://groups.example.com"],
-      ["challenge", "<challenge-from-relay>"]
-    ],
-    "content": "",
-    "sig": "<signature>"
-  }
-]));
+relay.onopen = () => {
+  // For private groups, authenticate using NIP-42
+  relay.send(JSON.stringify([
+    "AUTH",
+    {
+      "id": "<event-id>",
+      "pubkey": "<your-pubkey>",
+      "created_at": <timestamp>,
+      "kind": 22242,
+      "tags": [
+        ["relay", "wss://groups.example.com"],
+        ["challenge", "<challenge-from-relay>"]
+      ],
+      "content": "",
+      "sig": "<signature>"
+    }
+  ]));
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Connect to the group relay
const relay = new WebSocket('wss://groups.example.com');
// For private groups, authenticate using NIP-42
relay.send(JSON.stringify([
"AUTH",
{
"id": "<event-id>",
"pubkey": "<your-pubkey>",
"created_at": <timestamp>,
"kind": 22242,
"tags": [
["relay", "wss://groups.example.com"],
["challenge", "<challenge-from-relay>"]
],
"content": "",
"sig": "<signature>"
}
]));
// Connect to the group relay
const relay = new WebSocket('wss://groups.example.com');
relay.onopen = () => {
// For private groups, authenticate using NIP-42
relay.send(JSON.stringify([
"AUTH",
{
"id": "<event-id>",
"pubkey": "<your-pubkey>",
"created_at": <timestamp>,
"kind": 22242,
"tags": [
["relay", "wss://groups.example.com"],
["challenge", "<challenge-from-relay>"]
],
"content": "",
"sig": "<signature>"
}
]));
};
🤖 Prompt for AI Agents
In NOSTR_CLIENT_INTEGRATION.md around lines 31 to 49, the code calls relay.send
immediately after creating the WebSocket, which can fail if the socket is not
yet open. To fix this, move the relay.send call inside a relay.onopen event
handler or add a check to wait until relay.readyState equals WebSocket.OPEN
before sending the authentication message.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 22, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Created detailed documentation covering:
- Relay architecture and middleware stack
- Complete NIP-29 event type reference with examples
- Group types and permission system
- Event flow and data structures
- Configuration and deployment guide
- Testing examples and security considerations

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
relay_nip29_notes.md (3)

1-6: Add a Table of Contents and cross-reference the client integration guide

Given the length of this document, a table of contents at the top would greatly improve navigability. Additionally, including a “See also: NOSTR_CLIENT_INTEGRATION.md” link will help readers quickly locate the complementary client integration guide.


19-23: Specify fenced code block language for middleware diagram

The ASCII diagram of the middleware stack is wrapped in triple backticks without a language identifier. Please add a language (e.g., text) to enable proper syntax highlighting and satisfy markdown lint rules.
Suggested diff:

- ```
+ ```text
Client → LoggerMiddleware → Nip42Middleware → ValidationMiddleware → 
EventVerifierMiddleware → Nip70Middleware → Nip29Middleware → 
EventStoreMiddleware → Backing Relay
- ```
+ ```text
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

19-19: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)


426-438: Adjust JSON code block language or remove embedded comments

The block is marked as json but contains // comments, which breaks strict JSON parsing. Consider switching the fence to jsonc (JSON with comments) or removing the inline comments.
Suggested diff:

- ```json
+ ```jsonc
// Get group metadata
{"kinds": [39000], "authors": ["relay-pubkey"], "#d": ["group-id"]}

// Get group members
{"kinds": [39002], "authors": ["relay-pubkey"], "#d": ["group-id"]}

// Get group messages
{"kinds": [1], "#h": ["group-id"]}

// Get all groups
{"kinds": [39000], "authors": ["relay-pubkey"]}
- ```
+ ```jsonc
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0ad58e9 and 35bf120.

📒 Files selected for processing (1)
  • relay_nip29_notes.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
relay_nip29_notes.md

[uncategorized] ~325-~325: Loose punctuation mark.
Context: ... Environment Variables - DATABASE_URL: Override database path - RUST_LOG: Lo...

(UNLIKELY_OPENING_PUNCTUATION)

🪛 markdownlint-cli2 (0.17.2)
relay_nip29_notes.md

19-19: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Test
  • GitHub Check: Code Coverage
🔇 Additional comments (1)
relay_nip29_notes.md (1)

35-115: Verify inclusion of all NIP-29 admin/management event kinds

The documentation lists kinds 9000, 9001, 9002, 9005, 9006, 9007, 9008, and 9009 but omits kinds 9003 and 9004. Please confirm whether those event types are intentionally left out or if they should be documented here as well.

@dcadenas dcadenas force-pushed the main branch 4 times, most recently from 4016a81 to a84fc75 Compare May 31, 2025 07:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant