Oshun Platform · Guides & deep dives

Telegram Rooms, Reminders, Notifications, and Voice

The Telegram rooms contract exposes:

12sections6 minread1table

On this page

Telegram offers compact versions of Oshun's member rooms plus continuity controls that are natural in chat: resume, save, reminders, quiet hours, delivery stop/resume, time zone, voice notes, and spoken responses. Every read and write travels through a typed port so the bot cannot claim state it did not read or persist.

sequenceDiagram actor Member participant Telegram participant Webhook as Oshun BFF webhook participant Port as Room reminder or effects port participant Scheduler as Fenced delivery cycle participant BotAPI as Telegram Bot API Member->>Telegram: Room command reminder or voice note Telegram->>Webhook: Verified retried update Webhook->>Webhook: Durable claim scope safety and local-time checks Webhook->>Port: Typed read write or STT-grounded request Port-->>Webhook: Ready applied unavailable denied or failed outcome Webhook->>BotAPI: Response calls with keyboard or media BotAPI-->>Webhook: Application result and message id Webhook-->>Telegram: Acknowledge update and record receipt Telegram-->>Member: Honest room or action result opt reminder becomes due later Scheduler->>Port: Claim due reminder and re-check member policy Port-->>Scheduler: Deliverable suppressed blocked or retryable Scheduler->>BotAPI: Fenced reminder delivery BotAPI-->>Scheduler: Receipt retry-after or permanent failure end

Creation and scheduled delivery are separate promises. The scheduler must re-check current binding, stop/quiet state, time zone, policy, and provider result before it marks a reminder delivered.

Room port#

The Telegram rooms contract exposes:

Command Domain content Typical actions
/sit, /today Tara ritual Pace breath cues, advance/complete ritual, optionally schedule another reminder.
/checkin Arete check-in Present humane habit/mood state and record a permitted check-in.
/tonight Nyx sky window Resolve member time/location context and show the relevant observation window.
/passage Nisaba passage Present passage/source and offer save/share/deep-link actions.
/library Member library List open items without exposing another member's state.
/continue Continue point Resume the latest supported room/activity.
/streak Streak/recovery summary Show current state using non-punitive recovery language.
/settings Telegram/member settings Show time zone, quiet hours, voice, and delivery state.

Reads return structured ready/unavailable/forbidden/missing-context outcomes. The BFF rooms adapter connects these contracts to member-domain services or returns explicit not-connected copy. Group scope forbids personal room reads; shared passage and question content follow their separate rules.

Grounded question room#

/ask <question> invokes the Sophia grounder with actor/chat context and bounded question text. It returns answer, citations/evidence, provenance state, or abstention. A response is rendered with disclosure and source buttons where available. See Safety, privacy, grounding, and rights.

Save and preferences effects#

The effects port owns actual mutations:

  • save a note/link/reference;
  • change quiet-hours or delivery preferences;
  • stop and resume Telegram delivery;
  • change voice preference;
  • unlink the Telegram account;
  • set member time zone.

Each operation returns an applied/duplicate/invalid/denied/unavailable/failed outcome as applicable. The bot only uses success copy after an acknowledged effect. Idempotency uses update/callback/request identity so Telegram retrying an update cannot duplicate a note or flip a preference twice.

Time zone and local time#

Telegram does not provide a member's time zone. The bot resolves it from the durable member profile when available or asks for /timezone. It validates IANA zone names and can describe limitations of a fixed offset where supported.

All “today,” “tonight,” quiet-hours, and absolute reminder calculations use the member zone—not the container clock. Confirmations include local time and zone so an apparently valid instant is not misleading. DST gaps/overlaps, invalid zones, changed zones, and stale member profile state have explicit tests.

Location needed for Nyx is a separate permission/context fact; a time zone does not imply precise location.

Reminder creation#

/remind and supported natural phrasing parse a bounded vocabulary such as a relative duration, time today/tomorrow, or a clock time in the member's zone. The parser produces a typed ReminderRequest; ambiguous or unsupported text returns “time not understood” rather than guessing.

The reminders port schedules against the durable reminder service with member, chat/binding, requested local expression, resolved instant/zone, content/room reference, idempotency, and policy context. The confirmation repeats the actual resolved time. Maximum relative windows and reminder limits are enforced.

Scheduled delivery cycle#

