Files
2026-10-26 11:03:06 -03:00

14 KiB

NIP-82

Software Applications

draft optional

This NIP defines kind 32267 to describe a software application, kind 30063 for a software release and kind 3063 for a software asset. It also defines app curation sets (kind 30267), a way for publishers to link the signing certificate of their software to their Nostr key (kind 30509) and a list of relays used to fetch software applications from (kind 10067).

All software assets MUST be installable or executable given only the target platform and a standard runtime implied by the MIME type. Assets that require additional dependency resolution beyond what that runtime ordinarily performs are out of scope. Native executables SHOULD be statically linked.

Software Application

An application is an addressable event, as a pubkey may maintain many different ones and update their descriptions over time.

{
  "kind": 32267,
  // full description of the application, markdown is allowed
  "content": "<description>",
  "tags": [
    // REQUIRED: reverse-domain identifier (com.example.app) recommended, can be any string
    ["d", "<app-id>"],

    // REQUIRED: app name
    ["name", "<human-readable project name>"],

    // REQUIRED, MULTIPLE: platform identifiers (see Appendix A)
    ["f", "<platform-identifier>"],

    // OPTIONAL: short description, markdown not allowed
    ["summary", "<summary-text>"],

    // OPTIONAL: icon URL
    ["icon", "<icon-url>"],

    // OPTIONAL, MULTIPLE: screenshot or other image URLs
    ["image", "<image-url>"],

    // OPTIONAL, MULTIPLE: tags used to describe the application
    ["t", "<tag>"],

    // OPTIONAL: website URL for the application
    ["url", "<website-url>"],

    // OPTIONAL: source code repository URL, must be able to `git clone <repo-url>`
    ["repository", "<repo-url>"],

    // OPTIONAL: pointer to a NIP-34 repository
    ["a", "30617:<pubkey>:<repo-id>", "<relay-url>"],

    // OPTIONAL: SPDX license ID (https://spdx.org/licenses/)
    ["license", "<spdx-id>"]
  ]
}

Applications SHOULD use their application or bundle identifier (typically in reverse-domain notation) as the d tag. Application and asset identifiers are independent: an Android app may have com.example.android as ID while its macOS counterpart may use com.example.mac.

The f tags MUST list every platform for which there are assets available, so clients can filter applications using {"kinds": [32267], "#f": ["<platform>"]}. Software that runs on all architectures of a given operating system MUST list all of them.

For icon and image tags any URL is valid but a Blossom BUD-01 endpoint is recommended.

Software Release

A release is an addressable event, as it is important for developers to be able to overwrite a bad release and update pointers to the right assets.

{
  "kind": 30063,
  // full release notes, markdown allowed
  "content": "<release-notes>",
  "tags": [
    // REQUIRED: this MUST be the `d` tag of the application kind 32267
    ["i", "<app-id>"],

    // REQUIRED: release version, i.e. 1.2.3, v0.1.2-rc1
    ["version", "<version>"],

    // REQUIRED: MUST be the `i` and `version` tags joined by '@'
    ["d", "<app-id>@<version>"],

    // REQUIRED: see Appendix B for channel IDs
    ["c", "<channel-id>"],

    // REQUIRED, MULTIPLE: union of the platforms supported by all assets in this release
    ["f", "<platform-identifier>"],

    // REQUIRED, MULTIPLE: software asset event ids (kind 3063)
    ["e", "<asset-event-id>", "<relay-hint>"]
  ]
}

The e tags are pointers to all Software Assets in this release. This event MUST be the authoritative source for assets belonging to a given version.

The event's created_at timestamp MUST be the release date.

A release version, typically a git tag, does not need to coincide with any of the linked asset versions.

Software Asset

An asset is a regular event, mainly used to cryptographically link a file through its SHA-256 hash. This kind is an extension of kind 1063.

