nips/34.md

10 KiB

NIP-34

git stuff

draft optional

This NIP defines all the ways code collaboration using and adjacent to git can be done using Nostr.

Repository announcements

Git repositories are hosted in Git-enabled servers, but their existence can be announced using Nostr events, as well as their willingness to receive patches, bug reports and comments in general.

{
  "kind": 30617,
  "content": "",
  "tags": [
    ["d", "<repo-id>"], // usually kebab-case short name
    ["name", "<human-readable project name>"],
    ["description", "brief human-readable project description>"],
    ["web", "<url for browsing>", ...], // a webpage url, if the git server being used provides such a thing
    ["clone", "<url for git-cloning>", ...], // a url to be given to `git clone` so anyone can clone it
    ["relays", "<relay-url>", ...], // relays that this repository will monitor for patches and issues
    ["r", "<earliest-unique-commit-id>", "euc"],
    ["maintainers", "<other-recognized-maintainer>", ...],
    ["t", "<arbitrary string>"], // hashtags labelling the repository
  ]
}

The tags web, clone, relays, maintainers can have multiple values.

The r tag annotated with the "euc" marker should be the commit ID of the earliest unique commit of this repo, made to identify it among forks and group it with other repositories hosted elsewhere that may represent essentially the same project. In most cases it will be the root commit of a repository. In case of a permanent fork between two projects, then the first commit after the fork should be used.

Except d, all tags are optional.

Repository state announcements

An optional source of truth for the state of branches and tags in a repository.

{
  "kind": 30618,
  "content": "",
  "tags": [
    ["d", "<repo-id>"], // matches the identifier in the coresponding repository announcement
    ["refs/<heads|tags>/<branch-or-tag-name>","<commit-id>"]
    ["HEAD", "ref: refs/heads/<branch-name>"]
  ]
}

The refs tag may appear multiple times, or none.

If no refs tags are present, the author is no longer tracking repository state using this event. This approach enables the author to restart tracking state at a later time unlike NIP-09 deletion requests.

The refs tag can be optionally extended to enable clients to identify how many commits ahead a ref is:

{
  "tags": [
    ["refs/<heads|tags>/<branch-or-tag-name>", "<commit-id>", "<shorthand-parent-commit-id>", "<shorthand-grandparent>", ...],
  ]
}

Patches

Patches can be sent by anyone to any repository. Patches to a specific repository SHOULD be sent to the relays specified in that repository's announcement event's "relays" tag. Patch events SHOULD include an a tag pointing to that repository's announcement address.

Patches in a patch set SHOULD include a NIP-10 e reply tag pointing to the previous patch.

The first patch revision in a patch revision SHOULD include a NIP-10 e reply to the original root patch.

{
  "kind": 1617,
  "content": "<patch>", // contents of <git format-patch>
  "tags": [
    ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
    ["r", "<earliest-unique-commit-id-of-repo>"] // so clients can subscribe to all patches sent to a local git repo
    ["p", "<repository-owner>"],
    ["p", "<other-user>"], // optionally send the patch to another user to bring it to their attention

    ["t", "root"], // omitted for additional patches in a series
    // for the first patch in a revision
    ["t", "root-revision"],

    // optional tags for when it is desirable that the merged patch has a stable commit id
    // these fields are necessary for ensuring that the commit resulting from applying a patch
    // has the same id as it had in the proposer's machine -- all these tags can be omitted
    // if the maintainer doesn't care about these things
    ["commit", "<current-commit-id>"],
    ["r", "<current-commit-id>"] // so clients can find existing patches for a specific commit
    ["parent-commit", "<parent-commit-id>"],
    ["commit-pgp-sig", "-----BEGIN PGP SIGNATURE-----..."], // empty string for unsigned commit
    ["committer", "<name>", "<email>", "<timestamp>", "<timezone offset in minutes>"],
  ]
}

The first patch in a series MAY be a cover letter in the format produced by git format-patch.

Issues

Issues are Markdown text that is just human-readable conversational threads related to the repository: bug reports, feature requests, questions or comments of any kind. Like patches, these SHOULD be sent to the relays specified in that repository's announcement event's "relays" tag.

Issues may have a subject tag, which clients can utilize to display a header. Additionally, one or more t tags may be included to provide labels for the issue.

{
  "kind": 1621,
  "content": "<markdown text>",
  "tags": [
    ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
    ["p", "<repository-owner>"]
    ["subject", "<issue-subject>"]
    ["t", "<issue-label>"]
    ["t", "<another-issue-label>"]
  ]
}

Replies

Replies to either a kind:1621 issue or a kind:1617 patch event should follow NIP-22 comment.

Status

Root Patches and Issues have a Status that defaults to 'Open' and can be set by issuing Status events.

