Lanternina invents an afternoon for an adolescent, has a parent approve it, and then runs it in a real room — on paper, on e-paper displays, and on physical buttons. It reads what comes back in handwriting, decides what happens next from that, and stops at an hour the parent set.
A mini-PC in a house drives two e-paper displays, an inkjet and a flatbed scanner. Every language and vision call goes to Microsoft Foundry in the EU. No model runs on the device, and there is no offline mode. The house holds the clock and the sealing keys, and it is the only thing that starts work.
One of two displays. The frame is 3D printed and the unit was assembled by hand; the picture on it was generated an hour earlier from a theme the parent wrote.
Four decisions worth arguing about
One prompt draws the whole sheet
There is no layout engine. An image model is given every string that has already passed the safety gate, told to letter exactly those characters, and returns a finished A4 page. The design work is the prompt, and the page format lives in one Markdown file rather than in code.
A page is read against its own blank
No QR code, no ArUco markers, no declared grid — nothing printed on the paper that is there for a machine. Reading is handing a model two images, the blank and what came back off the glass, and asking what is different. An earlier version had all three, and they were deleted.
The cloud cannot start anything
The dashboard is inert by construction: approving writes a row and does nothing else. The house asks, on its own clock, and the answer arrives inside the reply. There is no inbound path to a device in a room, which is also why there is nothing on the home network to attack.
The guarantees are types, not conventions
An agent has nowhere to record that its own output is acceptable, becauseProposal has no status field. Only the safety gate can mint the type a user-facing payload requires. Each boundary test was mutation-checked: the violation was injected and the test watched to fail.
What comes out, and what goes back
The page below was drawn whole by an image model, from words that had already been screened. Somebody writes on it and puts it back on the scanner glass; the reading decides the next moments, which are written while the sheet is still on the table.
Handed over. Unedited model output, 19–33 s to draw.Came back. Filled in here by a simulated hand, so a whole run can be exercised with no person in it.
The reader's vocabulary is deliberately poor: a page came back with marks orblank, and nothing else. Not a count and not a fraction, because a count of somebody's marks is one step from a score. The reading is then gone — the type refuses to be pickled, copied or cached.
Measured on the deployment
Dates are attached because prompts change and the numbers move with them. Everything here was measured against the real services, not estimated.
Devising a whole afternoon
68–157 s
n=22, Sep 2026
Rereading it with a second model
14.4–22.8 s
Sep 2026
Drawing one page
19–33 s
Aug 2026
Ink on a drawn page
0.5–2.7 %
Aug 2026
Reading a returned page
4.4–5.5 s
Aug 2026
Button press to reading on the display
≈ 35 s
19 Aug 2026
Printed ruler, measured with a ruler
50 mm asked, 50 mm got
4 Aug 2026
The last row is the one that is not about speed. The print chain does not rescale, and that was checked by hand — a chain that silently rescales would make every physical dimension on every page wrong in a way no test would notice.
The stack
In the house
Raspberry Pi Compute Module 5 on a PoE base board, Raspberry Pi OS. Two 7.5" e-paper displays on XIAO ESP32-S3, running a patched TRMNL firmware against our own BYOS server. Epson ET-2870 over IPP and eSCL, driverless. Frames 3D printed, units assembled by hand.
In the cloud
Microsoft Foundry in the EU for every language, vision and image call, behind a single router module that is the only place allowed to import a model SDK. Azure AI Content Safety on everything generated and on every inbound image. Container Apps for the API, Cosmos DB, Blob Storage, Static Web Apps. Infrastructure as Bicep.
How it ships
A push to main publishes the API through a user-assigned managed identity with a federated credential, so there is no password anywhere in the pipeline — measured end to end at 1 m 35 s. The image is built on the runner rather than with az acr build, because the latter needs rights that would let the identity reconfigure the registry.
What goes into a frame: panel, XIAO ESP32-S3, a 2000 mAh cell, and the ribbon between them.
What it does not do
Engagement optimisation is easy to add to a system like this and would do harm, so it is a written rule rather than a matter of judgement. tests/test_boundaries.py refuses the vocabulary in the stored shape, in the panel, in the browser and in the prompts.
No streak, no daily goal, nothing withheld as a reason to come back.
No notification triggered by absence, and no measure of time spent.
A profile is kept, and it reaches the two models that write and run an afternoon — and no display, no printed sheet and no page of the panel. A review gate enforces that, not the hope that a prompt was polite.
No face or person detection, no emotion or attention inference, no biometrics.