Nostr Kind Ranges and Meanings in Buzz: Complete Technical Reference

Buzz organizes Nostr events into distinct numeric kind ranges that determine storage semantics, replacement rules, and access control, with all constants and validation logic centralized in crates/buzz-core/src/kind.rs.

The block/buzz repository implements a sophisticated event classification system that extends standard Nostr protocol specifications. Every kind number falls into a specific semantic range that dictates whether the event is immutable, replaceable, ephemeral, or command-based, directly impacting how the relay stores, routes, and secures each event.

Standard NIP Protocol Ranges

Standard NIP Kinds (0–3, 5, 7, 41)

These core protocol events follow NIP-01 and related specifications. In crates/buzz-core/src/kind.rs, they are defined as immutable baseline types:

  • KIND_PROFILE (0) – Metadata events defined at line 9
  • KIND_TEXT (1) – Short text notes at line 11
  • KIND_CONTACT (3) – Contact lists at line 13

These events are either immutable or follow standard NIP replacement rules.

Replaceable Range (10,000–19,999)

Events in this range represent user-owned global state keyed by (pubkey, kind). When a new event arrives with the same key, it completely replaces the previous version.

Key constants include:

  • KIND_MUTE_LIST (10000) at line 15
  • KIND_PIN_LIST, KIND_RELAY_LIST, KIND_BOOKMARK_LIST – All following the KIND_…_LIST naming convention

These are ideal for lists and settings that should persist as single, updatable records per user.

Parameterized Replaceable Range (30,000–39,999)

This range uses a composite key of (pubkey, kind, d_tag), allowing multiple replaceable streams per user. The most recent created_at timestamp wins for each unique d_tag.

The boundaries are defined by PARAM_REPLACEABLE_KIND_MIN and MAX at lines 52-54. Buzz utilizes this extensively for:

  • KIND_PERSONA (30175) at line 96
  • KIND_TEAM (30176) at line 76
  • Push leases (KIND_PUSH_LEASE = 30350) at line 108 – Within the sub-range 30378–30500 for author-only encrypted state

Ephemeral and Real-Time Ranges

Ephemeral Range (20,000–29,999)

Events in this category never persist to the Postgres database. They flow exclusively through Redis pub/sub for real-time scenarios like presence updates and typing indicators.

The boundaries are declared at lines 56-58 as EPHEMERAL_KIND_MIN and MAX. Validation uses the is_ephemeral helper function to ensure these events are only forwarded, never stored.

Buzz-Specific Domain Extensions

Direct Message Lifecycle (41,000–41,999)

Reserved for DM protocol events including conversation creation and membership management:

  • KIND_DM_OPEN (41010) at line 106
  • Add member, hide, and canonical DM creation events

Agent Job Protocol (43,000–43,999)

Job-control events for automated agents follow a request-response lifecycle:

  • KIND_JOB_REQUEST (43001) at line 116
  • JOB_ACCEPTED, JOB_PROGRESS, JOB_RESULT, JOB_CANCEL, and JOB_ERROR

Workflow Engine (46,000–46,999)

Workflow execution events support complex automation pipelines:

  • KIND_WORKFLOW_TRIGGER (46020) at line 158
  • Step start, completed, failed, approvals, and cancellations

Git and Repository Management (30,617–30,623)

Supporting NIP-34 Git functionality:

  • KIND_GIT_REPO_ANNOUNCEMENT (30617) at line 204
  • Repository state, patches, pull requests, issues, and status events

Forum and Social Features (45,001–45,003)

Community discussion primitives:

  • KIND_FORUM_POST (45001) at line 216
  • Forum votes and comments

Media and Audit Systems (48,001–48,999 and 49,000–49,999)

Internal diagnostics and upload tracking:

  • KIND_MEDIA_UPLOAD (49001) at line 200 – Internal audit entries not visible to clients
  • KIND_AUDIT_ENTRY (48001) at line 208 – System diagnostics

Administration and Moderation Ranges

Relay Administration Commands (9,030–9,033)

NIP-43 admin commands for workspace and member management. These are identified by the is_relay_admin_kind helper at lines 94-102 and processed directly by the relay handlers in crates/buzz-relay/src/handlers/relay_admin.rs.

Community Moderation (9,040–9,044)

Direct moderation actions processed as commands rather than stored events:

  • Ban, unban, timeout, untimeout, and resolve report
  • Validated via is_moderation_command_kind at lines 76-84

Identity Archival (9,035–9,036)

NIP-IA requests for archiving or unarchiving identities, handled by is_identity_archive_request_kind at lines 106-112.

Group and Synthetic Ranges

NIP-29 Group State (39,000–39,003)

Addressable group metadata following NIP-29:

  • KIND_NIP29_GROUP_METADATA (39000) through group admins, members, and roles at lines 120-128

Channel Window Overlays (39,005–39,006)

Synthetic events injected by bridge services:

  • KIND_THREAD_SUMMARY (39005) at line 134
  • Window bounds for UI threading