{
  "kind": 3063,
  "content": "",
  "tags": [
    // REQUIRED: asset identifier, here "i" stands for "identifier", not "infohash"
    ["i", "<app-id>"],

    // REQUIRED: SHA-256 hash of the asset
    ["x", "<sha256-hash>"],

    // REQUIRED: version, i.e. 1.2.3, 0.1.2-rc1
    ["version", "<version>"],

    // REQUIRED: MIME type of the asset, the primary source of truth for its runtime (see Appendix C)
    ["m", "<mime-type>"],

    // REQUIRED, MULTIPLE: platforms this asset can run on (see Appendix A)
    ["f", "<platform-identifier>"],

    // OPTIONAL, MULTIPLE: download URLs, may be Blossom URLs
    ["url", "<asset-url>"],

    // OPTIONAL: size of the asset in bytes
    ["size", "<size-bytes>"],

    // OPTIONAL: minimum platform version (see below)
    ["min_platform_version", "<min-platform-version>"],

    // OPTIONAL: platform version the software was designed for
    ["target_platform_version", "<target-platform-version>"],

    // OPTIONAL, MULTIPLE: NIPs supported by this software
    ["supported_nip", "<nip-id>"],

    // OPTIONAL: name used to differentiate sibling assets of the same version, i.e. "offline", "fdroid"
    ["variant", "<variant-name>"],

    // OPTIONAL: original filename, used as a fallback to differentiate sibling assets when there is no `variant`
    ["filename", "<filename>"],

    // OPTIONAL: commit used to build the asset (same as NIP-34), needed for reproducible builds
    ["commit", "<commit-id>"],

    // OPTIONAL: minimum version of this asset that is still allowed to run (see Appendix D)
    ["min_allowed_version", "<version>"],

    // REQUIRED for Android, OPTIONAL otherwise: integer version code
    ["version_code", "<version-code-int>"],

    // OPTIONAL: minimum allowed version as an integer version code
    ["min_allowed_version_code", "<version-code-int>"],

    // REQUIRED for Android APKs, MULTIPLE: SHA-256 hash of the APK signing certificate
    ["apk_certificate_hash", "<certificate-sha256-hash>"]
  ]
}

Both the asset i and version tags MAY be different from the application identifier and release version.

min_platform_version and target_platform_version refer to the runtime version when the MIME type implies one (e.g. VS Code for VSIX, Chrome for CRX) and to the operating system version otherwise (e.g. the Android API level, the macOS version).

When no url is given, or none of them work, clients SHOULD locate the asset via its SHA-256 hash using a Blossom BUD-01 endpoint.

App curation sets

Kind 30267 is a NIP-51 set of applications.

{
  "kind": 30267,
  "content": "<encrypted private items, optional>",
  "tags": [
    ["d", "<identifier>"],
    ["title", "<set title>"],
    ["description", "<set description>"],
    ["image", "<image-url>"],

    // REQUIRED: the platform this set was made for
    ["f", "<platform-identifier>"],

    // MULTIPLE: applications in this set, in order
    ["a", "32267:<pubkey>:<app-id>", "<relay-url>"]
  ]
}

Only a tags pointing to kind 32267 are allowed. Private items are encrypted in .content following the standard NIP-51 scheme, i.e. a NIP-44-encrypted stringified JSON array of ["a", ...] tags.

Identity proofs

Kind 30509 links an X.509 certificate (for example, the one used to sign an Android APK) to the Nostr key that publishes the software, so clients can know which certificates a publisher controls:

{
  "kind": 30509,
  "content": "",
  "created_at": <timestamp>,
  "tags": [
    // lowercase hex SHA-256 of the DER-encoded certificate
    ["d", "<certificate-hash>"],

    // base64 signature made with the certificate's private key
    ["signature", "<base64-signature>"],

    // unix timestamp after which the proof is no longer valid
    ["expiry", "<timestamp>"],

    // OPTIONAL: marks the proof as revoked
    ["revoked", "<reason>"]
  ]
}

The signed message is the UTF-8 string Verifying at <created_at> until <expiry> that I control the following Nostr public key: <hex-pubkey>, where <created_at> MUST be equal to the event's created_at. It is signed with RSA PKCS#1 v1.5 over SHA-256, with ECDSA over SHA-256 (ASN.1 DER signature), or with Ed25519 over the raw message, according to the certificate's key type.

Before installing an Android asset, clients SHOULD fetch kind 30509 events with {"#d": [<apk_certificate_hash>]}. They SHOULD then verify the signature against the certificate embedded in the APK, and check that the proof is authored by the asset publisher and is neither expired nor revoked.

App catalog relays

