Last post, all three unit kinds were done — RuntimeUnit, AdapterUnit, IntegrationUnit, their factories, and the theoretical boot sequence. Interfaces existed. Nothing used them yet.
That changed. The first internal runtime is running: Node.
Node is the default. Velnora is built on Node, the CLI runs on Node, and the majority of early workspaces will be JavaScript or TypeScript projects. If any runtime was going to be the first real implementation, it had to be this one.
For now, Node runs by default — it is not something you attach or configure. It is just there. This is intentional. Before I can make runtimes attachable and swappable, I need one that works end-to-end as a reference. Node is that reference.
The Node runtime is built using defineRuntime() — the same factory from the Unit System. It declares its capabilities and its toolchain. When the Kernel boots, Node is the runtime that is available.
This is still an example case. The runtime exists to prove that the interfaces work in practice, not just in type definitions. Can defineRuntime() actually produce something the Kernel can use? Can ctx.query('javascript') return a real API? Can a package manager resolve correctly for a Node project?
The answer to all of those is yes — but only because it is hardcoded for now.
The config file parser is already in place. Velnora reads the config, resolves units, and passes them through. But right now there is nothing meaningful to parse — the built-in runtimes are default ones, so their factory functions just return {}. No user-facing options, no overrides, no environment branching. The parser runs, but the configs are empty.
Later, when runtimes become attachable and start accepting real options, the parser will do actual work. For now it is wired up and waiting.
The goal is to make runtimes attachable. You should be able to drop node() or bun() into your config's unit array and have the Kernel pick it up. The current implementation is a stepping stone — once I test with Bun as a second runtime, the hardcoded default will be replaced with proper registration through the unit array.
Bun is the real test. If the same adapter code works unchanged with both Node and Bun — different runtimes, same ctx.query('javascript') call, different ExecutionPlan results — then the Unit System's design actually holds. That is the validation I am building toward.
For now, Node runs. The first runtime is alive. The interfaces are no longer just types.
Almost forgot — I also added H3 adapter support. H3 is already the HTTP layer powering Velnora's Host, so wiring it up as an adapter was a natural next step. This is the first real AdapterUnit in the project — built with defineAdapter(). Like the Node runtime, it is in the project and working, but not fully implemented yet. The scaffolding is there, the unit registers, the Kernel sees it — but the actual dev() and build() logic is still incomplete. Both Node and H3 are proof that the interfaces work in practice. They will grow as the project goes — each new feature that touches runtimes or adapters will fill in more of these implementations naturally.
With the runtime alive, the next piece is what I am calling the reader-implementor flow. The config file gets fetched, the built-in defaults get merged in, and the Kernel has to take that flat list of units and actually do something with it — classify by kind, topo-sort, call configure(), collect exposes. The "reader" reads the config and resolves units. The "implementor" walks the sorted units and runs their lifecycle hooks. Right now I am in the middle of wiring these two halves together. How is it going? Honestly, not great.