http Leaves std and Becomes a Package, So It Can Ripen at Its Own SpeedStatus: Superseded by ADR-289 — its D1-D5 are D1-D5 there; D6 is not carried
Date: September 14, 2026
Target Version: Nikaia 0.0.8
Supersedes: — nothing. It settles a question the specification answered
twice, differently, and that no record had ever put
Related: ADR-018 (the request is the handler’s first argument,
and what a handler returns), ADR-058 (a response body may be bytes
the program never allocated; D7’s Untrusted path), ADR-038 D1, D6
and §4.5 (the server is Nikaia’s own, HTTP/1.1 first, and it is not built),
ADR-002 D1 (a manifest key reaches Cargo verbatim),
ADR-047 D2 (the same path is the same package),
ADR-053 D2 (what a build calls each package)
The specification says both things.
The tooling chapter heads a section std::http and promises “a
production-ready HTTP/1.1 and HTTP/2 server and client”, and the README’s code
example opens with
use std::http
The first chapter uses the same name as its worked example of a foreign package — it is the passage that teaches how one package reaches another at all:
use http
fn handle(r: http::Request) -> rh::Response { … }
with http = { path = "../http" } in [dependencies]. And
ADR-046 D2 reaches for use http::server as its example of “a
path that is not std’s”.
So the same name is the standard-library example in one chapter and the
not-the-standard-library example in another. Nobody decided this, and nobody
noticed, for a reason that is itself the finding: neither exists. While there is
no way to name a package by a version (ADR-002 D1 §5 declines to
answer it deliberately), “in std” and “a package” look identical from
here — either way you cannot have it.
What did happen in the meantime is that nine decisions across two records elaborated a surface on top of the unasked question. That is the cost this record stops: each of them reads as settled, and the thing they rest on was never put.
http is a package, not a module of std, and it lives in examples/ until it is ripe.It is reached the way the first chapter already teaches, by a path:
[dependencies]
http = { path = "../http" }
A path dependency of this shape is not a promise about the future: it is the arm
project.rs already resolves, recursively, refusing two names for one path
(ADR-047 D2) and naming each package once per build
(ADR-053 D2). What the corpus exercises today is the type =
"rust" arm, in examples/foreign-runtime/; the Nikaia arm is the one
crates/nikaia/tests/project.rs covers.
examples/ rather than a repository of its own, because a package nobody can
fetch and nobody can build is not a package, it is a directory. In examples/
it is compiled by the same test that compiles every other example, and it grows
against a compiler that is moving.
std.The argument for a server in a standard library is that parts of it cannot live
outside one. That argument is worth taking seriously and it does not survive
being itemised. Three things in the design genuinely need the compiler, and all
three are already in std under their own names and for their own reasons:
std::html, which a
template needs whether or not a socket is involved;fs::map and
Bytes, which are the file and the stream.What is left after the subtraction is the protocol — request parsing, status
lines, headers, HTTP/2, TLS — and the framework: a route table, a handler
shape, listen. Neither needs a compiler, both are large, and both age. A
standard library that carries them ties the language’s release to a protocol’s.
Both answers could be wrong, and being wrong costs different amounts.
Moving a package into std later is an addition: programs that named it as a
dependency keep working, and the manifest line becomes redundant rather than
invalid. Moving a module out of std is a break: every use std::http in
every program stops compiling, and there is no deprecation that makes it not a
break.
So the asymmetry decides it even for a reader who thinks a server belongs in a standard library. Start outside, where a change of mind is additive.
A version of std is a version of the language: the ledger it ships is read by
the compiler, and its entries are checked against the compiler’s own inference
(crates/nikaia/tests/contracts.rs). A protocol implementation has a different
clock — it wants to be wrong in public, change its surface twice, and settle —
and a surface that changes twice inside std is two breaks in the language.
Outside, the same two changes are two versions of a package, and a program that wants the old one keeps it. That is the whole of why it moves, and the measure of ripeness is therefore not “is it finished” but “has its surface stopped moving”.
It looked as though it would be, and it is worth writing down that it is not: a path dependency needs no registry, no namespace, and no distribution format. The notes page’s entry on naming a package by a version stays open, and this record does not wait for it.
What the open question does decide is the day http leaves examples/ — which
is D4’s ripeness by another name, and a later decision than this one.
ADR-018 and ADR-058 decide what a handler receives,
what it may return, how bytes reach a socket, what may be kept between requests,
and what happens to a path a request names. None of that is about where the
code lives, and none of it is reopened here. A record is written once and is
not edited when the code moves (README.md), so those records keep
saying std; what changes is the specification, which is maintained, and this
record is the reason a reader finds for the difference.
The specification stops contradicting itself, which is the only thing that gets worse while nothing is built.
examples/fortunes.nika has somewhere to live. It does not compile today and
says so, waiting on the request surface; it is now waiting on a package rather
than on a chapter of std.
The concurrency half of the language still has no program. That is a separate
gap, found while this one was being looked at: no .nika file in the tree uses
spawn, Locked, Shared or SharedMut — those features live in Rust test
snippets only. A server is the honest program for it, which is why it is worth
building this one rather than a contrived queue.
The entry on the notes page closes — what is std::http — and the
question it should have asked, is http in std at all, is answered rather
than deferred.
The specification and the README. The tooling chapter’s section and the
README’s example now spell http as a package and name this record; the first
chapter needed no change, because it was already right.
Not the package. There is no examples/http/, and std::http never existed
to remove (ADR-038 §4.5) — this record moves a promise, not code.
D1’s path arm is built and tested; what is missing is the thing on the other end
of the path.