Telegram checklist forms¶
scripts/forge_telegram_checklist.py is the generic checkbox-form engine for the Telegram fleet (built 2026-06-09). One message = numbered item list + inline keyboard: a toggle button per item, a ✅ Submit (n) + 🔁 refresh row, then URL buttons linking to the source tables (tasks.justinsforge.com, Notion DB).
Productivity batch (2026-06-10, commit 8795a19): /today sends calendar block + ONE mixed form (tasks due today across all 5 brands + pending habits; per-item kind override drives apply). Every task row has a 📅 button opening forge_telegram_datepick.py (inline month grid, prefix cal, action registry; task_due sets Notion Due). /timer [min] [label] runs forge_telegram_timer.py, a DETACHED self-editing countdown (survives bot restarts). /keyboard on|off toggles a persistent quick-bar reply keyboard. forge_telegram_set_commands.py registers the / menu (re-run on command changes). PROBE RESULT: native sendChecklist returns PREMIUM_ACCOUNT_REQUIRED; inline-keyboard forms stay canonical. Inline mode still needs Justin in BotFather (/setinline).
Surfaces:
- Coordinator fast-path commands, zero LLM call: /todos [life|jwvr|nova|fishing|bass], /tasks [brand], /habits (parsed in forge_telegram_coordinator_bot._try_checklist_fastpath).
- Brain tools tasks_form + habits_form (in forge_telegram_inbox_brain.py, both in the coordinator hot set) so "show my todos" / "habits form" natural language works too.
- Any producer can call push_tasks_form(brand) / push_habits_form() or send_form() with arbitrary items (kinds: task sets Status=Done + Done At; habit sets Quantity=1; both via forge_n8n notion-update-page).
Quantity habits (2026-06-10, after "checkbox unclear for water cups" feedback): habits whose Habit Definition has Goal qty > 1 render as counters, not checkboxes. Button shows live progress (➕ Hydrate 3→5/15); each tap stages +1 (tapping past goal cycles staged to 0, that's the undo); a per-row ✓ all button stages the full remaining amount. Submit writes Quantity = base + staged ABSOLUTE (double-submit safe). Callback ops: chk:t tap, chk:f fill-all. Pending filter is goal-aware (qty < goal, partially-drunk water still shows). Defs-query failure degrades counters to plain checkboxes. Cross-process flock per form (<form_id>.lock) guards read-modify-write; the submit child snapshots under lock, calls n8n outside it, merges results back under lock so mid-apply taps survive.
Latency (fixed 2026-06-10 after lag report): toggles answer the spinner first, then edit ONLY the keyboard (editMessageReplyMarkup, no full-text edit; body marks catch up on Submit/refresh). The coordinator coalesces a burst of chk:t taps from one getUpdates batch into one keyboard edit per form (dispatch_toggle_batch). Fleet-wide: forge_telegram_format.tg() now reuses a pid-checked keep-alive requests.Session (bare requests.post paid a TLS handshake per call). Measured: single toggle 1.0s to 0.5s, 5-tap burst ~5s to 1.4s.
Mechanics: callback prefix chk (chk:t:<form_id>:<idx> toggle, chk:s:<form_id> submit, chk:r:<form_id> refresh); form state JSON at forge/data/telegram_checklists/<form_id>.json so the 64-byte callback_data limit never carries page ids. Submit forks a daemon mp.Process so the poll loop never blocks on n8n; applied items are flagged (idempotent, double-submit safe); failed updates get unchecked with a retry note. Habit dones also append to data/habits_callback_ledger.jsonl (source: checklist_form). Items capped at 12 per form; title says "first 12 of N" when truncated.
Gotchas: coordinator service must import the module (registers the chk prefix); restart coordinator after edits. CLI smoke test: ~/.forge-venvs/inbox/bin/python scripts/forge_telegram_checklist.py {todos [brand]|habits} sends a REAL form to the coordinator chat.
Related: [[feedback-telegram-bot-ux-reactions]], the per-habit [Done][Skip][Tomorrow] buttons in forge_habits_callbacks.py (single-item sibling).
[Claude Code]