Roadmap
Calcite is built in 10 phases, and none starts until the one before it has passed its gate. Phases 0 to 5 have passed. The plan, with every task and decision, is in the repo, and the work is tracked on Acta.
Design on paper
gateSample addons and sketches written with no hand-waving; spec and host API v0.
- G0.1All five addons and all three sketches are written without hand-waving over a missing feature (passed)
- G0.2
CALX_SPEC.mdv0 settles every "Must" in it (passed) - G0.3The host API sketch covers every call the five addons make (passed)
- G0.4Every entry in the global-systems inventory has a home (passed)
- G0.5The benchmark is defined (passed)
The 7 tasks
- P0.1Write the five sample addons in imagined syntax: a
/homecommand with saved data, a chat filter, a custom mob drop, a teleport that crosses regions, and a timed world event. Seeplugins/samples/README.mdfor what each one has to test. - P0.2Sketch three pieces of Calcite in imagined Calx: the tick loop with D20's phases, one region actor and one packet handler.
- P0.3Write
CALX_SPEC.mdv0 from what those needed. It must settle every "Must" in the spec skeleton: - P0.4Inventory vanilla's world-wide systems in
docs/global-systems.md: every system that reads or writes beyond one region, where it runs (global phase or region), and whether it becomes a deliberate difference. Start with these: - P0.5Write the host API sketch in
plugins/api/HOST_API.md, once for both kinds of plugin, with the plugin model built in: - P0.6Define the Phase 3 tick-loop benchmark in
calx/docs/benchmarks.md, so the gate is fixed before the compiler exists. It should cover palette-container reads and writes, entity physics in doubles, hash-map work and actor messages. - P0.7Keep the decision log current. Every settled question goes in it, numbered in order.
Oracle rig
gateVanilla agrees with itself; the scoreboard shows Calcite at 0%.
- G1.1Vanilla agrees with itself on every pure probe under the varied self-check, with any nondeterministic cases quarantined (passed)
- G1.2The scoreboard shows Calcite at 0% across the board (passed)
- G1.3CI runs on Windows and Linux (passed)
The 9 tasks
- P1.1Keep your own
server-26.3.jarin the gitignoredoracle/jars/folder. It's already there, downloaded from Mojang and checked against the SHA-1 in Mojang's manifest. - P1.2Write the vanilla adapter in Java 25: boot, a probe dispatcher over stdin/stdout, and the first probes (RNG, NBT, text components). The jar has been unobfuscated since 26.1, so the adapter calls vanilla by its real names, with no mapping step.
- P1.3Write the runner in Python: case files, golden recording, hashes in
expected/26.3/, the self-check and the scoreboard. - P1.4Make the self-check vary everything vanilla itself might be sensitive to, not just run it twice: JVM restarts, worker thread counts and generation order. Quarantine anything that varies, or list it as a deliberate difference. Done: generation order does change vanilla's answer, so it's tested by cases in each order rather than by a variant, and Calcite matches each (D278).
- P1.5Add a
MathagainstStrictMathprobe for every transcendental function vanilla calls (sin,cos,tan,atan2,exp,log,powand so on), and run it on Windows and on Linux. Done: HotSpot's x86-64 intrinsics differ fromStrictMath, and can't be matched without copying GPL code. So the rig's reference is vanilla with the intrinsics off, whereMathis exactlyStrictMath, and default vanilla is recorded too, to measure the gap (D60). - P1.6Add a Calcite adapter stub that answers "unimplemented" to every probe.
- P1.7Write
rig/PROTOCOL.mdfor the adapter wire format: a JSON header plus raw byte blobs, sharing no code with Calcite. - P1.8Keep a registry of deliberate differences in
rig/differences/: each fixed vanilla bug or exploit, the cases it affects, and why. The scoreboard reports these separately instead of counting them as failures. - P1.9Set up CI on Windows and Linux. For now it runs the runner's own tests. Compiler tests, doc tests and Calcite checks against the committed hashes come later. Because only hashes are committed, CI can check Calcite without the vanilla jar.
Generated data tables
gateOne command regenerates everything, byte-identical on rerun.
- G2.1One command regenerates every table from a jar (passed)
- G2.2Running it twice gives byte-identical output (passed)
The 5 tasks
- P2.1Run Mojang's data generator:
java -DbundlerMainClass=net.minecraft.data.Main -jar server-26.3.jar --all --output <dir>. This was checked on 26.3 with Java 25. The options are--all,--reports,--server,--dev,--validate,--inputand--output. The bundler unpacks its libraries into the working directory, so run it from the gitignoredoracle/work/. Done:oracle/datagen/datagen.pyruns it, fetching the jar first, and drops the generator's timestamped.cache/(seeoracle/datagen/README.md). - P2.2Write a converter that turns the reports into neutral input for Calx codegen: block states with global IDs and properties, registries, packet IDs per protocol state, the command tree and items. Done:
oracle/datagen/convert.pywrites eight canonical tables, keeping every number's original text. Block states turned out to be pure arithmetic: consecutive IDs per block, mixed radix over the properties in name order. The converter checks all 35,723 states against that rule, and theblock_stateprobe confirms it against the live game. - P2.3Split what is compiled in (block states, packet IDs) from what is loaded at startup (data packs: worldgen settings, loot tables, tags, recipes), so Calcite reads data packs the way vanilla does. Done: D61. What vanilla defines in code is compiled in, including item default components and the code-defined biome parameter lists. What its built-in data pack holds is loaded from the jar at startup.
- P2.4Write the jar fetch step for the build (D30), shared with the rig: read Mojang's version manifest, download the jar and check its SHA-1. Calcite gets its own runtime version in Phase 5. Done:
oracle/fetch.py, used by the adapter's build and the data generator step. The manifest is read once, to pin a version's URL, size and SHA-1 in the committedoracle/versions.json, so builds verify offline (D62). - P2.5Write the cases for a block-state lookup probe (ID to properties and back), ready for when Calx can run them. Done: 104 cases in
cases/block_state/, recorded against vanilla and repeatable under every self-check variant. Range cases cover every state and block ID with no game data in the repo. The parser cases found vanilla accepting trailing commas and leading zeros.
Calx compiler core
gateRNG probes 100% bit-exact; tick-loop benchmark within 10% of Rust.
- G3.1RNG probes are 100% bit-exact against vanilla (passed)
- G3.2The tick-loop benchmark runs within about 10% of the Rust version on both platforms. If it doesn't, follow D37 before going further. (passed)
- G3.3Every shipped language feature has a reference page, and every example in the docs passes in CI (passed)
- G3.4On the reference machine,
calx runon a small program takes under half a second from a cold cache and under 50 ms when nothing changed, and changing one module of the benchmark rebuilds it in debug mode in under a second (passed)
The 14 tasks
- P3.1Write the Rust version of the P0.6 benchmark and run it on both platforms.
- P3.2Build the compiler in C++ with CMake and Ninja: lexer, parser, type checker and C emitter, with clang compiling its output. Goose's design notes are worth reading for ideas, but no code is reused.
- P3.3Core language:
- P3.4Java-exact semantics in the emitted C:
- P3.5A runtime library in C for Windows and Linux, with macOS later:
- P3.6Start the standard library: Java-compatible collections (D27) and strings (D28), checked against Java by the collection probes.
- P3.7Region actors, minimal at first: spawn an actor, send a flat message, receive it, and a lockstep tick barrier that delivers messages in a fixed order (D19, D20).
- P3.8Write the Calcite adapter in Calx: stdin/stdout and enough JSON to read
PROTOCOL.mdheaders, answering the RNG probes. - P3.9A compiler test suite of small Calx programs with expected output, run on every change in CI on both platforms. Docs examples run as part of it (D41).
- P3.10Debugging support: emit
#linedirectives so debuggers and profilers on both platforms show Calx source lines, and make compiler errors readable. Editor support starts here (D65): a VS Code extension with a TextMate grammar, the compiler's errors as you type throughcalx check --json, and running files. - P3.11Start performance tracking (D34): run the benchmark per commit and keep the results in
bench/. Have the emitter addrestrictwhere ownership proves there's no aliasing. - P3.12Write the reference page for every feature as it lands (D40), and move its section out of
CALX_SPEC.md. Start the guide with a first tutorial once there's enough language to write one. - P3.13Make the type checker as strict as D63 says: exact-only
T(x), named lossy conversions, no implicit optionals, no dropped values, no unused names or shadowing, and parentheses where precedence surprises. Every rule gets a compile-fail test. - P3.14Make builds fast (D64): a cache of objects keyed by their C text, parallel clang, a prebuilt runtime, lld, and
calx runreusing an unchanged executable. Track build time per commit next to run time inbench/.
Protocol and a flat world
gateA real client joins in online mode, walks around and chats.
- G4.1A real client joins in online mode, walks around and chats, with signed chat on (passed)
- G4.2The login and configuration protocol suites pass (passed)
- G4.3A recorded session replays to identical output (passed)
The 10 tasks
- P4.1Add packet codegen to Calx: declare a packet's fields once and generate its reader and writer.
- P4.2Handshake and status, so the server shows up in the multiplayer list.
- P4.3Login, in this order:
- P4.4Configuration state: registry data, known packs, tags and feature flags.
- P4.5Play state: join (with the SHA-256 hashed seed), a flat world sent as simple chunks, movement, keep-alive and chat. Start with unsigned chat (offline mode,
enforce-secure-profile=false), then add signed chat: chat sessions, message chains and acknowledgements of recently seen messages. - P4.6The network layer (D33):
- P4.7The input log (D21): record every handled packet with the tick that handled it, and add a replay mode.
- P4.8Point the rig's protocol bot at both servers and compare sessions packet by packet.
- P4.9Hardening: size limits on every packet and every decompressed payload, connection throttling, and a fuzzer on each packet decoder.
- P4.10Add a fixed bot scenario to performance tracking (D34).
Chunks, storage, regions, worldgen
gateWorldgen suites pass in all three dimensions; worlds round-trip; one thread and many give identical results.
- G5.1The worldgen suites pass on the seed grid in all three dimensions (passed)
- G5.2Worlds round-trip between vanilla and Calcite (passed)
- G5.3One-thread and many-thread runs of the same input log give identical results (passed)
The 12 tasks
- P5.1Palette containers for block states and biomes as Calx primitives, plus chunk sections and heightmaps.
- P5.2Read and write the whole world folder, not just the region files, in 26.3's format only (D31):
- P5.3Crash-safe saving: write files atomically, and autosave each region without pausing its tick.
- P5.4Build regions in steps: one region, then several fixed regions, then regions that split and merge as players move (D22).
- P5.5Chunk tickets and load levels as vanilla has them: view distance, simulation distance, entity ticking range, forced chunks, and portal and ender pearl tickets. What's loaded and ticking decides how farms behave, so this gets its own parity suite.
- P5.6Chunk loading and generation run as jobs off the region threads, and their completions go into the input log (D21).
- P5.7Lighting: sky light and block light, checked by the light probe.
- P5.8Load data packs at startup: the built-in pack from the client jar's data (D30, D140), plus the world's own packs. They mustn't slow the start much. The boot cache's key takes in each pack's path, size and modification time, and each file's for a pack that's a folder, so an unchanged world still starts from the cache. On a miss, the packs' files are read and parsed in parallel, and the cache is written again.
- P5.9Worldgen in vanilla's stage order, with a probe per stage: noise and density functions, biomes, terrain shape, surface, carvers, features, then structures. Features are decorated in the 3×3-colored order (D29), and the rig drives vanilla in the same order.
- P5.10The Overworld first, then the Nether and the End.
- P5.11Cache chunk packets: encode each chunk once and send the same bytes to every player who needs it.
- P5.12Pregenerate chunks, built in, as the Chunky mod does:
/pregenwith Chunky's subcommands generates every chunk in an area, a center and radius or the world border, in any of the usual shapes, region by region or in rings or a spiral.
Simulation
gateSuite parity where you want it; a survival session feels like vanilla.
- G6.1Each suite's parity is where you want it on the scoreboard (not yet)
- G6.2You can play an ordinary survival session on Calcite without noticing a difference (not yet)
The 9 tasks
- P6.1Copy vanilla's order of work inside a tick exactly, mapped onto the tick phases. Turn on the agent's seeded randomness and keep the RNG tape running from here on.
- P6.2Blocks: neighbor updates, scheduled and random ticks and fluids, then redstone (wire, repeaters, comparators, then pistons). Use the Java-compatible collections wherever vanilla's iteration order shows, starting with redstone wire.
- P6.3Players and items: inventories and containers, placing and breaking blocks, crafting.
- P6.4Entities: movement and collision, then mobs (AI goals, pathfinding, brains), then spawning.
- P6.5Combat, damage, effects, enchantments, loot tables, advancements and scoreboards.
- P6.6Commands: a parser driven by the generated command tree, then the commands themselves. Selectors and anything else that can reach beyond a region run in the global phase (D20).
- P6.7The rest of the data pack system: functions, predicates, item modifiers, recipes,
/reloadand/datapack. - P6.8The world-wide systems from the Phase 0 inventory.
- P6.9Build test contraptions in vanilla, save them as structure files, and use them as sim fixtures. Vanilla's data-driven GameTest framework (
/test) may already be able to run them in vanilla, so check that before building a custom harness.
Plugin host
gateFive sample addons run natively and one as WASM; runaways are stopped; reload keeps state.
- G7.1All five sample addons run as native plugins (not yet)
- G7.2One of them also runs as WASM, built from the same source (not yet)
- G7.3A runaway or panicking plugin of either kind is stopped without hurting the tick (not yet)
- G7.4Reloading a plugin keeps its state (not yet)
- G7.5Every host API function the samples use has generated reference docs and a guide page that covers it (not yet)
The 12 tasks
- P7.1Generate both bindings and the reference docs from the one host API definition: a Calx interface for native plugins and WASM imports for addons (D41).
- P7.2Native Calx plugins: compile each to a shared library against the host API and load it at startup. Calx's type checker enforces region scoping at compile time. Plugins mustn't slow the start much either: their libraries load in parallel, each one's start is timed and a slow one is named in the log, and work a plugin can leave for later runs after the server listens.
- P7.3Tick budgets for native plugins: have the compiler insert cheap budget checks at loop back-edges in plugin builds, so a runaway plugin can be stopped without a sandbox.
- P7.4Native plugin limits and isolation: a plugin gets only the host API unless it's marked trusted, and a panic stops only that plugin's instance (D15, D25).
- P7.5Hot reload for native plugins: load the new library, run a state-migration hook, and swap between ticks.
- P7.6Per-plugin profiling from day one: tick time per plugin and per handler, always on and cheap enough to leave on.
- P7.7Host API versioning (D35) and plugin data storage (D36).
- P7.8Permissions: permission nodes, with defaults by op level. A plugin can replace the permission store.
- P7.9Inter-plugin APIs: a plugin can export typed functions and messages for other plugins to use.
- P7.10WASM second: embed Wasmtime, expose the same host API as imports, enforce budgets with the runtime's interruption, and grant capabilities per addon. Calx emits C and clang can compile C to wasm32, so a plugin that stays inside the host API can build both ways from one source.
- P7.11Write the plugin developer guide in
docs/plugins/alongside the host: getting started, the plugin model, events, commands, data, testing. - P7.12Port the five sample addons as native plugins, then build one of them as WASM too.
Benchmarks and your own servers
gateMSPT recorded against Paper, Folia and Pumpkin; one of your servers runs on Calcite.
- G8.1MSPT is recorded at every bot count for all four servers (not yet)
- G8.2One of your own servers runs on Calcite (not yet)
The 6 tasks
- P8.1Reuse the rig's bot as a swarm of 25, 50, 100 and 200 bots that walk, explore new chunks, build and fight.
- P8.2Run the same seed and script on Calcite, Paper, Folia and Pumpkin. Record MSPT (mean and 99th percentile), memory and CPU use per core. Time pregenerating the same area against Chunky on Paper and Folia, in chunks a second (P5.12).
- P8.3Profile the slowest systems and fix them, rerunning the rig after every fix.
- P8.4Soak test: run the bot swarm for a full day to catch memory leaks and slow drift in tick time.
- P8.5Operations: read vanilla's server.properties, ops, whitelist and ban files so a server folder moves over unchanged, and add the console, RCON, logs, metrics and crash reports.
- P8.6Move one of your own servers over, keeping backups. Because worlds round-trip, vanilla or Paper stays your fallback. Older worlds go through vanilla 26.3 first (D31).
Plugin SDK, tooling and docs site
gateA newcomer ships a tested plugin in under an hour using only the docs.
- G9.1Someone new to Calcite goes from nothing to a working, tested plugin in under an hour using only the docs (not yet)
- G9.2The language server works in VS Code on Windows and Linux (not yet)
- G9.3The docs website is live and is rebuilt from the repos on every merge (not yet)
The 7 tasks
- P9.1A
calxCLI for plugins: - P9.2A Calx language server (diagnostics, completion, go-to-definition, hover docs from the host API), which the VS Code extension from P3.10 switches to (D65).
- P9.3A plugin test harness: headless Calcite, scripted bots (the rig's bot) and recorded input logs replayed against the plugin, with assertions on world state and packets.
- P9.4The docs website, built from the Markdown both repos have been keeping since Phase 0 (D40). Pick the site generator then. It covers the Calx guide and reference, the plugin guide, and the generated host API reference. The five samples become tutorials. The Calx part came earlier: the Calx website is built now, in
calx/site/, on its own track (D174, CLX-60), and is live at https://calxlang.com. P9.4 adds the plugin guide and the host API reference to it. - P9.5A profiler view for the per-plugin data from P7.6.
- P9.6SDKs for WASM addons in other languages, Rust first, generated from the host API.
- P9.7Custom content without client mods: helpers for data components, item models, dialogs and data-pack registries.