Status: Accepted
Date: September 30, 2026
Answers: #93, three corpus files cannot be compiled with
--input, and none of them is broken — two questions: what a single-file
command means for a file inside a project, and what it is called
Related: ADR-002 D1 (a project is a nikaia.toml),
ADR-021 (a unit’s cache key holds every switch that reached it),
ADR-286 (a Nikaia package dependency), ADR-269 and
ADR-247 (nikaia test, which is what checks the examples),
ADR-258 (the four weights this is weighed by), Part III 13.2
The single-file command was nikaia --input f.nika, the compiler as it was
before there were projects. It lowered one file to Rust and wrote f.rs and a
ledger beside it without calling rustc; with --backend interpreter it ran
the file instead, and with --explain it mapped rustc’s JSON on stdin back
onto the .nika source. Three things were wrong with it.
It was neither inside a project nor outside one. It walked up to the
nearest nikaia.toml and took its [build] settings - one file must not be
cached under one project’s switches and compiled under another’s - but handed
the lowering an empty package list. So use http in
examples/hello-http/src/main.nika, with http declared in the manifest two
directories up, was refused with “there’s no dependency called http. Add it
to the project’s [dependencies]” - a refusal that is wrong and tells the
user to do what they did.
The name said nothing. --input names an argument, not what happens to it,
and the other commands are verbs (build, run, test, describe,
lower-std).
Three different jobs shared one switch set. Lower this file, interpret
this file and explain rustc’s errors against this file are separate
questions; --backend, --output and --explain existed only because they
were all --input.
Wherever a command takes a .nika file, the nearest nikaia.toml above it, if
there is one, decides everything: the [build] settings and the declared
dependencies, which are read and handed to the lowering exactly as nikaia build
hands them. The cache key holds the settings and the dependencies,
because what a file is checked against is one of the things that decides the
answer.
Weighed by ADR-258: D4 (consistent with itself) — a file is in a project or it is not, and the half-way reading is what produced the wrong refusal; D2 — the compiler finds the project, the developer does not name it twice.
With no nikaia.toml above it the file has the default settings and the
command-line switches, and no dependencies. use http in such a file is
refused with a message that says a single file outside a project has no
dependencies and names nikaia.toml as where one is declared — not that one is
missing from a manifest that does not exist.
| Was | Is | What it does |
|---|---|---|
nikaia --input f.nika |
nikaia lower f.nika |
writes f.rs and the ledger beside it; does not call rustc. The name follows lower-std |
nikaia --input f.nika --backend interpreter |
nikaia interpret f.nika |
runs the file in the interpreter |
nikaia --input f.nika --explain |
nikaia explain f.nika |
reads rustc --error-format=json on stdin and reports it against the .nika source |
--output belongs to lower alone. --backend leaves the single-file path: the
backends that are not rust and interpreter are refused by name already
(ADR-021 D9), and a verb per job says which one was asked. The explaining
switches (--trust, --overlaps, --sharing, --tethers, --comptime,
--asserts) and --locked, --no-cache, --target, --user-parallelism stay
where they are, on build, run, test and lower.
nikaia run f.nika compiles and runs one file.With a file argument and no nikaia.toml above it, run builds a project it
keeps for itself — a scratch directory under the user’s cache directory, keyed on
the file’s path — through the same Cargo workspace nikaia build makes, and
starts the program, so a single file behaves as a program and not as a lowering.
With a nikaia.toml above it, run f.nika builds that project and runs the
binary whose entry is f.nika, or is refused with the project’s binaries
named. run without a file is unchanged. The interpreter is not what run
uses: it handles a part of the language and would make a file mean something at
run that it does not mean when built (Part I 1.2’s promise is that a program
means one thing).
Weighed by ADR-258: D1 — the cost of the special case (one file
with no project) is carried by the file, which needs no manifest and no mkdir;
the common case, a project, is unchanged.
--input is removed, not kept as an alias.The language is pre-alpha and its status page says syntax and diagnostics change between releases with no migration. A deprecated second name would be one more thing to remove.
nikaia run f.nika a -v b runs f.nika with a -v b, as go run does; a
switch of nikaia run stands before the file, and -- still works. This is
what lets the kernel start a script: it calls nikaia run ./f.nika a b with no
--.
#! line opens an entry point and is skipped.A file whose first two bytes are #! has its first line skipped, and the line
still counts, so a diagnostic names the line it names in the editor. Only the
file that holds main may carry one; anywhere else a # is an error, as it was.
With #!/usr/bin/env -S nikaia run and the execute bit, ./f.nika is a
command. A file is still a whole program, so there is no REPL in this.
nikaia new name writes a project that builds, runs and tests.A new directory with nikaia.toml holding name and version and nothing
else, so every default applies without being copied; src/main.nika printing
Hello, Nikaia!; tests/main.stdout holding that line, so nikaia test
checks something at once; and a .gitignore naming target/. A directory that
exists and is not empty is refused.
D6-D8 decided October 9, 2026 (#537).
examples/hello-http/src/main.nika, lowers
without a special case.lower writes Rust and stops, interpret
runs, run builds and runs.--help for each verb says what it does and what it does not (does not call
rustc) in its first sentence.lower_to_rust and nikaia build both call
(project::explain), are the same for every verb.Keep --input and fix only the message. It would repair one wrong sentence
and keep a name nobody can guess and three jobs in one switch set.
A single file is always standalone, even inside a project (no manifest
search). It is consistent, but it makes nikaia lower over a project’s file
disagree with nikaia build over the same file — the situation D1 removes — and
it would need its own answer to the cache-key argument above.
nikaia run f.nika uses the interpreter. Cheaper to build and it skips
rustc, but the interpreter runs part of the language. A program that means one
thing under run and another under build is what the two settings of
user_parallelism are held to never do.