Core Concepts
Five primitives. Everything else in the framework — networking, persistence, kits, anti-exploit — is built out of these.
1. Kernel
Section titled “1. Kernel”Boots once per machine — server and client each run one. It owns the scheduler, hooks, bus, and services. ServerKernel adds sessions, networking, and everything privileged.
-- src/Server/Main.server.luau already does this; shown for orientationlocal ServerKernel = require(game:GetService("ServerScriptService").ChloeKernelServer)local Kernel = ServerKernel.boot()-- ...Bootstrap registers services here...Kernel:start()
-- anywhere else on the server, after boot:local Kernel = ServerKernel.current()Deep dive: Kernel & Boot.
2. Services
Section titled “2. Services”Your game’s systems, registered before start(), booted in dependency order. Every init runs before any start, so start can safely use any dependency. Cycles crash loudly with the full chain (A -> B -> C -> A).
Kernel:registerService({ Name = "Quests", Dependencies = { "Inventory" }, init = function(self, kernel) self.Kernel = kernel self.Active = {} end, start = function(self) self.Inventory = self.Kernel:getService("Inventory") -- guaranteed initialized end, stop = function(self) end, -- reverse boot order on shutdown})Deep dive: Services.
3. Sessions
Section titled “3. Sessions”One per player, created on join, destroyed on leave. Anything bound to a session is torn down automatically — connections, instances, functions.
Kernel:onSession(function(session) session.Data.Streak = 0 -- per-visit scratch session:bind(session.Player.CharacterAdded:Connect(onSpawn)) -- auto-disconnected on leave session:bind(function() print("left:", session.Player.Name) end)end)session.Data is per-visit scratch; session.Profile is persistent data once a DataDriver is attached. onSession also fires for players already in the game, so late-registering systems never miss anyone.
Deep dive: Sessions.
4. Hooks
Section titled “4. Hooks”Named validation chains. Handlers mutate a context or cancel by returning false. Fail-closed: a crashing validator rejects the action. Every network intent passes through one.
Kernel.Hooks:on("Intent.BuyItem", function(context) if context.Session.Profile.Data.Coins < Prices[context.Args[1]] then return false -- rejected; the handler never runs endend, 10) -- lower numbers run earlier
local Passed, Context = Kernel.Hooks:fire("Intent.BuyItem", { Session = s, Args = { itemId } })Deep dive: Hooks · every built-in hook point: reference.
5. The Bus
Section titled “5. The Bus”Topic pub/sub so systems communicate without importing each other. Wildcards subscribe to whole families.
Kernel.Bus:subscribe("Combat.Kill", function(topic, killer, victim) end)Kernel.Bus:subscribe("Combat.*", function(topic, ...) end) -- whole familyKernel.Bus:publish("Combat.Kill", killerSession, victimSession)Deep dive: Signals & Bus · every built-in topic: reference.
How they compose
Section titled “How they compose”A single player action touches all five. A client fires UseItem; the NetDriver checks the rate limit, decodes the buffer against the channel schema, and fires the Intent.UseItem hook chain with the player’s session in context; validators check server-side state; the handler mutates session.Profile.Data; the change publishes on the bus; a replica picks it up and schedules a delta broadcast on the scheduler under the frame budget — and nothing in that path trusted a byte the client sent.
The security consequences of this shape are spelled out in Architecture & Security.