The safety gate: shipping model output to a three-year-old
July 2026 · Markus Skov
Fable's on-device model writes bedtime stories for children. The hard part is not generation. It is the promise that no model output reaches a child unchecked, in seven languages, on a device we cannot observe.
The design assumes the model is untrusted and the parent's input is hostile until proven boring. Four ideas carry the whole thing.
1. One chokepoint in, one gate out
Every request passes through a single neutralization boundary: names and free-text fields validated, lookalike characters folded, zero-width characters stripped, template braces removed. And every story, from every engine, passes the same acceptance gate before display. The provider re-checks even engines that gate their own output, because a postcondition that depends on someone else's internals is not a postcondition.
2. The gate speaks every shipped language
A denylist that flags the German word "die" as English death, or misses that a Norwegian story ended in an English "goodnight", is worse than none. Each language carries its own denied vocabulary, its own sleep-signal words for the mandatory wind-down ending, and its own false-friend exemptions. Matching happens after Unicode normalization, so homoglyph tricks do not slip past.
3. Prompts fence data from instructions
Everything a parent typed, and every recap the model itself wrote on an earlier night, sits inside a delimited data block with the fence characters stripped from the values. The instructions above the fence never contain a parent's words. This sits under the operating system's own model safety layer, not instead of it.
4. Failure falls to a calmer floor
Model refused, gate refused, model unavailable: a hand-written story shelf answers. Shelf broken: an emergency story from neutralized values. That broken too: one constant story proven safe by exhaustive test. A child sees exactly one story and zero errors, every night.
Does it hold?
We measure it. When we first instrumented per-language yield, the model passed the gate on roughly half to three quarters of first attempts depending on language, and the dominant failures were ending discipline, not content: stories that forgot the child's name on the last page, or wound down in the wrong language. After restructuring the ending contract so the engine and the gate share one definition, a full measurement run passed 8 of 8 attempts in every supported language. The seeded, hand-written shelves are swept exhaustively: thousands of rendered stories per language through the full gate, and separate live-model sweeps lint real generations for artifacts the gate does not judge, like lookalike apostrophes.
None of this is exotic. It is layered defense applied to a consumer AI product, with the unusual constraint that the runtime is a phone in airplane mode and the user is asleep before the second page.
The other half of this story is the architecture: An AI bedtime app with no server.