Kits Overview
The kernel contains no game rules. It ships scheduling, networking, sessions, hooks, the bus, and persistence — and deliberately stops there. Kits are where game rules live: pre-built userspace services in ChloeKernelServer/Kits that implement one genre mechanic each (hitscan guns, mana casting, melee parries, checkpoints, shops, parties) as server-validated gameplay over those primitives. You register a kit, configure it, and extend it through hooks — you do not fork it.
Every kit follows the same contract: the client sends requests, the server decides. A kit’s config is not a suggestion — each field maps to a server-enforced gate. FireRate = 8 in WeaponKit means the ninth shot in a second dies in validation no matter what the client claims.
Two registration shapes
Section titled “Two registration shapes”Config-driven kits are kernel services — build with Kit.service(config), register, done. Kits you interact with at runtime return a handle from Kit.attach(Kernel, options) with methods your code calls.
local Root = game:GetService("ServerScriptService").ChloeKernelServerlocal WeaponKit = require(Root.Kits.WeaponKit)local MeleeKit = require(Root.Kits.MeleeKit)
-- Shape 1: config-driven service. Registered, then driven by client intents.Kernel:registerService(WeaponKit.service({ Weapons = { [1] = { Name = "Rifle", Damage = 34, FireRate = 8, MaxRange = 300 }, },}))
-- Shape 2: attached handle. Client intents auto-wire AND your server code-- (NPC behaviors, quest scripts) calls the same methods players ride.local Melee = MeleeKit.attach(Kernel, { Moveset = { Jab = { Damage = 8, ComboNext = { "Cross" } }, Cross = { Damage = 12 }, },})BehaviorTree is the one exception: a pure helper with no internal scheduling — you build a tree and tick it from your own loop. MoveKit is the other special case: it lives in Shared/ChloeKernel because it has two halves — attach() on the client executes abilities, server() on the server meters them.
The shared anatomy
Section titled “The shared anatomy”Four patterns repeat across every kit. Learn them once and each kit page becomes a table of specifics.
Fail-closed client intents
Section titled “Fail-closed client intents”Kits that accept client input define prefixed intent channels on the NetDriver — WK_Fire, SK_Cast, ML_Attack, CKMove, INV_Use, SH_Buy. Each channel carries a fixed wire schema and a per-channel rate limit, and every message runs the fail-closed Intent.<Channel> hook chain before any handler executes. Fail-closed means rejection is the default: a validator returning false rejects, and a validator that errors rejects too. An exploiter cannot get a message through by crashing a check.
The kit’s own gate registers at priority 50. Your game rules prepend at lower priority numbers and run first — no forking:
-- "No firing in the lobby" — prepends below WeaponKit's gate (priority 50)Kernel.Hooks:on("Intent.WK_Fire", function(context) return Kernel:getService("RoundKit"):current() == "Round"end, 10)Fail-open hook gates
Section titled “Fail-open hook gates”Where a kit asks a game-rules question — may this damage land, may this craft start, may this companion summon — it fires a fail-open hook point instead: Weapon.CanDamage, Melee.CanHit, Craft.CanCraft, Companion.CanSummon, Party.CanInvite, Inventory.CanEquip/Inventory.CanUse. Returning false vetoes; an erroring handler is skipped and the action proceeds.
The asymmetry is deliberate. An erroring intent validator must not let an exploit message through (fail closed). An erroring damage-policy handler must not silently break all combat in your game (fail open). Input trust and game policy fail in opposite directions.
TeamKit is the pattern’s showcase: FriendlyFire = false registers vetoes on Weapon.CanDamage and Melee.CanHit, and neither combat kit knows teams exist.
Bus topics
Section titled “Bus topics”Every kit publishes its outcomes on the kernel bus — Weapon.Hit, Melee.Parried, Craft.Completed, Obby.Checkpoint. That is the extension surface for reactions: kill feeds, VFX replication, leaderboard submits, and QuestKit objectives all subscribe instead of patching kit code. Topics also compose kits that never import each other — QuestKit counts Combat.Kill and Zone.Entered without knowing what publishes them.
Profile persistence
Section titled “Profile persistence”Kits that hold long-lived player state write it through the session profile when a DataDriver is attached — session.Profile.Data — and fall back to transient session.Data otherwise. CheckpointKit stages, QuestKit progress, InventoryKit bags, LootKit pity counters, and ShopKit’s default currency field all follow this rule. No kit talks to DataStores directly; the loss-hardening lives in one place.
Composition
Section titled “Composition”Kits stack. The composition lines to know:
- InventoryKit is the item substrate. LootKit awards its rolls through it, CraftingKit consumes inputs and grants outputs through it, and ShopKit sells out of it. Define items once in InventoryKit’s registry; the other three reference ids.
- CompanionKit rides NPCKit. A companion is an NPCKit archetype spawned and follow-looped by CompanionKit; its optional
Aurais an Effects name applied to the owner while summoned. - SpellKit delegates its payloads. The kit owns mana, cooldowns, and channels; what a spell does is your
Castfunction — typically firing Projectiles or applying Effects (SpellKit). - TeamKit vetoes into the combat gates and PartyKit deliberately does not — parties are social, not combat policy, and feed Matchmaking group queues instead.
- BehaviorTree drives NPCKit handles. Trees make decisions; the handle’s helpers (and MeleeKit/Projectiles via movesets) execute them.
The kits
Section titled “The kits”| Kit | Registration | Client channels | Purpose |
|---|---|---|---|
| WeaponKit | service() |
WK_Fire |
Server-validated hitscan weapons: fire-rate/ammo gates, lag-compensated hits against rewound capsules |
| MeleeKit | attach() |
ML_Attack / ML_Block / ML_Parry |
Server-authoritative melee: windup/hit-frame/recovery state machine, combos, the block/guard-break/parry triangle |
| SpellKit | service() |
SK_Cast |
Mana, regen, cooldowns, and channelled casts as killable kernel Processes |
| MoveKit | attach() + server() |
CKMove |
Movement-context abilities (double jump, air step, dash) — client executes, server meters |
| NPCKit | attach() |
— | NPC lifecycle and per-npc state (skill model, senses memory, cooldowns); your loop makes the decisions |
| BehaviorTree | helper | — | Selector/Sequence/decorator trees with no internal scheduling — tick from your own loop |
| InventoryKit | attach() |
INV_Move / INV_Equip / INV_Unequip / INV_Use |
Server-authoritative items: definition registry, slotted stacking bags, equip slots, use handlers |
| LootKit | attach() |
— | Server-rolled weighted loot tables with nesting and per-player pity persisted in the profile |
| CraftingKit | attach() |
CR_Craft / CR_Cancel |
Recipes over InventoryKit: atomic input checks, timed crafts with cancel refunds, station gating |
| ShopKit | attach() |
SH_Buy / SH_Sell |
Soft-currency shops over InventoryKit with deterministic cross-server rotation and stock caps |
| CompanionKit | attach() |
CP_Summon / CP_Dismiss |
Owned NPC followers built from NPCKit archetypes, with owner auras via Effects |
| QuestKit | service() |
— | Quests as declarative objectives counted off server-published bus topics |
| RoundKit | service() |
— (replica out) | Round loop: ordered phase cycle, duration timers, MinPlayers gates, countdown replication |
| CheckpointKit | service() |
— (server-side Touched) |
Validated obby progression: sequence and minimum-time checks, profile persistence |
| TeamKit | attach() |
— | Team assignment, team spawns, and friendly-fire vetoes wired into the combat gates |
| PartyKit | attach() |
PT_Invite / PT_Accept / PT_Decline / PT_Leave / PT_Kick / PT_Promote |
Same-server parties: invites with expiry, leadership flow, roster pushes |
| InteractionKit | service() |
prompt triggers via Intent.Interact |
Exploit-proof ProximityPrompts: every trigger re-validates distance, line of sight, and cooldown server-side |
| ProceduralKit | service() |
— (wire yours through service:validate) |
Runtime ProceduralModel spawning with fail-closed parameter validation and rate-limited regeneration |
Which template exercises which kits
Section titled “Which template exercises which kits”The starter templates are complete minimal games; each server file lists its map requirements at the top.
| Template | Kits exercised | Alongside |
|---|---|---|
| GunArena | WeaponKit, TeamKit, RoundKit | Rewind lag compensation, Leaderboards |
| WizardDuel | SpellKit, MeleeKit, MoveKit | Effects curses and wards |
| Obby | CheckpointKit, MoveKit | Zones kill bricks, Leaderboards speedrun board |