Package registries, manifest formats, lockfiles, version ranges and identifiers all have written specifications of some kind, spread across six kinds of venue. Specifications show up in package management mostly as an invisible layer of the dependency tree, where an HTTP library is built against RFC 9110 and a JSON parser against ECMA-404, and the documents covering package management itself are spread just as thinly.

I went looking for the IETF’s share, since wire protocols between independently written implementations are what the RFC series exists for, and found nine documents, most of them concerned with firmware updates on IoT devices. The rest is distributed among Ecma, ISO, CNCF and OASIS, the enhancement proposal processes individual ecosystems run for themselves, and for a couple of registries a service’s own API reference. Which venue a document is published in determines whether a second client, a mirror or an archival reconstruction can rely on it, since each of those requires specified behaviour rather than whatever a given server returns this week.

Venues

Package management specifications are published in six kinds of venue: the IETF, the industry standards bodies, the software foundations, a single ecosystem’s enhancement proposal process, a service operator’s own API documentation, and a third party’s description of observed behaviour. The IETF handles protocols that independently written implementations have to interoperate under, while Ecma, ISO/IEC and OASIS cover formats consumed across industries, which is also what gets them cited in procurement rules and regulation.

CNCF, the OCI and the Linux Foundation publish the same kinds of format with a lighter process and faster revisions, while the ecosystem processes, PEPs and Rust RFCs and conda CEPs and Gentoo GLEPs among them, produce documents binding on a single language community. The last two slots are weaker: API documentation describes one running service rather than a contract others can implement against, and a third-party description is written by whoever needed the behaviour recorded when the operator had published none.

IETF

A title search for “package” across the whole RFC series returns 42 documents, 41 of them about something else entirely: SIP event packages, MGCP media gateway packages, and CMS symmetric and asymmetric key packages. The one exception, RFC 4108 from 2005 on using CMS to protect firmware packages, is the first of the nine. Searching for “software” returns mostly ARPANET-era host notes and SDN terminology. The series covers inventory and attestation instead, nearly all of it produced by the IoT firmware update effort.

Concise Software Identification Tags, the CBOR encoding of SWID, is RFC 9393, with RFC 8412 covering Software Inventory Message and Attributes for reporting installed software over PA-TNC. There is a YANG data model for reporting SBOMs and vulnerability information in RFC 9472. The SUIT working group accounts for two more, RFC 9019 giving a firmware update architecture for IoT devices and RFC 9124 the manifest information model that goes with it.

SCITT’s architecture for trustworthy and transparent digital supply chains became RFC 9943 in June 2026, the newest of the set and the closest to current SBOM and attestation deployments. The last two are RFC 8240, a report from the 2016 IoT Software Update workshop, and RFC 1805 from 1995, describing a Location-Independent Data/Software Integrity Protocol.

The document that would actually specify a package format is draft-ietf-suit-manifest, the CBOR serialization of the manifest described abstractly in RFC 9124. Revision 00 went up in October 2019, the individual draft it was derived from in October 2017, and revision 37 arrived in June 2026 with the usual six month expiry on it. Nearly nine years in, it is the IETF’s one software update wire format, scoped to firmware on constrained devices rather than to registry clients.

The series supplies more than that count suggests: every registry protocol here runs over HTTP, and Python’s core metadata began as PEP 241 in 2001, defining PKG-INFO as a single set of RFC 822 headers parseable by the rfc822.py module. The current specification still describes the format as based on email headers, and notes that in the absence of a precise definition the practical standard is whatever email.parser accepts under its compat32 policy.

Debian’s deb822 field folding is documented as similar to RFC 5322, enough that control files of a single stanza parse with RFC 5322 parsers. Maven Central requires OpenPGP signatures, the .asc files that appear in its published layout, and OpenPGP is now RFC 9580 from July 2024, which obsoleted RFC 4880 along with the Camellia and ECC extensions. apt verifies Release files against the same format, inline as InRelease or detached as Release.gpg. RubyGems signs with X.509 certificates instead, which its own security guide calls rarely used for want of an established chain of trust.

Standards bodies

The cross-ecosystem pieces, the ones several language communities and most compliance tooling have to share, are nearly all published at Ecma, whose TC54 was established with OWASP in September 2023. Package URL became ECMA-427 with its first edition published on 10 December 2025, and TC54’s second task group is putting a second edition to the December 2026 General Assembly. CycloneDX was ratified earlier, version 1.6 as ECMA-424 1st edition in June 2024 and 1.7 arriving as the 2nd edition in December 2025. Common Lifecycle Enumeration, which records releases, end of support dates and component transitions, is ECMA-428 as of December 2025.

SPDX went to ISO instead and is ISO/IEC 5962:2021, whose text describes SPDX 2.2.1 while the project itself is on 3.x, so a contract or a procurement rule citing ISO/IEC 5962:2021 is naming 2.2.1 regardless of what whoever wrote it had in mind. CycloneDX has shipped a second edition through Ecma over the same period, so Ecma’s published text tracks the implementation more closely than ISO’s does for SPDX.

Outside Ecma and ISO, CSAF is an OASIS standard for machine-readable security advisories, and the attestation layer is at CNCF, as TUF, in-toto and Sigstore. The OCI distribution spec is this group’s one registry protocol, implemented by Docker Hub, GHCR, ECR, Harbor, Quay, Zot and Artifactory, and since adopted by Homebrew for bottles and Helm for charts.

