mirror of
https://github.com/nostr-protocol/nips.git
synced 2025-12-09 00:28:51 +00:00
Compare commits
9 Commits
stream-ext
...
llm-stuff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8966eb103 | ||
|
|
3430b8bf3d | ||
|
|
37bc37c95a | ||
|
|
cddab6d244 | ||
|
|
569f55a90f | ||
|
|
9eb4a33049 | ||
|
|
a6a2020933 | ||
|
|
509613b9fa | ||
|
|
0c993526f0 |
4
01.md
4
01.md
@@ -85,7 +85,7 @@ As a convention, all single-letter (only english alphabet letters: a-z, A-Z) key
|
||||
|
||||
### Kinds
|
||||
|
||||
Kinds specify how clients should interpret the meaning of each event and the other fields of each event (e.g. an `"r"` tag may have a meaning in an event of kind 1 and an entirely different meaning in an event of kind 10002). Each NIP may define the meaning of a set of kinds that weren't defined elsewhere. [NIP-10](10.md), for instance, especifies the `kind:1` text note for social media applications.
|
||||
Kinds specify how clients should interpret the meaning of each event and the other fields of each event (e.g. an `"r"` tag may have a meaning in an event of kind 1 and an entirely different meaning in an event of kind 10002). Each NIP may define the meaning of a set of kinds that weren't defined elsewhere. [NIP-10](10.md), for instance, specifies the `kind:1` text note for social media applications.
|
||||
|
||||
This NIP defines one basic kind:
|
||||
|
||||
@@ -144,7 +144,7 @@ All conditions of a filter that are specified must match for an event for it to
|
||||
|
||||
A `REQ` message may contain multiple filters. In this case, events that match any of the filters are to be returned, i.e., multiple filters are to be interpreted as `||` conditions.
|
||||
|
||||
The `limit` property of a filter is only valid for the initial query and MUST be ignored afterwards. When `limit: n` is present it is assumed that the events returned in the initial query will be the last `n` events ordered by the `created_at`. Newer events should appear first, and in the case of ties the event with the lowest id (first in lexical order) should be first. It is safe to return less events than `limit` specifies, but it is expected that relays do not return (much) more events than requested so clients don't get unnecessarily overwhelmed by data.
|
||||
The `limit` property of a filter is only valid for the initial query and MUST be ignored afterwards. When `limit: n` is present it is assumed that the events returned in the initial query will be the last `n` events ordered by the `created_at`. Newer events should appear first, and in the case of ties the event with the lowest id (first in lexical order) should be first. Relays SHOULD use the `limit` value to guide how many events are returned in the initial response. Returning fewer events is acceptable, but returning (much) more should be avoided to prevent overwhelming clients.
|
||||
|
||||
### From relay to client: sending events and notices
|
||||
|
||||
|
||||
2
19.md
2
19.md
@@ -34,7 +34,7 @@ These are the possible bech32 prefixes with `TLV`:
|
||||
|
||||
- `nprofile`: a nostr profile
|
||||
- `nevent`: a nostr event
|
||||
- `naddr`: a nostr _replaceable event_ coordinate
|
||||
- `naddr`: a nostr _addressable event_ coordinate
|
||||
- `nrelay`: a nostr relay (deprecated)
|
||||
|
||||
These possible standardized `TLV` types are indicated here:
|
||||
|
||||
20
21.md
20
21.md
@@ -12,9 +12,27 @@ The scheme is `nostr:`.
|
||||
|
||||
The identifiers that come after are expected to be the same as those defined in [NIP-19](19.md) (except `nsec`).
|
||||
|
||||
## Examples
|
||||
#### Examples
|
||||
|
||||
- `nostr:npub1sn0wdenkukak0d9dfczzeacvhkrgz92ak56egt7vdgzn8pv2wfqqhrjdv9`
|
||||
- `nostr:nprofile1qqsrhuxx8l9ex335q7he0f09aej04zpazpl0ne2cgukyawd24mayt8gpp4mhxue69uhhytnc9e3k7mgpz4mhxue69uhkg6nzv9ejuumpv34kytnrdaksjlyr9p`
|
||||
- `nostr:note1fntxtkcy9pjwucqwa9mddn7v03wwwsu9j330jj350nvhpky2tuaspk6nqc`
|
||||
- `nostr:nevent1qqstna2yrezu5wghjvswqqculvvwxsrcvu7uc0f78gan4xqhvz49d9spr3mhxue69uhkummnw3ez6un9d3shjtn4de6x2argwghx6egpr4mhxue69uhkummnw3ez6ur4vgh8wetvd3hhyer9wghxuet5nxnepm`
|
||||
|
||||
### Linking HTML pages to Nostr entities
|
||||
|
||||
`<link>` tags with `rel="alternate"` can be used to associate webpages to Nostr events, in cases where the same content is served via the two mediums (for example, a web server that exposes Markdown articles both as HTML pages and as `kind:30023' events served under itself as a relay or through some other relay). For example:
|
||||
|
||||
```
|
||||
<head>
|
||||
<link rel="alternate" href="nostr:naddr1qqyrzwrxvc6ngvfkqyghwumn8ghj7enfv96x5ctx9e3k7mgzyqalp33lewf5vdq847t6te0wvnags0gs0mu72kz8938tn24wlfze6qcyqqq823cph95ag" />
|
||||
</head>
|
||||
```
|
||||
|
||||
Likewise, `<link>` tags with `rel="me"` or `rel="author"` can be used to assign authorship of webpages to Nostr profiles. For example:
|
||||
|
||||
```
|
||||
<head>
|
||||
<link rel="me" href="nostr:nprofile1qyxhwumn8ghj7mn0wvhxcmmvqyd8wumn8ghj7un9d3shjtnhv4ehgetjde38gcewvdhk6qpq80cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwswpnfsn" />
|
||||
</head>
|
||||
```
|
||||
|
||||
32
25.md
32
25.md
@@ -7,38 +7,38 @@ Reactions
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
A reaction is a `kind 7` event that is used to react to other events.
|
||||
A reaction is a `kind 7` event that is used to indicate user reactions to other events. A
|
||||
reaction's `content` field MUST include user-generated-content indicating the value of the
|
||||
reaction (conventionally `+`, `-`, or an emoji).
|
||||
|
||||
The generic reaction, represented by the `content` set to a `+` string, SHOULD
|
||||
be interpreted as a "like" or "upvote".
|
||||
A reaction with `content` set to `+` or an empty string MUST be interpreted as a "like" or "upvote".
|
||||
A reaction with `content` set to `-` MUST be interpreted as a "dislike" or "downvote".
|
||||
|
||||
A reaction with `content` set to `-` SHOULD be interpreted as a "dislike" or
|
||||
"downvote". It SHOULD NOT be counted as a "like", and MAY be displayed as a
|
||||
downvote or dislike on a post. A client MAY also choose to tally likes against
|
||||
dislikes in a reddit-like system of upvotes and downvotes, or display them as
|
||||
separate tallies.
|
||||
|
||||
The `content` MAY be an emoji, or [NIP-30](30.md) custom emoji in this case it MAY be interpreted as a "like" or "dislike",
|
||||
or the client MAY display this emoji reaction on the post. If the `content` is an empty string then the client should
|
||||
consider it a "+".
|
||||
A reaction with `content` set to an emoji or [NIP-30](30.md) custom emoji SHOULD NOT be interpreted
|
||||
as a "like" or "dislike". Clients MAY instead display this emoji reaction on the post.
|
||||
|
||||
Tags
|
||||
----
|
||||
|
||||
There MUST be always an `e` tag set to the `id` of the event that is being reacted to. The `e` tag SHOULD include a relay hint pointing to a relay where the event being reacted to can be found. If a client decides to include other `e`, which not recommended, the target event `id` should be last of the `e` tags.
|
||||
|
||||
The SHOULD be a `p` tag set to the `pubkey` of the event being reacted to. If a client decides to include other `p` tags, which not recommended, the target event `pubkey` should be last the `p` tags.
|
||||
There SHOULD be a `p` tag set to the `pubkey` of the event being reacted to. If a client decides to include other `p` tags, which not recommended, the target event `pubkey` should be last the `p` tags.
|
||||
|
||||
If the event being reacted to is an addressable event, an `a` SHOULD be included together with the `e` tag, it must be set to the coordinates (`kind:pubkey:d-tag`) of the event being reacted to.
|
||||
|
||||
The reaction SHOULD include a `k` tag with the stringified kind number of the reacted event as its value.
|
||||
|
||||
The `e` and `a` tags SHOULD include relay and pubkey hints. The `p` tags SHOULD include relay hints.
|
||||
|
||||
The reaction event MAY include a `k` tag with the stringified kind number of the reacted event as its value.
|
||||
|
||||
**Example code**
|
||||
|
||||
```swift
|
||||
func make_like_event(pubkey: String, privkey: String, liked: NostrEvent) -> NostrEvent {
|
||||
tags.append(["e", liked.id, liked.source_relays.first ?? ""])
|
||||
tags.append(["p", liked.pubkey])
|
||||
func make_like_event(pubkey: String, privkey: String, liked: NostrEvent, hint: String) -> NostrEvent {
|
||||
var tags: [[String]] = []
|
||||
tags.append(["e", liked.id, hint, liked.pubkey])
|
||||
tags.append(["p", liked.pubkey, hint])
|
||||
tags.append(["k", String(liked.kind)])
|
||||
let ev = NostrEvent(content: "+", pubkey: pubkey, kind: 7, tags: tags)
|
||||
ev.calculate_id()
|
||||
|
||||
73
53.md
73
53.md
@@ -84,79 +84,6 @@ Event `kind:1311` is live chat's channel message. Clients MUST include the `a` t
|
||||
|
||||
Hosts may choose to pin one or more live chat messages by updating the `pinned` tags in the live event kind `30311`.
|
||||
|
||||
### Stream Raids
|
||||
|
||||
Event `kind:1312` is a live stream raid (redirect viewers to another stream).
|
||||
|
||||
Clients MUST include two `a` tags, one marked as `from` and the other marked as `to` which redirects viewers to a new live stream.
|
||||
The `content` MAY contain a raid message.
|
||||
|
||||
Clients SHOULD automatically redirect viewers from one stream to another.
|
||||
This is a similar function used on Twitch also called raids.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 1312,
|
||||
"tags": [
|
||||
["a", "30311:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>", "from"],
|
||||
["a", "30311:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>", "to"],
|
||||
],
|
||||
"content": "Zap this epic streamer!",
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
### Stream Clips
|
||||
|
||||
Event `kind:1313` is a live stream clip.
|
||||
|
||||
A clip is a small video clip taken from the live stream used to highlight a specific memorable or entertaining part of the stream.
|
||||
|
||||
Clients MUST include one `a` tag which points to the live stream event which the clip was taken from.
|
||||
|
||||
Clients MUST include one `r` tag which is a URL pointing to the video clip file, preferably in MP4 format for maximum compatibility.
|
||||
|
||||
Clients MAY also include a message about the clip in the `title` tag.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 1313,
|
||||
"tags": [
|
||||
["a", "30311:<Community event author pubkey>:<d-identifier of the community>", "<Optional relay url>", "root"],
|
||||
["r", "https://example.com/my-clip.mp4"],
|
||||
["title", "Streamer gets rekt by bot!"]
|
||||
],
|
||||
"content": "",
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
### Stream Timeout
|
||||
|
||||
Event `kind:1314` is a live chat moderation event that temporarily mutes a user from chatting.
|
||||
|
||||
Clients MUST include one or more `p` tags of the timed out users.
|
||||
|
||||
Clients MUST include a [NIP-40](./40.md) expiration timestamp which signals when the timeout will end.
|
||||
|
||||
Clients SHOULD enfore timeouts by disabling chat functions in their apps and not displaying any chat messages from the user during their timeout.
|
||||
|
||||
Clients SHOULD listen for timeout events published by the stream host.
|
||||
|
||||
Clients MAY include a reason for the timeout in the `content` field.
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"kind": 1314,
|
||||
"tags": [
|
||||
["p", "<pubkey-of-muted-user>"],
|
||||
["expiration", "1747658333"]
|
||||
],
|
||||
"content": "Rude",
|
||||
// other fields...
|
||||
}
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
Common use cases include meeting rooms/workshops, watch-together activities, or event spaces, such as [zap.stream](https://zap.stream).
|
||||
|
||||
175
77.md
Normal file
175
77.md
Normal file
@@ -0,0 +1,175 @@
|
||||
NIP-77
|
||||
======
|
||||
|
||||
Negentropy Syncing
|
||||
------------------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This document describes a protocol extension for syncing events. It works for both client-relay and relay-relay scenarios. If both sides of the sync have events in common, then this protocol will use less bandwidth than transferring the full set of events (or even just their IDs).
|
||||
|
||||
It is a Nostr-friendly wrapper around the [Negentropy](https://github.com/hoytech/negentropy) protocol, which uses a technique called [Range-Based Set Reconciliation](https://logperiodic.com/rbsr.html).
|
||||
|
||||
Since Negentropy is a binary protocol, this wrapper hex-encodes its messages. The specification for Negentropy Protocol V1 is attached as an appendix to this NIP below.
|
||||
|
||||
## High-Level Protocol Description
|
||||
|
||||
We're going to call the two sides engaged in the sync the client and the relay (even though the initiator could be another relay instead of a client).
|
||||
|
||||
* (1) Client (initiator) chooses a filter, and retrieves the set of events that it has locally that match this filter (or uses a cache), and constructs an initial message.
|
||||
* (2) Client sends a `NEG-OPEN` message to the relay, which includes the filter and the initial message.
|
||||
* (3) Relay selects the set of events that it has locally that match the filter (or uses a cache).
|
||||
* (4) Relay constructs a response and returns it to the client in a `NEG-MSG` message.
|
||||
* (5) Client parses the message to learn about IDs it has (and relay needs) and IDs it needs (and relay has).
|
||||
* If client wishes to continue, then it constructs a new message and sends it to the relay in a `NEG-MSG` message. Goto step 4.
|
||||
* If client wishes to stop, then it sends a `NEG-CLOSE` message or disconnects the websocket.
|
||||
|
||||
The above protocol only results in the client learning about IDs it has/needs, and does not actually transfer events. Given these IDs, the client can upload events it has with `EVENT`, and/or download events it needs with `REQ`. This can be performed over the same websocket connection in parallel with subsequent `NEG-MSG` messages. If a client is only interested in determining the number of unique events (ie, reaction counts), it may choose to not download/upload at all.
|
||||
|
||||
## Nostr Messages
|
||||
|
||||
### Initial message (client to relay):
|
||||
|
||||
```jsonc
|
||||
[
|
||||
"NEG-OPEN",
|
||||
<subscription ID string>,
|
||||
<filter>,
|
||||
<initialMessage, hex-encoded>
|
||||
]
|
||||
```
|
||||
|
||||
* The subscription ID is used by each side to identify which query a message refers to. It only needs to be long enough to distinguish it from any other concurrent subscriptions on this websocket connection (an integer that increments once per `NEG-OPEN` is fine). Subscription IDs are in a separate namespace from `REQ` subscription IDs. If a `NEG-OPEN` is issued for a currently open subscription ID, the existing subscription is first closed.
|
||||
* The filter is as described in [NIP-01](01.md).
|
||||
* `initialMessage` is the initial Negentropy binary message, hex-encoded. See appendix.
|
||||
|
||||
### Error message (relay to client):
|
||||
|
||||
If a request cannot be serviced by the relay, an error is returned to the client:
|
||||
|
||||
```jsonc
|
||||
[
|
||||
"NEG-ERR",
|
||||
<subscription ID string>,
|
||||
<reason code string>
|
||||
]
|
||||
```
|
||||
|
||||
Error reasons are the same format as in NIP-01. They should begin with a machine-readable single-word prefix, followed by a `:` and then a human-readable message with more information.
|
||||
|
||||
The current suggested error reasons are
|
||||
|
||||
* `blocked`
|
||||
* Relays can optionally reject queries that would require them to process too many records, or records that are too old
|
||||
* The maximum number of records that can be processed can optionally be returned as the 4th element in the response
|
||||
* Example: `blocked: this query is too big`
|
||||
* `closed`
|
||||
* Because the `NEG-OPEN` queries may be stateful, relays may choose to time-out inactive queries to recover memory resources
|
||||
* Example: `closed: you took too long to respond!`
|
||||
|
||||
After a `NEG-ERR` is issued, the subscription is considered to be closed.
|
||||
|
||||
### Subsequent messages (bidirectional):
|
||||
|
||||
Relay and client alternate sending each other `NEG-MSG`s:
|
||||
|
||||
```jsonc
|
||||
[
|
||||
"NEG-MSG",
|
||||
<subscription ID string>,
|
||||
<message, hex-encoded>
|
||||
]
|
||||
```
|
||||
|
||||
* `message` is a Negentropy binary message, hex-encoded. Both message directions use the same format. See appendix.
|
||||
|
||||
### Close message (client to relay):
|
||||
|
||||
When finished, the client should tell the relay it can release its resources with a `NEG-CLOSE`:
|
||||
|
||||
```jsonc
|
||||
[
|
||||
"NEG-CLOSE",
|
||||
<subscription ID string>
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
## Appendix: Negentropy Protocol V1
|
||||
|
||||
### Preparation
|
||||
|
||||
There are two protocol participants: Client and server. The client creates an initial message and transmits it to the server, which replies with its own message in response. The client continues querying the server until it is satisifed, and then terminates the protocol. Messages in either direction have the same format.
|
||||
|
||||
Each participant has a collection of records. A records consists of a 64-bit numeric timestamp and a 256-bit ID. Each participant starts by sorting their items according to timestamp, ascending. If two timestamps are equal then items are sorted lexically by ID, ascending by first differing byte. Items may not use the max uint64 value (`2**64 - 1`) as a timestamp since this is reserved as a special "infinity" value.
|
||||
|
||||
The goal of the protocol is for the client to learn the set of IDs that it has and the server does not, and the set of items that the server has and it does not.
|
||||
|
||||
### `Varint`
|
||||
|
||||
Varints (variable-sized unsigned integers) are represented as base-128 digits, most significant digit first, with as few digits as possible. Bit eight (the high bit) is set on each byte except the last.
|
||||
|
||||
Varint := <Digit+128>* <Digit>
|
||||
|
||||
### `Id`
|
||||
|
||||
IDs are represented as byte-strings of length `32`:
|
||||
|
||||
Id := Byte{32}
|
||||
|
||||
### `Message`
|
||||
|
||||
A reconciliation message is a protocol version byte followed by an ordered list of ranges:
|
||||
|
||||
Message := <protocolVersion (Byte)> <Range>*
|
||||
|
||||
The current protocol version is 1, represented by the byte `0x61`. Protocol version 2 will be `0x62`, and so forth. If a server receives a message with a protocol version that it cannot handle, it should reply with a single byte containing the highest protocol version it supports, allowing the client to downgrade and retry its message.
|
||||
|
||||
Each Range corresponds to a contiguous section of the timestamp/ID space. The first Range starts at timestamp 0 and an ID of 0 bytes. Ranges are always adjacent (no gaps). If the last Range doesn't end at the special infinity value, an implicit `Skip` to infinity Range is appended. This means that the list of Ranges always covers the full timestamp/ID space.
|
||||
|
||||
### `Range`
|
||||
|
||||
A Range consists of an upper bound, a mode, and a payload:
|
||||
|
||||
Range := <upperBound (Bound)> <mode (Varint)> <payload (Skip | Fingerprint | IdList)>
|
||||
|
||||
The contents of the payload is determined by mode:
|
||||
|
||||
* If `mode = 0`, then payload is `Skip`, meaning the sender does not wish to process this Range further. This payload is empty:
|
||||
|
||||
Skip :=
|
||||
|
||||
* If `mode = 1`, then payload is a `Fingerprint`, which is a [digest](#fingerprint-algorithm) of all the IDs the sender has within the Range:
|
||||
|
||||
Fingerprint := Byte{16}
|
||||
|
||||
* If `mode = 2`, the payload is `IdList`, a variable-length list of all IDs the sender has within the Range:
|
||||
|
||||
IdList := <length (Varint)> <ids (Id)>*
|
||||
|
||||
|
||||
### `Bound`
|
||||
|
||||
Each Range is specified by an *inclusive* lower bound and an *exclusive* upper bound. As defined above, each Range only includes an upper bound: the lower bound of a Range is the upper bound of the previous Range, or 0 timestamp/0 ID for the first Range.
|
||||
|
||||
A Bound consists of an encoded timestamp and a variable-length disambiguating prefix of an ID (in case multiple items have the same timestamp):
|
||||
|
||||
Bound := <encodedTimestamp (Varint)> <length (Varint)> <idPrefix (Byte)>*
|
||||
|
||||
* The timestamp is encoded specially. The infinity timestamp is encoded as `0`. All other values are encoded as `1 + offset`, where offset is the difference between this timestamp and the previously encoded timestamp. The initial offset starts at `0` and resets at the beginning of each message.
|
||||
|
||||
Offsets are always non-negative since the upper bound's timestamp is greater than or equal to the lower bound's timestamp, ranges in a message are always encoded in ascending order, and ranges never overlap.
|
||||
|
||||
* The size of `idPrefix` is encoded in `length`, and can be between `0` and `32` bytes, inclusive. This allows implementations to use the shortest possible prefix to separate the first record of this Range from the last record of the previous Range. If these records' timestamps differ, then the length should be 0, otherwise it should be the byte-length of their common ID-prefix plus 1.
|
||||
|
||||
If the `idPrefix` length is less than `32` then the omitted trailing bytes are implicitly 0 bytes.
|
||||
|
||||
|
||||
### Fingerprint Algorithm
|
||||
|
||||
The fingerprint of a Range is computed with the following algorithm:
|
||||
|
||||
* Compute the addition mod 2<sup>256</sup> of the element IDs (interpreted as 32-byte little-endian unsigned integers)
|
||||
* Concatenate with the number of elements in the Range, encoded as a [Varint](#varint)
|
||||
* Hash with SHA-256
|
||||
* Take the first 16 bytes
|
||||
2
84.md
2
84.md
@@ -23,7 +23,7 @@ or obvious non-useful information from the query string.
|
||||
### Attribution
|
||||
Clients MAY include one or more `p` tags, tagging the original authors of the material being highlighted; this is particularly
|
||||
useful when highlighting non-nostr content for which the client might be able to get a nostr pubkey somehow
|
||||
(e.g. prompting the user or reading a `<meta name="nostr:nprofile1..." />` tag on the document). A role MAY be included as the
|
||||
(e.g. prompting the user or reading a `<link rel="me" href="nostr:nprofile1..." />` tag on the document). A role MAY be included as the
|
||||
last value of the tag.
|
||||
|
||||
```jsonc
|
||||
|
||||
@@ -88,6 +88,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
- [NIP-72: Moderated Communities](72.md)
|
||||
- [NIP-73: External Content IDs](73.md)
|
||||
- [NIP-75: Zap Goals](75.md)
|
||||
- [NIP-77: Negentropy Syncing](77.md)
|
||||
- [NIP-78: Application-specific data](78.md)
|
||||
- [NIP-7D: Threads](7D.md)
|
||||
- [NIP-84: Highlights](84.md)
|
||||
@@ -150,10 +151,7 @@ They exist to document what may be implemented by [Nostr](https://github.com/nos
|
||||
| `1063` | File Metadata | [94](94.md) |
|
||||
| `1068` | Poll | [88](88.md) |
|
||||
| `1111` | Comment | [22](22.md) |
|
||||
| `1311` | Live Stream Chat Message | [53](53.md) |
|
||||
| `1312` | Live Stream Raid | [53](53.md) |
|
||||
| `1313` | Live Stream Clip | [53](53.md) |
|
||||
| `1314` | Live Stream Timeout | [53](53.md) |
|
||||
| `1311` | Live Chat Message | [53](53.md) |
|
||||
| `1337` | Code Snippet | [C0](C0.md) |
|
||||
| `1617` | Patches | [34](34.md) |
|
||||
| `1621` | Issues | [34](34.md) |
|
||||
|
||||
72
xx.md
Normal file
72
xx.md
Normal file
@@ -0,0 +1,72 @@
|
||||
NIP-XX
|
||||
======
|
||||
|
||||
LLM Stuff
|
||||
---------
|
||||
|
||||
`draft` `optional`
|
||||
|
||||
This NIP defines kinds related to LLM stuff.
|
||||
|
||||
# Prompt diffs
|
||||
a way to publish LLM prompts that describe modifications to software projects. Where code diffs usually expire in a couple of releases and require constant upkeep,tThese "prompt diffs" enable way longer-lasting, shareable software modifications.
|
||||
|
||||
## Abstract
|
||||
|
||||
A prompt diff is a Nostr event that contains instructions for an LLM to modify a codebase. Prompt diffs describe the intent and let LLMs handle the implementation details.
|
||||
|
||||
## Event Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": 496,
|
||||
"content": "<human-readable-description>",
|
||||
"tags": [
|
||||
["title", "<modification-title>"],
|
||||
["description", "<prompt>"],
|
||||
["r", "<git-repository-url>"],
|
||||
["t", "<tag>"],
|
||||
["model", "<suggested-llm-model>"],
|
||||
]
|
||||
}
|
||||
Required Tags
|
||||
|
||||
title - Short title describing the modification
|
||||
r - Git repository URL this applies to
|
||||
prompt - The actual prompt containing modification instructions
|
||||
|
||||
## Optional Tags
|
||||
|
||||
t - Hashtags for categorization (#security, #performance, #feature-removal, etc.)
|
||||
model - Suggested LLM model that successfully applies this modification
|
||||
|
||||
Example: Remove Edit Functionality from Amethyst
|
||||
json{
|
||||
"kind": 496,
|
||||
"pubkey": "...",
|
||||
"created_at": 1234567890,
|
||||
"content": "Removes the ability to edit kind:1 text notes in Amethyst",
|
||||
"tags": [
|
||||
["title", "Remove Kind:1 Edit Functionality"],
|
||||
["description", "Remove all edit functionality for kind:1 events from the Amethyst Android app. This includes:\n\n1. Find and remove the edit button/icon from the note options menu (three dots menu) for kind:1 events\n2. Remove any edit action handlers, click listeners, or menu item cases related to editing kind:1 notes\n3. Remove or disable any UI components like EditPostView or EditPostDialog that are used for editing existing posts\n4. Keep the edit functionality for other event kinds if they exist (like kind:30023 long-form content)\n5. Remove any edit-related permissions checks or business logic specific to kind:1 events\n6. Clean up any unused imports or resources that were only used for kind:1 editing\n7. Do not remove the ability to create new kind:1 posts, only the ability to edit existing ones\n8. Look for edit functionality in:\n - Note composition screens\n - Note option menus \n - ViewModels handling note actions\n - Any files with names containing 'Edit' and 'Note' or 'Post'\n\nMake sure the app still compiles and runs after these changes. The diff should be clean with no leftover dead code."],
|
||||
["r", "https://github.com/vitorpamplona/amethyst"],
|
||||
["t", "noedits"],
|
||||
["t", "amethyst"],
|
||||
["model", "claude-3.5-sonnet"],
|
||||
],
|
||||
"sig": "..."
|
||||
}
|
||||
|
||||
# Implementation Guidelines
|
||||
### For Prompt Authors
|
||||
|
||||
Write clear, specific prompts that describe intent rather than implementation
|
||||
Include context about why changes should be made in certain locations
|
||||
Specify what should NOT be changed to prevent over-modification
|
||||
Add test commands to verify the modification works
|
||||
Test prompts against the current main branch of the repository
|
||||
|
||||
# Security Considerations
|
||||
|
||||
* Always review LLM-generated changes before applying
|
||||
* Prompt Injection Protection: Clients MUST sanitize repository file contents before passing to LLMs to prevent malicious code comments or documentation from hijacking the modification intent
|
||||
Reference in New Issue
Block a user