Kind 10067 is a replaceable list of the relays a user wants to fetch kinds 32267, 30063, 3063 and 30267 from. It contains r tags with optional read or write markers, as in NIP-65. Private relays can be encrypted in .content following the NIP-51 scheme.

{
  "kind": 10067,
  "content": "",
  "tags": [
    ["r", "wss://relay.zapstore.dev"],
    ["r", "wss://relay.example.com", "read"]
  ]
}

Appendix A: Platform identifiers

A platform is the specific underlying system on which the application is executed: a combination of operating system and hardware architecture. We use the f tag for this purpose, with the following identifiers loosely based on uname -sm:

Identifier OS Architecture
android-arm64-v8a Android ARMv8-A
android-armeabi-v7a Android ARMv7-A
android-x86 Android x86
android-x86_64 Android x86-64
darwin-arm64 macOS ARM64
darwin-x86_64 macOS x86-64
linux-aarch64 Linux ARM64
linux-x86_64 Linux x86-64
linux-armv7l Linux ARMv7 (32-bit)
linux-riscv64 Linux RISC-V 64-bit
windows-aarch64 Windows ARM64
windows-x86_64 Windows x86-64
ios-arm64 iOS ARM64
freebsd-x86_64 FreeBSD x86-64
freebsd-aarch64 FreeBSD ARM64
wasm32 WebAssembly WASM 32-bit
wasm64 WebAssembly WASM 64-bit
wasi-wasm32 WASI WASM 32-bit
wasi-wasm64 WASI WASM 64-bit

Universal builds (e.g. an APK without native libraries, or a macOS fat binary) MUST list every architecture they support.

Appendix B: Channel IDs

Standard channel identifiers:

  • main (default)
  • beta
  • nightly
  • dev

Custom channel identifiers MAY be used for organization-specific needs (e.g. internal, canary, lts).

Appendix C: MIME types

The MIME type is the primary source of truth for determining the asset's runtime and handling. Generic archives (e.g. application/gzip, application/zip) and dependency-based packages (e.g. .deb, .rpm) are NOT supported.

MIME type Platform/Runtime Common Extension
application/vnd.android.package-archive Android .apk
application/vnd.apple.ipa iOS .ipa
application/x-apple-diskimage macOS .dmg
application/vnd.apple.installer+xml macOS .pkg
application/x-msi Windows .msi
application/vnd.appimage Linux .AppImage
application/vnd.flatpak Linux (Flatpak) .flatpak
application/vnd.oci.image.manifest.v1+json OCI (Docker/Podman) —
application/x-executable Linux (ELF) —
application/x-mach-binary macOS (Mach-O) —
application/vnd.microsoft.portable-executable Windows (PE) .exe
application/vsix VS Code .vsix
application/x-chrome-extension Chrome / Chromium .crx
application/x-xpinstall Firefox .xpi
application/wasm Browser / WASI .wasm
application/webbundle Browser (PWA) .wbn, .swbn

Native executables (application/x-executable, application/x-mach-binary, application/vnd.microsoft.portable-executable) SHOULD be statically linked. Self-contained formats like AppImage or Flatpak are preferred when additional dependencies are required.

Appendix D: Version comparison

Version strings are used in the version, min_platform_version, target_platform_version and min_allowed_version tags. Implementations MUST follow Semantic Versioning 2.0.0 precedence rules for versions that conform to SemVer. Other versions are compared as follows:

  1. Split the version string into segments using ., - and _ as delimiters.
  2. Compare segments left-to-right:
    • numeric segments are compared as integers: 9 < 10 < 100;
    • alphanumeric segments are compared lexicographically (case-insensitive);
    • numeric segments sort before alphanumeric segments;
    • missing segments are less than present segments: 1.0 < 1.0.0 < 1.0.0.1.

Common pre-release identifiers sort as dev < alpha < beta < rc:

1.0.0-dev < 1.0.0-alpha < 1.0.0-alpha.2 < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-rc1 < 1.0.0 < 1.0.1

Purely numeric versions (e.g. Android API levels) are compared directly as integers. version_code and min_allowed_version_code MUST be monotonically increasing integers.

Appendix E: Attribution

Signers MAY include other pubkeys as p tags and zap tags as per NIP-57 - Appendix G in any of the event kinds defined here. This is useful when the signer is not the maintainer of the software, or in the case of multiple authors.