Ecosystem specs

Published registry protocols come out of a single ecosystem’s own process, each in its own client’s vocabulary, which is what sent me looking for a reference model above them in January. Python has the longest paper trail, with the simple repository API now a living specification the PyPA maintains, consolidating nine PEPs: 503 for the original HTML format in 2015, 592 for yanking, 629 for API versioning, 691 for the JSON format, 700 for project versions and file sizes and upload times, 714 for renaming the metadata field, 740 for provenance, 792 for project status markers, and 833, from June 2026, which freezes the HTML representation. PEP 503 established, and every later document preserved, that a directory of files on a static web server is a valid index, so devpi, Artifactory, Nexus, CodeArtifact and an S3 bucket all serve pip.

NuGet covers more of the protocol than any of them, documented by Microsoft as a service index listing named resources, four of them required: PackageBaseAddress for package content, RegistrationsBaseUrl for metadata, PackagePublish for pushes and SearchQueryService for search. A separate implementation guide in the same documentation is addressed to anyone building a NuGet repository. Composer documents its repository format the same way, with packages.json, the metadata-url template and the HTTP caching requirements written out, and Satis generates static repositories from it.

RubyGems documents its compact index as three endpoints, /versions, /info/<gem> and /names, served as append-only text with ETags and HTTP Range support so a client fetches only what changed since its last request. The format came out of the 2012 RubyGems.org capacity crisis and took four years to ship. Cargo’s sparse index cites it as prior art, quoting Bundler’s path from a full index to a centralized query API to an incrementally downloaded flat file.

Cargo’s sparse index came through RFC 2789 in the Rust process, with the motivation stated in the document: a git clone of the full index reported 215MiB against 10MiB for the same content under xz -6, and CI was downloading all of it to use a fraction. Its design constraint was static files behind a CDN using HTTP/2 alone, the same constraint Python’s format has, and the Cargo book documents a registry web API on top of the index format, covering publish, yank, owners and search for alternate registries. Go specified the GOPROXY protocol in the module reference with endpoints written out, /@v/list and /@v/$version.info among them, and ships one client that implements it.

Debian’s repository format is documented on the wiki, outside the policy manual, and the page is labelled a work in progress covering the structure of the official repository and the format clients accept, with the goal of becoming a sub-policy eventually. dak, reprepro and aptly produce that format and apt reads it, so the wiki page is treated as normative whatever the label says.

Registries

npm and Maven Central both publish documentation that omits the part a client installs from. npm’s registry API documentation ships an OpenAPI file for publishing, search, tokens, organisations, access control and trusted publishers, leaving out GET /{package} and tarball downloads, which together are the read path every install runs through. Older endpoint documentation is in npm/registry as an archived collection and in npm/api-documentation, and the fullest public account of the read path is a third-party OpenAPI file assembled from observed behaviour.

npm-registry-couchapp was the last publicly readable server and GitHub archived it on 11 August 2021, with a deprecation notice that names the internal micro-services now serving the API. Verdaccio and cnpm implement a compatible API by matching observed behaviour, a weakness in an ecosystem with five clients in npm, yarn, pnpm, bun and Deno.

Maven publishes the repository layout and the POM reference, with maven-metadata.xml defined by the Repository Metadata Model, so the storage format is specified. What stays de facto is the resolver’s conflict and ordering behaviour, defined by what ComparableVersion and the resolver in maven-artifact compute. The Gradle team derived those semantics from observed behaviour and then shipped Gradle Module Metadata alongside the POM as its own specification. Sonatype has operated Maven Central since 2008, GitHub operates npm, and each publishes what it chooses to document. ecosyste.ms maintains OpenAPI schemas for more than 25 registry APIs. Two of those registries publish an official schema themselves, crates.io and open-vsx.org, and the rest are generated from the mapping code in packages.ecosyste.ms.

Versioning

Every ecosystem has its own versioning rules, and version comparison is the least settled part of the whole business. Semantic Versioning 2.0.0 is a self-published document on semver.org by Tom Preston-Werner under CC BY 3.0, and its one IETF reference is RFC 2119, cited for MUST and SHOULD. It specifies version syntax and precedence only, so range syntax comes from each client: node-semver’s README is the operative document for npm, Cargo’s caret default is in the Cargo book, Ruby’s ~> is in the RubyGems documentation, and Python’s are in PEP 440 and PEP 508.

Ordering rules split the same way: Debian Policy section 5.6.12 gives the comparison algorithm for epoch, upstream_version and debian_revision in the policy text itself, PEP 440 does the same for Python, and Go’s pseudo-versions and +incompatible suffix are described in the module reference. RPM’s ordering is rpmvercmp inside librpm and Maven’s is ComparableVersion in maven-artifact, with the implementation as the reference in both cases. univers exists because of that spread: one library that reimplements every ecosystem’s comparison rules behind a single interface.

The cross-ecosystem attempt is vers, from the purl project, which defines a URI syntax for version ranges together with the semantics for interpreting each notation, so an npm caret range comes out as vers:npm/>=1.0.2|<2.0.0. It was developed alongside purl and is due to be proposed to Ecma later in 2026, which would put ranges in the same venue as identifiers and lifecycle events. Ecma would then hold the identifier, the bill of materials, the lifecycle record and the version range, four of the pieces that have to mean the same thing in every ecosystem, within three years of TC54’s founding, while the protocol layer remains inside the ecosystems and with the registry operators.