All outbound notifications from Luci go through ~/workspace/notify.py -- a lightweight Telegram helper with quiet hours, deduplication, and forum topic routing.
notify.py (~120 lines) with no external dependencies beyond stdliburllib.request (no SDK needed)246672479) -- direct private messages-1003838721412) -- organized by topic threadsThe Claude Forum is a Telegram group with forum mode enabled. Each topic is a persistent thread:
| Topic | Thread ID | Used For |
|---|---|---|
| General | 1 | Spotify radio, uncategorized |
| Home | 3 | Home Assistant health checks |
| Life Manager | 7 | Life digests, personal alerts |
| Work | 20472 | CEO dashboard briefings, FlySafair data |
| Mission Control | 4712 | New ticket notifications, task failures |
from notify import send, send_telegram, send_to_topic, send_life_manager, send_home, send_work, send_mc, send_spotify, send_ticket_notification, send_audio
# Preferred: central dispatcher with named destination key
send("dm", "message")
send("home", "message")
send("work", "message")
send("mc", "message")
send("life-manager", "message")
send("general", "message")
# Audio upload (sendAudio multipart)
send_audio("work", "/path/to/file.mp3", caption="Daily brief")
# Lower-level / legacy wrappers (still supported)
send_telegram("message") # DM to Elmar
send_to_topic(TOPIC_LIFE_MANAGER, "message")
send_life_manager("message")
send_home("message")
send_work("message")
send_mc("message")
send_spotify("message")
# MC ticket notification (auto-formats with priority emoji and link)
send_ticket_notification(ticket_id, identifier, title, priority="medium")
notify.py exposes a NOTIFY_DESTINATIONS dict mapping each key to (chat_id, thread_id, label). This is the canonical list — add new topics here and every consumer (CLI, MC dropdown, scheduler tasks) sees them automatically. Valid keys: dm, general, home, life-manager, work, mc.
notify_to: frontmatterScheduled tasks declare a destination in their .md frontmatter:
---
id: my-task
notify_to: home # one of NOTIFY_DESTINATIONS keys
...
---
The scheduler injects this as LUCI_NOTIFY_DEST into the task subprocess environment. Scripts that route through notify.py read it (os.environ.get("LUCI_NOTIFY_DEST", <default>)) to pick the destination. Falls back to a per-script default when unset.
python3 ~/workspace/notify.py "msg" # DM to Elmar
python3 ~/workspace/notify.py --dest work "msg" # Forum: Work topic
python3 ~/workspace/notify.py --dest mc "msg"
--topic is accepted as a legacy alias for --dest.
False)force=True to bypass quiet hours/tmp/luci-notify-dedup.jsonforce=True skips dedup entirelyThe 03-scheduler/overview|scheduler sends notifications based on each task's notify_on setting:
| Event | Notification | Force |
|---|---|---|
| Task completed | LUCI: {title} completed ({duration}s) |
No |
| Task failed | LUCI ALERT: {title} failed Nx consecutively |
No |
| Self-heal succeeded | LUCI SELF-HEALED: {title} -- fixed automatically |
No |
| Self-heal rejected | LUCI HEAL REJECTED: {title} -- diff failed validation |
No |
| Probation failure | LUCI PROBATION FAILURE: {title} failed again |
Yes |
| Task suspended | LUCI SUSPENDED: {title} |
Yes |
| Task timeout | LUCI TIMEOUT: {title} killed after {timeout}s |
No |
| Scheduler crash | LUCI SCHEDULER CRASH |
Yes |
| Duplicate task ID | LUCI SCHEDULER ERROR: Duplicate task ID |
No |
Created via send_ticket_notification():
python3 notify.py "Your message here"
Sends a direct DM to Elmar with force=True (bypasses quiet hours and dedup). Useful for manual one-off alerts.
All messages default to Markdown parse mode (parse_mode="Markdown"). Pass parse_mode=None to send plain text if Markdown formatting causes issues.
Telegram send failed: {error})False but do not raise exceptionsnotify.py module using the Telegram Bot APIforce=True overridesMission Control is the board for your delegated work: requests come in, Luci coordinates the next step, and evidence stays visible for review.
Luci is your always-on assistant for routing, status updates, and follow-through. Operators can still open deeper evidence when needed.