Range Validation Helpers

The kind.rs module exports predicate functions that enforce range semantics throughout the codebase:

  • is_ephemeral – Checks against EPHEMERAL_KIND_MIN/MAX (lines 56-58)
  • is_replaceable – Validates 10,000–19,999 range
  • is_parameterized_replaceable – Validates 30,000–39,999 range
  • is_moderation_command_kind – 9040–9044 range check
  • is_relay_admin_kind – 9030–9033 range check
  • is_identity_archive_request_kind – 9035–9036 range check

These helpers ensure compile-time and runtime consistency for persistence rules and access control gates.

Practical Implementation Examples

Below are Rust snippets demonstrating how to construct events using the constant definitions from buzz-core:

use buzz_core::kind::*;
use nostr::{EventBuilder, Keys, Kind, Tag};

// Standard profile event (Kind 0)
let keys = Keys::generate();
let profile = EventBuilder::new(Kind::Custom(KIND_PROFILE as u16), r#"{"name":"Alice"}"#)
    .sign_with_keys(&keys)
    .unwrap();

// Replaceable mute list (Kind 10000)
let mute_list = EventBuilder::new(Kind::Custom(KIND_MUTE_LIST as u16), "[]")
    .tags(vec![Tag::parse(["d", "global"]).unwrap()])
    .sign_with_keys(&keys)
    .unwrap();

// Parameterized replaceable persona (Kind 30175)
let persona = EventBuilder::new(Kind::Custom(KIND_PERSONA as u16), r#"{"display_name":"Work Identity"}"#)
    .tags(vec![
        Tag::parse(["d", "professional"]).unwrap(),
        Tag::parse(["shared", "true"]).unwrap(),
    ])
    .sign_with_keys(&keys)
    .unwrap();

// Ephemeral typing indicator (within 20000-29999)
let typing = EventBuilder::new(Kind::Custom(KIND_TYPING_INDICATOR as u16), "")
    .tags(vec![Tag::parse(["h", "channel-uuid"]).unwrap()])
    .sign_with_keys(&keys)
    .unwrap(); // Relay forwards via Redis only, no database storage

// Workflow trigger (Kind 46020)
let trigger = EventBuilder::new(Kind::Custom(KIND_WORKFLOW_TRIGGER as u16), r#"{"workflow_id":"deploy"}"#)
    .sign_with_keys(&keys)
    .unwrap();

Summary

Buzz extends the Nostr protocol with a rigorous kind range taxonomy defined in crates/buzz-core/src/kind.rs:

  • 0–41: Standard immutable and basic replaceable events
  • 10,000–19,999: User global state (replaceable by pubkey+kind)
  • 20,000–29,999: Ephemeral events (Redis-only, no persistence)
  • 30,000–39,999: Parameterized replaceable (versioned by d-tag)
  • 41,000–41,999: Direct message lifecycle
  • 43,000–43,999: Agent job protocol
  • 46,000–46,999: Workflow engine events
  • 9,030–9,044: Relay administration and moderation commands
  • 39,000–39,006: Group state and synthetic overlays
  • 45,001–45,003: Forum posts and voting
  • 48,001–49,999: Audit and media tracking

Helper functions like is_ephemeral and is_parameterized_replaceable provide runtime guards to enforce these semantics across the relay, client, and agent implementations.

Frequently Asked Questions

What is the difference between replaceable and parameterized replaceable kinds in Buzz?

Replaceable kinds (10,000–19,999) use (pubkey, kind) as a composite key, allowing only one event per kind per user. Parameterized replaceable kinds (30,000–39,999) add a d_tag to the key, enabling multiple parallel streams per user where each unique d_tag value maintains its own replacement history. This allows Buzz to support multiple personas, teams, or workflow states per identity.

Why do ephemeral kinds (20,000–29,999) never touch the database?

Ephemeral kinds are designed for real-time, transient data like typing indicators or presence updates. According to the implementation at lines 56-58 of kind.rs, these events bypass Postgres entirely and flow only through Redis pub/sub. This prevents database bloat from temporary state while maintaining low-latency broadcasting to connected clients.

How does Buzz validate that an event is a moderation command versus a regular event?

Moderation commands in the 9,040–9,044 range are identified by the is_moderation_command_kind helper function (lines 76-84). Unlike standard events that are stored in the database, these are processed as immediate commands by the relay handlers in crates/buzz-auth/src/handlers/moderation_commands.rs, executing actions like ban or timeout without creating a persistent event record accessible to clients.

Which kind range should developers use for custom agent automation?

For autonomous agent workflows, use the Agent Job Protocol range (43,000–43,999) for lifecycle events (request, progress, result), and the Workflow Engine range (46,000–46,999) for orchestration events. These ranges are specifically reserved in kind.rs (lines 116 and 158) to ensure agents can communicate job state and trigger complex multi-step workflows without colliding with user content or standard NIP events.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →