Projects

TaleTykes

Software Engineer · September 2026 to present

A child picks who is in the story and where it happens, from pictures. TaleTykes writes and illustrates a book at the level they are actually reading, then reads it along with them one word at a time. The level gets checked before anything is drawn. Nothing becomes public without a person having read it.

A child picks who is in the story and where it happens by tapping pictures. No typing, no spelling. What comes back is a book written and illustrated for the level they are actually reading, and then it reads along with them, the word lighting up as they hear it.

Those picks are also the first safety decision. What a child taps is an identifier off a fixed list, so a child's own words never arrive in the model's instructions. On top of that there's a check for text behaving like an instruction rather than like story material, and it folds homoglyphs and zero width characters before it looks, since that's the cheap way past anything that matches literally.

There are four age bands, from a picture book somebody reads aloud up to a first chapter book. Each one sets its own word count, sentence length, grade range and how much jeopardy the story is allowed to contain. In the five to seven band the story is also built out of the letter sounds the child has already been taught, in the order schools teach them, and tapping a word shows the sounds it's made of. That constraint loosens as the phase goes up, because a story assembled purely from a restricted set stops sounding like a story.

The level check and the decodability check both run before anything gets drawn. Pictures are where nearly all the money goes, so a draft that misses its level is rewritten for a fraction of a penny instead of being illustrated and thrown away. Payment is taken at the end, after the book exists, so a family is never charged for one that failed.

Every paid call writes a cost row when it happens and the totals are sums of those rows. A book costs up to forty five cents to make and the prices are set against that ceiling rather than the cheaper usual case. A test asserts that each price clears its cost. That used to be a claim in a comment instead, and while it was a comment the two larger credit packs were selling below cost.

Making a book is a chain of separate requests handed along a queue, so one call never holds the whole thing open and a failure retries a step instead of a book. A step can be delivered twice, which is fine, because every transition is checked before any work happens. The real problem is a step that never arrives at all: the job sits there marked busy and a child waits for a book that isn't coming. So the status endpoint the browser is already polling doubles as a watchdog. If a job hasn't moved in twenty seconds and the stage it's on has pieces nobody started, they get sent again. Doing a little work twice is the cheaper mistake.

Moderation is four tiers, cheapest first, and almost everything is settled by the first two for a few milliseconds and no money. The terms carry weights rather than sitting in one flat list. Lost and dark are ordinary furniture in a picture book and drowning and corpse are not, and scoring them the same fires on nearly every bedtime story, which teaches everyone to ignore the thing. Decisions that allow get written down too. Keeping those is the only way to find out later whether the thresholds are letting things through.

Isolation between families is the database's job, not the interface's. The app connects as a role that cannot bypass row level security and declares which parent and which child it's acting for on every transaction. The credit ledger and the audit log only take new rows, with a trigger refusing updates outright. The balance is maintained by that trigger under a constraint that won't go below zero, so an overspend fails inside the transaction that tried it. Staff can grant credits and take them back from the console and both are new rows: a mistake gets corrected by an opposing entry. Every staff action states a reason, and the reason goes to the audit log rather than to the family.

A book becomes visible to anyone else only after a person has read it and the parent has turned sharing on, and the consent is snapshotted at that moment so flipping the toggle later doesn't rewrite what was true. A shared book shows a first name. There's no column for a surname anywhere in the schema. Retention is a scheduled job rather than a paragraph in the policy: a deleted profile's stories stay thirty days so a parent who changes their mind can undo it, job records and costs stay ninety so a bill can still be reconciled, and the consent records and the audit log are kept, since they're the evidence.

Children sign in with a PIN or a picture password on round keys eighty pixels across. A five year old aiming at a forty pixel square with a whole hand on the screen misses, and missing reads to them as being told no. A wrong attempt says to try again, and after a few it says to ask a grown up, which is honest, because at that point trying harder isn't going to produce the answer. There are no streaks, no timers and nothing to chase. A median dwell time is stored for working out pacing and is never shown to a child, because that is a timer.

Every external service has a stand-in that runs whenever its keys are absent, so the whole app runs, builds, tests and deploys against an empty environment. The stand-in that writes stories has to clear the same reading level and decodability checks as the real one, which is what gets those checks exercised on every commit rather than only when somebody spends money. Twice while I was building it the stand-in wrote above the level it claimed and the checks turned it down.

Not finished

Reading levels here are estimates off sentence length and word familiarity. They are good for matching a child to a book and they are not a measure of a child, and the product says that on the page rather than in a footnote. No automated check of this kind is right every time, which is why a person reads everything that becomes public and why reporting is one tap away. OpenDyslexic is offered because some readers prefer it and the evidence for it is weak, so that's what the product says about it. Model prices move and providers rename things, so the rates are configuration and want checking against the provider on a schedule. The consent and retention specifics want a lawyer before launch.