Architecture & Security
Two locations define the whole model:
ReplicatedStorage.ChloeKernel replicates — generic primitives onlyServerScriptService.ChloeKernelServer NEVER replicates — everything privilegedThe principles
Section titled “The principles”- The client is a renderer with opinions. It sends intents, never state. The server validates every intent through fail-closed hook chains and is the only thing that mutates state.
- Code placement = attack surface. Validators, rate limits, drop tables, AI logic, data:
ServerScriptService. The client holds only what it must execute — input, prediction, VFX. Anything inReplicatedStoragewill be read by exploiters; that is assumed, not feared. - Fail-closed everywhere. A crashing validator rejects the action. A failed data load kicks rather than risking a wipe. A schema-violating save is refused. An unmigratable record won’t load. A handler-bearing channel with no validator rejects every payload — missing permission is not permission (NetDriver).
- Your character stays yours. The kernel never reassigns a character’s network ownership and never anchors character parts — the client keeps simulating its own character at all times, so movement always feels local. Anti-exploit corrections are plain CFrame writes (ownership intact), and movement abilities go through Prediction: the client moves itself instantly, the server validates, rejections roll back.
- Explicit non-goals. Client code is always readable by exploiters — the defense is never trusting it, not hiding it. Cross-server trades can’t be made safe without a coordinator, so they’re refused. Obfuscation is not security.
What this means in practice
Section titled “What this means in practice”| You want to… | The architectural answer |
|---|---|
| Let players buy an item | Client sends SH_Buy intent → validators re-derive price and balance from server books → server grants. Client math is UI decoration. |
| Show fast, responsive abilities | Prediction: client acts instantly, server reconciles, rejection rolls back. Authority never moves. |
| Punish speedhackers | Movement Monitor detects; your hook decides policy. Detection is the kernel’s job; punishment is yours. |
| Validate shots from high-ping players | Rewind rewinds position history to the client’s timestamp — server raycasts; the client never reports hits. |
| Know your surface is closed before shipping | kernel:securityAudit() sweeps unguarded channels, Open escape hatches, fail-open gate hooks, defaulted rate limits — see Fuzz & Security Audit. |
Layered defenses on every intent
Section titled “Layered defenses on every intent”Every network intent passes, in order:
- Transport flood cap — Packet’s 8KB/heartbeat budget per player, checked before any decoding so garbage can’t buy CPU (
Net.FloodDetected). - Schema decode — buffer-typed arguments in the Packet transport; a payload that doesn’t decode is discarded.
- Session & per-channel rate limit — a session must exist, then the token bucket, per player (
Net.RateLimited). - Validator-absence check — a handler-bearing channel with no validator rejects outright.
- Declarative rules —
Range/OneOf/MaxLengthfrom the Registry, installed at priority 5. - Your validators — the fail-closed hook chain, server state only.
- The handler — runs only after everything above passed.
The full pipeline costs well under a microsecond per packet (benchmarks). Rejected intents cost the client nothing and the server ~150ns through the chain.