The source well-known URI
A fixed address, /.well-known/source, where a server says what
software it runs and where to get the exact source code of that build. Any
client can find it the same way on any host, not only a person reading a web
page.
| Version | 1 (draft 2) |
|---|---|
| Date | 2026-10-28 |
| Status | Draft. Not yet registered with IANA. |
| Change controller | Coffey Labs LLC |
| Contact | licensing@coffeylabs.org |
1. Why
Free software licenses for network services, the GNU AGPL most of all, ask whoever runs a modified program to offer its source to the people using it. Servers do that today with a link in their web interface, each in a different place. A mail app speaking IMAP, a phone speaking JMAP or a script calling an API never sees that link, and nothing tells an auditor where to look.
This specification gives the offer one address on every host. It doesn't change what any license requires. It only makes the answer to “what code is this server running, and where can I get it?” something software can read.
The key words “MUST”, “MUST NOT”, “SHOULD”, “SHOULD NOT” and “MAY” are to be read as described in BCP 14 (RFC 2119 and RFC 8174) when, and only when, they appear in all capitals.
2. The resource
The resource is at /.well-known/source on a host, as defined by
RFC 8615, for example https://mail.example.org/.well-known/source.
- A server that publishes the resource MUST answer
GETandHEADover HTTPS. It MAY also answer over plain HTTP. - The response is a JSON document (RFC 8259) with the media type
application/json, described in section 3. - A
404means the host doesn't publish the resource. It says nothing about whether the software is free. - The content is public, so a server SHOULD send
Access-Control-Allow-Origin: *, letting web clients on other origins read it. - The document describes the build that is running now. A server MUST
change it when the running build changes, and SHOULD send
Cache-Control: no-cacheor a shortmax-ageso caches don't keep an old answer. - Each host answers for itself. In a cluster, nodes running different builds give different answers.
3. The document
The document is a JSON object with two members:
version(number, required): the version of this specification the document follows. This page defines version1.software(array, required): one object for each program answering on the host, such as a mail server and the webmail in front of it. It MUST NOT be empty.
Each object in software has these members:
| Member | Type | What it holds |
|---|---|---|
| name | string, required | The program's name, as it reports itself. |
| version | string, required | The version of the running build, in the program's own format. |
| license | string, required | An SPDX license expression for the program, such as AGPL-3.0-only. |
| repository | string, see below | A URL for a public repository holding the source the running build was made from. |
| revision | string, see below | The revision in repository the build was made from: a full commit id, or a tag. |
| source | string, see below | A URL for an archive of the exact tree the running build was made from. |
| sha256 | string, recommended with source | The SHA-256 digest of that archive, in lowercase hexadecimal. |
| modified | boolean, optional | true if the running build includes changes that aren't in revision. |
There are two ways to say where the source is, and an object MUST use at least one:
- A repository at a revision:
repositoryandrevisiontogether. This suits a build made from a commit that is already public, which is how most releases are made. A full commit id is better than a tag, since a tag can be moved. - An archive:
source, withsha256. This suits a build whose source isn't in any public repository.
A build that includes changes not in any public revision MUST give
source, because a repository can't show them. It SHOULD also set
modified to true, and MAY still name the
repository and revision it started from, which helps
a reader compare.
URLs MAY be relative. They are resolved against the URL of the well-known resource itself. What they point to SHOULD be retrievable without credentials. Where a license lets the offer go only to the service's own users, it MAY require the same sign-in the service does.
A client MUST ignore members it doesn't recognize, so later versions can add
members without breaking it. A document with a version the client
doesn't support SHOULD be treated as unknown, not as an error in the server.
Example
A host running a mail server built from a public commit, and a webmail its operator changed locally:
GET /.well-known/source HTTP/1.1
Host: mail.example.org
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: *
Cache-Control: no-cache
{
"version": 1,
"software": [
{
"name": "Example Mail Server",
"version": "4.2.1",
"license": "AGPL-3.0-only",
"repository": "https://git.example.net/example/mail-server",
"revision": "3c1e9b72a4f0d5e8b1c6a9f2d7e4b0c3a8f5d1e6"
},
{
"name": "Example Webmail",
"version": "2.0.0",
"license": "AGPL-3.0-or-later",
"repository": "https://git.example.net/example/webmail",
"revision": "v2.0.0",
"modified": true,
"source": "/webmail/source-2.0.0-local.tar.gz",
"sha256": "9f2c…e41a"
}
]
}
4. Security considerations
- The archive must not carry secrets. A build that packs its whole working tree, uncommitted changes included, can sweep in credentials, keys or local configuration. Implementations SHOULD build the archive from a list of what belongs in the source and check it for secrets before publishing.
- It reveals the exact version. Anyone can learn which build a host runs, including one with known flaws. Operators who must offer source already disclose this, and hiding a version is weak protection anyway. Keeping the build current is the defense.
- It isn't an attestation. A revision names a tree, and a digest shows an archive is the one the server named. Neither proves the server runs code built from it. A server can lie. Reproducible builds and signed provenance answer that question, and are outside this specification.
- Archives are large. A server SHOULD serve them as static files and MAY rate-limit them, so the offer can't be used to exhaust the host.
5. Privacy considerations
The document describes software, not people, and holds no personal data. Requests for it are logged like any other request to the host.
6. Relation to other registrations
nodeinfocarries a software name, version andrepositoryURL for federated social servers. It has no revision or archive, so it names the project, not the build a host runs, and NodeInfo is specific to the fediverse.sbom(RFC 9472) points to a software bill of materials: the components inside a product, not its source code. A host can publish both.- The
licenselink relation (RFC 4946) points from a page to its license. It says which terms apply, not where the code is.
7. IANA registration
The template below is for the Well-Known URIs registry, following section 3.1 of RFC 8615.
- URI suffix:
source - Change controller: Coffey Labs LLC (licensing@coffeylabs.org)
- Specification document: this page,
https://coffeylabs.org/specs/well-known-source/ - Status: provisional
- Related information: none
8. Implementations
None yet. Support in inbuxa is under way: its server, console and webmail will each name their repository and the revision they were built from.
Changes
- Version 1, draft 2, 2026-10-28: a public repository at a named revision now meets the offer, as an alternative to an archive. An archive is required only for changes that aren't public.
- Version 1, draft 1, 2026-10-28: first draft.