1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
NIP-C1
======
Collaborative Ownership
-----------------------
`draft` `optional`
This NIP defines a mechanism for multiple pubkeys to collaboratively maintain addressable events while preserving backwards compatibility.
## Motivation
Certain applications require shared ownership where:
1. **Attribution matters**: Each collaborator signs with their own key
2. **Dynamic membership**: Owners can be added or removed
3. **Backwards compatibility**: Non-supporting clients see normal events
## Specification
### Collaborative Pointer Event
A new addressable event kind `39382` serves as a pointer to collaboratively-owned content:
```jsonc
{
"kind": 39382,
"pubkey": "<creator-pubkey>",
"tags": [
["d", "<slug>"],
["k", "<target-kind>"],
["p", "<owner-1-pubkey>"],
["p", "<owner-2-pubkey>"],
["p", "<owner-3-pubkey>"]
],
"content": "",
"created_at": 1234567890
}
```
#### Tag Definitions
| Tag | Required | Description |
|-----|----------|-------------|
| `d` | Yes | `<slug> |`
| `k` | Yes | Target event kind |
| `p` | Yes | Owner pubkeys (one or more) |
### Resolution Algorithm
To resolve the current state of collaboratively-owned content:
1. Parse the `39382` pointer event to extract owners (`p` tags) and target kind (`k` tag)
2. Extract the slug from the `d` tag (everything after the first `-`)
3. Query: `{"kinds": [<target-kind>], "authors": [<all-owners>], "#d": ["<slug>"], "limit": 1}`
### Back-Reference
Target events MUST include an `a` tag pointing to the `39382` pointer:
```jsonc
{
"kind": 30023,
"tags": [
["d", "my-article"],
["a", "39382:<pointer-creator-pubkey>:30023-my-article"]
]
}
```
This allows clients to discover collaborative ownership from either direction: pointer → content or content → pointer.
## Example
### Pointer Event
```jsonc
{
"kind": 39382,
"pubkey": "alice-pubkey",
"tags": [
["d", "collaborative-guide"],
["k", "30023"],
["p", "alice-pubkey"],
["p", "bob-pubkey"],
["p", "carol-pubkey"]
],
"content": ""
}
```
### Target Article (by any owner)
```jsonc
{
"kind": 30023,
"pubkey": "bob-pubkey",
"tags": [
["d", "collaborative-guide"],
["title", "A Collaborative Guide"],
["a", "39382:alice-pubkey:30023-collaborative-guide"]
],
"content": "..."
}
```
### Client Resolution
1. Client receives `naddr` for the `39382` pointer
2. Parses owners: `[alice, bob, carol]`
3. Queries: `{"kinds": [30023], "authors": ["alice", "bob", "carol"], "#d": ["collaborative-guide"], "limit": 1}`
4. Returns most recent version regardless of which owner published it
|