Blog ยท release
Latch 0.12.0
Playsets and events. Content made by other people โ training, Handler lines, wheel segments, habits, trance scores, badges โ installed from one file and taken out as one unit; and events, which are playsets with a window, a sign you wear, and badges you can only earn inside it. Locktober 2026 is the first.
- A playset is data, never code. One
playset.toml(plusart/*.png,scores/*.json,README.md) in a zip.core/playsets.pyparses it, checks it against a fixed format and copies it into tables that already exist. ๐ด Unknown keys are refused at every level, so a playset written for a newer Latch fails loudly instead of installing three-quarters of itself. The same validator is on the command line:python -m latch.playsets check <file>. - Install is tagged; remove is exact. Every row a playset writes carries
playset_id(migration 12). Remove deletes what has no history and keeps โ disabled, still tagged โ a task you actually did or a prompt you actually answered. Badges you earned stay: frozen evidence, never a live join. Switching a playset off hides its content; on restores it. - Events.
[event]gives a playset a window (local dates), a sign and accent, a Handler line,voice = replace|mix, and[[event.days]]โ one task per day, assigned on the day, once, due at midnight. Join and leave are events in the log (event_join,event_leave); nothing joins you. While you are in a running event its lines take the Handler's voice for every kind it wrote, the sign sits in the header, the card leads the dashboard, and the newevent_name/event_daytokens put LOCKTOBER ยท DAY 12/31 on share cards and stamped photos โ as-of the shutter, like every other token. - Badges from a menu, not a language. Five rule templates โ
joined,count,days,locked_days,finishedโ each writing its own evidence. Event badges carryevent:<slug>as their period, so next year is a new trophy. ๐ดfinishedis decided only after the window closes; the others land the day you hit them. A playset's art renders on/badgesin place of the emoji. - Trance scores travel.
scores.library(conn)is the built-ins plus every enabled playset's scores, through the same validator; a built-in slug cannot be replaced. The module's "no score upload" line still holds โ the upload is a playset's. - The core still makes zero outbound calls. The app never fetches a playset. The catalogue is a page your browser visits; you bring the file.
- New page
/playsets, new guide page, 33 tests. Audio tracks in playsets are spec 2.