Creating a reminder is not delivering one. A deployed scheduled cycle must:

  1. Claim due reminders with lease/fencing and a bounded batch.
  2. Re-check binding, opt-in, stop state, quiet hours, rights/policy, and current member time zone/delivery context.
  3. Build the Telegram response and inline action keyboard.
  4. Call the real Bot API and inspect the application response.
  5. Mark delivered only after acceptance; record retryable/permanent/blocked failure separately.
  6. Use bounded backoff without losing a transient failure or delivering twice.
  7. Release/recover stale claims and expose backlog/age/attempt metrics.

Deployment must run exactly one logically fenced cycle per due item even when multiple tasks/processes are active. The promise-kept and delivery-stop tests in the BFF pin this boundary.

Reminder actions#

Delivered reminders can carry namespaced callbacks for completion/dismissal and supported snooze choices (the shared contract currently defines short and hour-scale options). The action re-authorizes the member/chat/reminder, deduplicates callbacks, rejects expired/foreign state, persists the outcome, and answers the callback query.

Snooze creates/updates the durable schedule with an exact new instant. “Done” and “dismissed” remain distinguishable where domain behavior needs it. A local button acknowledgement without the reminder-port result is not completion.

Quiet hours, stop, and resume#

Quiet hours suppress ordinary scheduled delivery according to the member zone and policy, with a declared next eligible time. They do not silently discard the reminder. Crisis and critical transactional policy is evaluated by the channel dispatcher, not by bypassing preferences ad hoc.

/stop is a durable delivery control and must stop both scheduled and ordinary eligible outbound sends after acknowledgement. /resume is the explicit recovery. Blocking the bot at Telegram is also observed as stopped/blocked delivery but cannot be reversed from Oshun; the member must unblock/reopen the chat.

Notifications beyond reminders#

The shared dispatcher can route allowed member/curated intent classes such as session notifications, ritual reminders, grounded content, and transactional receipts to Telegram when consent, residency, tier, capability, quiet-hour, frequency, crisis, and tenant policy allow it. AAA and operator traffic never routes to messaging.

Every outbound notification carries content class, disclosure/provenance, member/binding, correlation/idempotency, and delivery state. A scheduled task or event producer must be deployed; a renderer and dispatcher alone do not create notifications.

Voice notes and speech-to-text#

For a Telegram voice message, the runtime:

  1. validates update/chat/member scope and rate/safety policy;
  2. resolves Telegram file metadata/download under size/type/time limits;
  3. sends recording/typing presence as appropriate;
  4. invokes the configured STT provider with bounded audio and declared locale;
  5. treats the transcript as untrusted member input and routes it through the same command/question/safety logic;
  6. records provider/version and failure without storing raw audio/transcript as durable memory unless policy and consent permit.

Missing STT configuration returns stt_not_configured behavior; it never pretends to understand audio. Provider timeout, invalid media, empty/low-quality transcript, oversized file, and download failure are explicit.

Text-to-speech#

When voice response is enabled and a TTS provider is configured, response text is bounded and normalized for speech, synthesized, delivered as Telegram voice media, and linked to the same response/audit. Long evidence details remain in text when speech trimming would omit meaning. Missing/failing TTS degrades to text with honest state rather than dropping the reply.

Voice preference is member-specific and private. Voice synthesis does not impersonate a person or obscure the Lilith/system disclosure.

Verification matrix#

  • Room read success, unavailable, forbidden, missing location/time zone, and stale/partial responses.
  • Personal-room commands blocked in groups; passage/ask shared behavior.
  • Save/preference/timezone/stop/resume/unlink applied, invalid, duplicate, denied, unavailable, and failed outcomes.
  • Reminder parsing across relative/absolute, locale/zone, DST, ambiguous, unsupported, maximum, and past times.
  • Scheduler fencing, due selection, quiet hours, opt-in/stop, transient retry, permanent/blocked failure, duplicate cycle, callback actions, and backlog.
  • STT download/type/size/provider/transcript/safety paths and TTS configured/ absent/failure/length paths.
  • Webhook-to-Bot-API browser/integration evidence that a real effect/delivery is reached, not only response copy.

Primary modules are rooms.ts, room-commands.ts, reminders.ts, reminder-requests.ts, effects.ts, stt-provider.ts, and tts-provider.ts under libs/oshun/messaging-channels/src/telegram, with BFF adapters under apps/oshun/bff/src/telegram.