Compatibility and stability
Khora is 0.x. It may break. This page says when, how you find out, and what 1.0 is waiting for — because “pre-1.0, anything can change” is not a policy, it is the absence of one.
What 0.x promises
Section titled “What 0.x promises”Within one release, everything. A program that compiles with one khora 0.4.0 build compiles with every 0.4.0 build, and the lockfile resolves the same way. Pin the toolchain and a build is reproducible.
[toolchain]version = "0.4.0"A pin that cannot be satisfied fails loudly. It never silently runs a different compiler — the toolchain shim hands over before argument parsing, and khora toolchain which tells you which build answered and why.
Between releases, nothing is guaranteed — but nothing breaks silently either:
- Every breaking change is in the changelog, under a Breaking heading, before anything else.
- A change that made a program silently wrong is listed under Breaking as well as Fixed, because code written around the old behavior will behave differently now.
- Where a mechanical fix exists, the entry names it.
What counts as breaking
Section titled “What counts as breaking”| Surface | Breaking? |
|---|---|
| Language syntax and semantics | Yes |
Making a pub field of a pub type private, or closing an open wrapper (= pub T to = T) |
Yes |
| Adding a private field to a type that already has one | No: nothing outside the module could build it before either |
Adding any field to a type whose fields are all pub |
Yes: literals outside the module stop compiling |
A std signature, type or behavior |
Yes |
A std item’s removal or rename |
Yes |
Renaming a parameter of a public function, in std or a package |
Yes. A caller may have labeled the argument with the name |
| Lockfile format | Yes |
| Manifest keys the toolchain requires | Yes |
| CLI flags and their meanings | Yes |
| Diagnostic wording | No |
| A new lint, or a lint’s default level | No |
| Compiler internals, IR, symbol names | No |
| Which fiber implementation is the default | Yes, today. It is meant to be unobservable and is not — see below |
Anything under docs/ in the repository |
No |
A new lint can make khora check report something it did not report before. That is deliberate and is not treated as breaking: a lint tells you about code that was already wrong. Set its level in [lints] if you disagree.
The fiber backend is observable
Section titled “The fiber backend is observable”The two backends answer cancellation alike: a fiber in clock.sleep, on a
channel, on a socket or on another fiber is woken by a cancellation under
either one. They schedule differently — which fiber runs when, and how many run
at once — so a program that depends on an order the language does not promise
can see which backend it has.
So the backend is not an implementation detail, and the default cannot change without a breaking-change note. Known limitations has the detail.
Editions
Section titled “Editions”There is no editions mechanism, and there will not be one until something needs it. An edition is a promise to maintain two languages at once, and a 0.x with three release candidates has no evidence that it is the right shape of promise.
khora.toml has no edition key. The question it looks like it would answer — which Khora builds this? — is answered by the toolchain table, which names a version that exists and selects the binary that runs.
What 1.0 is waiting for
Section titled “What 1.0 is waiting for”1.0 means the surfaces in the table above stop changing without a major version. It is waiting on four things, none of which is a feature:
- A bug-discovery rate that has flattened. The honest signal is not a feature list; it is how often a session aimed at known issues turns up something new. Recent sessions have still produced silent-wrongness bugs in trait dispatch and structured concurrency. Until that stops, a stability promise would be a promise to keep bugs.
- The formal soundness review finished. All 282
unsafeblocks now name the invariant that makes them sound, and a gate step keeps it that way. What is missing is the other half: which test protects each invariant. The load-bearing ones say so; most do not. The soundness design note is where that lives. - The scheduler measured on Linux. Fibers are OS threads by default and the M:N scheduler is opt-in; that choice is settled for 0.3.0 and written up in the fibers design note. What is not settled is whether it should stay that way, and the missing evidence is the density claim on Linux — the reason the scheduler exists. The I/O backends underneath it are the other half of that question, and Linux now has
epoll– a backend rather than a rewrite, with apollfallback where the kernel will not open one. macOS wantskqueue, which is the same shape; Windows wants IOCP, which is not a backend swap because it is completion-based. - Use by people who did not write it. Nothing else substitutes for it, and it has not happened yet.
The known limitations page tracks the shorter-term version of the same list.
How language changes are decided
Section titled “How language changes are decided”In the open, in an issue, before the code. Changes that alter what a program means are recorded in the roadmap or in a design note, with the argument rather than only the conclusion. CONTRIBUTING.md has the process.
One maintainer has final say. That is stated plainly rather than dressed as a committee, so you can judge the project’s bus factor for yourself.
Reporting a break
Section titled “Reporting a break”If an upgrade breaks a program and the changelog does not say it would, that is a bug in the changelog and worth reporting on its own. Include khora --version — it carries the commit and the target triple, which is usually enough to find the change that did it.
Khora 0.4.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource