upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/29.md
diff options
context:
space:
mode:
Diffstat (limited to '29.md')
-rw-r--r--29.md203
1 files changed, 141 insertions, 62 deletions
diff --git a/29.md b/29.md
index 0f4a579..a116433 100644
--- a/29.md
+++ b/29.md
@@ -16,12 +16,18 @@ Normally a group will originally belong to one specific relay, but the community
16 16
17## Relay-generated events 17## Relay-generated events
18 18
19Relays are supposed to generate the events that describe group metadata and group admins. These are parameterized replaceable events signed by the relay keypair directly, with the group _id_ as the `d` tag. 19Relays are supposed to generate the events that describe group metadata and group admins. These are _addressable_ events signed by the relay keypair directly, with the group _id_ as the `d` tag.
20 20
21## Group identifier 21## Group identifier
22 22
23A group may be identified by a string in the format `<host>'<group-id>`. For example, a group with _id_ `abcdef` hosted at the relay `wss://groups.nostr.com` would be identified by the string `groups.nostr.com'abcdef`. 23A group may be identified by a string in the format `<host>'<group-id>`. For example, a group with _id_ `abcdef` hosted at the relay `wss://groups.nostr.com` would be identified by the string `groups.nostr.com'abcdef`.
24 24
25Group identifiers must be strings restricted to the characters `a-z0-9-_`.
26
27When encountering just the `<host>` without the `'<group-id>`, clients can choose to connect to the group with id `_`, which is a special top-level group dedicated to relay-local discussions.
28
29Group identifiers in most cases should be random or pseudo-random, as that mitigates message replay confusion and ensures they can be migrated or forked to other relays easily without risking conflicting with other groups using the same id in these new relays. This isn't a hard rule, as, for example, in `unmanaged` and/or ephemeral relays groups might not want to migrate ever, so they might not care about this. Notably, the `_` relay-local group isn't expected to be migrated ever.
30
25## The `h` tag 31## The `h` tag
26 32
27Events sent by users to groups (chat messages, text notes, moderation events etc) must have an `h` tag with the value set to the group _id_. 33Events sent by users to groups (chat messages, text notes, moderation events etc) must have an `h` tag with the value set to the group _id_.
@@ -36,89 +42,133 @@ This is a hack to prevent messages from being broadcasted to external relays tha
36 42
37Relays should prevent late publication (messages published now with a timestamp from days or even hours ago) unless they are open to receive a group forked or moved from another relay. 43Relays should prevent late publication (messages published now with a timestamp from days or even hours ago) unless they are open to receive a group forked or moved from another relay.
38 44
45## Group management
46
47Groups can have any number of users with elevated access. These users are identified by role labels which are arbitrarily defined by the relays (see also the description of `kind:39003`). What each role is capable of not defined in this NIP either, it's a relay policy that can vary. Roles can be assigned by other users (as long as they have the capability to add roles) by publishing a `kind:9000` event with that user's pubkey in a `p` tag and the roles afterwards (even if the user is already a group member a `kind:9000` can be issued and the user roles must just be updated).
48
49The roles supported by the group as to having some special privilege assigned to them should be accessible on the event `kind:39003`, but the relay may also accept other role names, arbitrarily defined by clients, and just not do anything with them.
50
51Users with any roles that have any privilege can be considered _admins_ in a broad sense and be returned in the `kind:39001` event for a group.
52
53## Unmanaged groups
54
55Unmanaged groups are impromptu groups that can be used in any public relay unaware of NIP-29 specifics. They piggyback on relays' natural white/blacklists (or lack of) but aside from that are not actively managed and won't have any admins, group state or metadata events.
56
57In `unmanaged` groups, everybody is considered to be a member.
58
59Unmanaged groups can transition to managed groups, in that case the relay master key just has to publish moderation events setting the state of all groups and start enforcing the rules they choose to.
60
39## Event definitions 61## Event definitions
40 62
41- *text root note* (`kind:11`) 63These are the events expected to be found in NIP-29 groups.
42 64
43This is the basic unit of a "microblog" root text note sent to a group. 65### Normal user-created events
44 66
45```js 67These events generally can be sent by all members of a group and they require the `h` tag to be present so they're attached to a specific group.
46 "kind": 11, 68
69- _chat message_ (`kind:9`)
70
71This is the basic unit of a _chat message_ sent to a group.
72
73```jsonc
74 "kind": 9,
47 "content": "hello my friends lovers of pizza", 75 "content": "hello my friends lovers of pizza",
48 "tags": [ 76 "tags": [
49 ["h", "<group-id>"], 77 ["h", "<group-id>"],
50 ["previous", "<event-id-first-chars>", "<event-id-first-chars>", ...] 78 ["previous", "<event-id-first-chars>", "<event-id-first-chars>", /*...*/]
51 ] 79 ]
52 ... 80 // other fields...
53``` 81```
54 82
55- *threaded text reply* (`kind:12`) 83- _thread root post_ (`kind:11`)
56 84
57This is the basic unit of a "microblog" reply note sent to a group. It's the same as `kind:11`, except for the fact that it must be used whenever it's in reply to some other note (either in reply to a `kind:11` or a `kind:12`). `kind:12` events SHOULD use NIP-10 markers, leaving an empty relay url: 85This is the basic unit of a forum-like root thread post sent to a group.
58 86
59* `["e", "<kind-11-root-id>", "", "root"]` 87```jsonc
60* `["e", "<kind-12-event-id>", "", "reply"]` 88 "kind": 11,
61
62- *chat message* (`kind:9`)
63
64This is the basic unit of a _chat message_ sent to a group.
65
66```js
67 "kind": 9,
68 "content": "hello my friends lovers of pizza", 89 "content": "hello my friends lovers of pizza",
69 "tags": [ 90 "tags": [
70 ["h", "<group-id>"], 91 ["h", "<group-id>"],
71 ["previous", "<event-id-first-chars>", "<event-id-first-chars>", ...] 92 ["previous", "<event-id-first-chars>", "<event-id-first-chars>", /*...*/]
72 ] 93 ]
73 ... 94 // other fields...
74``` 95```
75 96
76- *chat message threaded reply* (`kind:10`) 97- _other events_:
77 98
78Similar to `kind:12`, this is the basic unit of a chat message sent to a group. This is intended for in-chat threads that may be hidden by default. Not all in-chat replies MUST use `kind:10`, only when the intention is to create a hidden thread that isn't part of the normal flow of the chat (although clients are free to display those by default too). 99Groups may also accept other events, like [NIP-22](22.md) comments as threaded replies to both chats messages and threads, long-form articles, calendar, livestreams, market announcements and so on. These should be as defined in their respective NIPs, with the addition of the `h` tag.
79 100
80`kind:10` SHOULD use NIP-10 markers, just like `kind:12`. 101### User-related group management events
102
103These are events that can be sent by users to manage their situation in a group, they also require the `h` tag.
81 104
82- *join request* (`kind:9021`) 105- *join request* (`kind:9021`)
83 106
84Any user can send one of these events to the relay in order to be automatically or manually added to the group. If the group is `open` the relay will automatically issue a `kind:9000` in response adding this user. Otherwise group admins may choose to query for these requests and act upon them. 107Any user can send one of these events to the relay in order to be automatically or manually added to the group. If the group is `open` the relay will automatically issue a `kind:9000` in response adding this user. Otherwise group admins may choose to query for these requests and act upon them.
85 108
86```js 109```json
87{ 110{
88 "kind": 9021, 111 "kind": 9021,
89 "content": "optional reason", 112 "content": "optional reason",
90 "tags": [ 113 "tags": [
114 ["h", "<group-id>"],
115 ["code", "<optional-invite-code>"]
116 ]
117}
118```
119
120The optional `code` tag may be used by the relay to preauthorize acceptances in `closed` groups, together with the `kind:9009` `create-invite` moderation event.
121
122- *leave request* (`kind:9022`)
123
124Any user can send one of these events to the relay in order to be automatically removed from the group. The relay will automatically issue a `kind:9001` in response removing this user.
125
126```json
127{
128 "kind": 9022,
129 "content": "optional reason",
130 "tags": [
91 ["h", "<group-id>"] 131 ["h", "<group-id>"]
92 ] 132 ]
93} 133}
94``` 134```
95 135
136### Group state -- or moderation
137
138These are events expected to be sent by the relay master key or by group admins -- and relays should reject them if they don't come from an authorized admin. They also require the `h` tag.
139
96- *moderation events* (`kinds:9000-9020`) (optional) 140- *moderation events* (`kinds:9000-9020`) (optional)
97 141
98Clients can send these events to a relay in order to accomplish a moderation action. Relays must check if the pubkey sending the event is capable of performing the given action. The relay may discard the event after taking action or keep it as a moderation log. 142Clients can send these events to a relay in order to accomplish a moderation action. Relays must check if the pubkey sending the event is capable of performing the given action based on its role and the relay's internal policy (see also the description of `kind:39003`).
99 143
100```js 144```jsonc
101{ 145{
102 "kind": 90xx, 146 "kind": 90xx,
103 "content": "optional reason", 147 "content": "optional reason",
104 "tags": [ 148 "tags": [
105 ["h", "<group-id>"], 149 ["h", "<group-id>"],
106 ["previous", ...] 150 ["previous", /*...*/]
107 ] 151 ]
108} 152}
109``` 153```
110 154
111Each moderation action uses a different kind and requires different arguments, which are given as tags. These are defined in the following table: 155Each moderation action uses a different kind and requires different arguments, which are given as tags. These are defined in the following table:
112 156
113| kind | name | tags | 157| kind | name | tags |
114| --- | --- | --- | 158| --- | --- | --- |
115| 9000 | `add-user` | `p` (pubkey hex) | 159| 9000 | `put-user` | `p` with pubkey hex and optional roles |
116| 9001 | `remove-user` | `p` (pubkey hex) | 160| 9001 | `remove-user` | `p` with pubkey hex |
117| 9002 | `edit-metadata` | `name`, `about`, `picture` (string) | 161| 9002 | `edit-metadata` | fields from `kind:39000` to be modified |
118| 9003 | `add-permission` | `p` (pubkey), `permission` (name) | 162| 9005 | `delete-event` | `e` with event id hex |
119| 9004 | `remove-permission` | `p` (pubkey), `permission` (name) | 163| 9007 | `create-group` | |
120| 9005 | `delete-event` | `e` (id hex) | 164| 9008 | `delete-group` | |
121| 9006 | `edit-group-status` | `public` or `private`, `open` or `closed` | 165| 9009 | `create-invite` | |
166
167It's expected that the group state (of who is an allowed member or not, who is an admin and with which permission or not, what are the group name and picture etc) can be fully reconstructed from the canonical sequence of these events.
168
169### Group metadata events
170
171These events contain the group id in a `d` tag instead of the `h` tag. They MUST be created by the relay master key only and a single instance of each (or none) should exist at all times for each group. They are merely informative but should reflect the latest group state (as it was changed by moderation events over time).
122 172
123- *group metadata* (`kind:39000`) (optional) 173- *group metadata* (`kind:39000`) (optional)
124 174
@@ -126,7 +176,9 @@ This event defines the metadata for the group -- basically how clients should di
126 176
127If the group is forked and hosted in multiple relays, there will be multiple versions of this event in each different relay and so on. 177If the group is forked and hosted in multiple relays, there will be multiple versions of this event in each different relay and so on.
128 178
129```js 179When this event is not found, clients may still connect to the group, but treat it as having a different status, `unmanaged`,
180
181```jsonc
130{ 182{
131 "kind": 39000, 183 "kind": 39000,
132 "content": "", 184 "content": "",
@@ -138,7 +190,7 @@ If the group is forked and hosted in multiple relays, there will be multiple ver
138 ["public"], // or ["private"] 190 ["public"], // or ["private"]
139 ["open"] // or ["closed"] 191 ["open"] // or ["closed"]
140 ] 192 ]
141 ... 193 // other fields...
142} 194}
143``` 195```
144 196
@@ -146,40 +198,29 @@ If the group is forked and hosted in multiple relays, there will be multiple ver
146 198
147- *group admins* (`kind:39001`) (optional) 199- *group admins* (`kind:39001`) (optional)
148 200
149Similar to the group metadata, this event is supposed to be generated by relays that host the group. 201Each admin is listed along with one or more roles. These roles SHOULD have a correspondence with the roles supported by the relay, as advertised by the `kind:39003` event.
150
151Each admin gets a label that is only used for display purposes, and a list of permissions it has are listed afterwards. These permissions can inform client building UI, but ultimately are evaluated by the relay in order to become effective.
152
153The list of capabilities, as defined by this NIP, for now, is the following:
154
155- `add-user`
156- `edit-metadata`
157- `delete-event`
158- `remove-user`
159- `add-permission`
160- `remove-permission`
161- `edit-group-status`
162 202
163```js 203```jsonc
164{ 204{
165 "kind": 39001, 205 "kind": 39001,
166 "content": "list of admins for the pizza lovers group", 206 "content": "list of admins for the pizza lovers group",
167 "tags": [ 207 "tags": [
168 ["d", "<group-id>"], 208 ["d", "<group-id>"],
169 ["p", "<pubkey1-as-hex>", "ceo", "add-user", "edit-metadata", "delete-event", "remove-user"], 209 ["p", "<pubkey1-as-hex>", "ceo"],
170 ["p", "<pubkey2-as-hex>", "secretary", "add-user", "delete-event"] 210 ["p", "<pubkey2-as-hex>", "secretary", "gardener"],
171 ] 211 // other pubkeys...
172 ... 212 ],
213 // other fields...
173} 214}
174``` 215```
175 216
176- *group members* (`kind:39002`) (optional) 217- *group members* (`kind:39002`) (optional)
177 218
178Similar to *group admins*, this event is supposed to be generated by relays that host the group. 219It's a list of pubkeys that are members of the group. Relays might choose to not to publish this information, to restrict what pubkeys can fetch it or to only display a subset of the members in it.
179 220
180It's a NIP-51-like list of pubkeys that are members of the group. Relays might choose to not to publish this information or to restrict what pubkeys can fetch it. 221Clients should not assume this will always be present or that it will contain a full list of members.
181 222
182```json 223```jsonc
183{ 224{
184 "kind": 39002, 225 "kind": 39002,
185 "content": "list of members for the pizza lovers group", 226 "content": "list of members for the pizza lovers group",
@@ -188,10 +229,48 @@ It's a NIP-51-like list of pubkeys that are members of the group. Relays might c
188 ["p", "<admin1>"], 229 ["p", "<admin1>"],
189 ["p", "<member-pubkey1>"], 230 ["p", "<member-pubkey1>"],
190 ["p", "<member-pubkey2>"], 231 ["p", "<member-pubkey2>"],
191 ] 232 // other pubkeys...
233 ],
234 // other fields...
192} 235}
193``` 236```
194 237
195## Storing the list of groups a user belongs to 238- *group roles* (`kind:39003`) (optional)
239
240This is an event that MAY be published by the relay informing users and clients about what are the roles supported by this relay according to its internal logic.
241
242For example, a relay may choose to support the roles `"admin"` and `"moderator"`, in which the `"admin"` will be allowed to edit the group metadata, delete messages and remove users from the group, while the `"moderator"` can only delete messages (or the relay may choose to call these roles `"ceo"` and `"secretary"` instead, the exact role name is not relevant).
243
244The process through which the relay decides what roles to support and how to handle moderation events internally based on them is specific to each relay and not specified here.
245
246```jsonc
247{
248 "kind": 39003,
249 "content": "list of roles supported by this group",
250 "tags": [
251 ["d", "<group-id>"],
252 ["role", "<role-name>", "<optional-description>"],
253 ["role", "<role-name>", "<optional-description>"],
254 // other roles...
255 ],
256 // other fields...
257}
258```
259
260## Implementation quirks
261
262### Checking your own membership in a group
263
264The latest of either `kind:9000` or `kind:9001` events present in a group should tell a user that they are currently members of the group or if they were removed. In case none of these exist the user is assumed to not be a member of the group -- unless the group is `unmanaged`, in which case the user is assumed to be a member.
265
266### Adding yourself to a group
267
268When a group is `open`, anyone can send a `kind:9021` event to it in order to be added, then expect a `kind:9000` event to be emitted confirming that the user was added. The same happens with `closed` groups, except in that case a user may only send a `kind:9021` if it has an invite code.
269
270### Storing your list of groups
271
272A definition for `kind:10009` was included in [NIP-51](51.md) that allows clients to store the list of groups a user wants to remember being in.
273
274### Using `unmanaged` relays
196 275
197A definition for kind `10009` was included in [NIP-51](51.md) that allows clients to store the list of groups a user wants to remember being in. 276To prevent event leakage, replay and confusion, when using `unmanaged` relays, clients should include the [NIP-70](70.md) `-` tag, as just the `previous` tag won't be checked by other `unmanaged` relays.