{
  "kind": 1630, // Open
  "kind": 1631, // Applied / Merged for Patches; Resolved for Issues
  "kind": 1632, // Closed
  "kind": 1633, // Draft
  "content": "<markdown text>",
  "tags": [
    ["e", "<issue-or-original-root-patch-id-hex>", "", "root"],
    ["e", "<accepted-revision-root-id-hex>", "", "reply"], // for when revisions applied
    ["p", "<repository-owner>"],
    ["p", "<root-event-author>"],
    ["p", "<revision-author>"],

    // optional for improved subscription filter efficiency
    ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>", "<relay-url>"],
    ["r", "<earliest-unique-commit-id-of-repo>"]

    // optional for `1631` status
    ["e", "<applied-or-merged-patch-event-id>", "", "mention"], // for each
    // when merged
    ["merge-commit", "<merge-commit-id>"]
    ["r", "<merge-commit-id>"]
    // when applied
    ["applied-as-commits", "<commit-id-in-master-branch>", ...]
    ["r", "<applied-commit-id>"] // for each
  ]
}

The Status event with the largest created_at date is valid.

The Status of a patch-revision defaults to either that of the root-patch, or 1632 (Closed) if the root-patch's Status is 1631 and the patch-revision isn't tagged in the 1631 event.

Git Diffs

Git Diff events (kind: 1622) represent changes between two commits within a Git repository, encapsulated as a unified diff. This event type is distinct from Git patches as it explicitly represents the state difference between two specific commits rather than modifications intended for direct application.

Clients should render the event's content field as preformatted unified diff text (commonly displayed with diff highlighting).

{
  "kind": 1622,
  "content": "<git unified-diff content>",
  "tags": [
    // Reference to the repo's 30617 event if one exists 
    ["a", "30617:<base-repo-owner-pubkey>:<base-repo-id>"],
    // Explicit commit ID this diff represents (mandatory)
    ["commit", "<current-commit-id>"],
    // Parent commit ID from which the diff is generated (mandatory)
    ["parent-commit", "<parent-commit-id>"],

    // Explicit repository URL (optional if resolvable via 'a' tag, recommended for interoperability)
    ["repo", "https://github.com/user/repo.git"],
    // refs associated with the repository
    ["refs/<heads|tags>/<branch-or-tag-name>","<commit-id>"]
    // File path within the repository affected by this diff (optional but recommended if diff is single-file)
    ["file", "<fully-qualified-filepath>"],
    // Optional start and end lines in the diff context (recommended for precise referencing)
    ["lines", "172", "196"],
    // Optional description for context or explanation of changes
    ["description", "Implements new diff handling in NIP-34"]
  ]
}

Clients rendering Git Diff events SHOULD:

  • Display the unified diff content with syntax highlighting for added/removed lines.
  • Provide options to view or open the diff context within external repository browsers or local Git clients.
  • Use commit and parent-commit identifiers for querying or fetching the exact commit state.
  • Clearly indicate repository, branch, and file context if provided.

This detailed structure improves clarity, usability, and interoperability, providing clients with comprehensive context and ensuring precise referencing and rendering.

Permalink events (kind: 1623) represent a permanent reference to specific lines within a file from a Git repository. They are intended to directly reference code or documentation precisely and immutably. Clients should render the event's content field as preformatted text (code blocks).

{
  "kind": 1623,
  "content": "<referenced code or text excerpt>",
  "tags": [
    // Reference to the repo's 30617 event if one exists 
    ["a", "30617:<repo-owner-pubkey>:<repo-id>"],
    // Explicit repository URL (optional if resolvable via 'a' tag, recommended for interoperability)
    ["repo", "<repo.url>"],
    // refs associated with the repository (mandatory)
    ["refs/<heads|tags>/<branch-or-tag-name>","<commit-id>"]
    // Specific commit identifier referencing the repository state (mandatory)
    ["commit", "<commit-id>"],
    // Path to the specific file in the repository (mandatory)
    ["file", "<fully-qualified-filepath>"],

    // Start and end lines referenced within the file (optional, otherwise the event refers to the complete file)
    ["lines", "<start-line>", "<optional-end-line>"],
    // Language identifier for syntax highlighting (optional but recommended)
    ["l", "<language>"],
    ["description", "<short-text-description>"]
  ]
}

Clients rendering permalink events SHOULD:

  • Fetch and display the exact lines from the referenced commit and file if the content is not explicitly included or for verification.
  • Display provided code/text using syntax highlighting according to the specified language tag (l).
  • Offer navigation or direct links to view the file within external repository browsers or clients.

Possible things to be added later

  • "branch merge" kind (specifying a URL from where to fetch the branch to be merged)
  • inline file comments kind (we probably need one for patches and a different one for merged files)