Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

Scheduled Messages (compose-to-self, fire-into-inbox)

Scheduled Messages lets you write a rich-markdown note to yourself, schedule it to arrive once or on a recurring cadence, and have Omniscio drop it silently into your unified inbox when it fires — a letter to your future self with no approvals and nothing to respond to.

What it is

Scheduled Messages lets you write a rich-markdown note to yourself — a subject line plus a Markdown body, with optional inline images — schedule it to arrive once at a future time or on a recurring cadence, and have Omniscio silently drop it into your unified inbox when it fires. Think "a letter to your future self": a reminder, a checklist, a standing weekly prompt, a bit of context you want resurfaced next Monday morning. When the message fires it lands as a persistent inbox item that survives an app restart; you read it and archive it (and Ctrl+Z brings it right back if you archive one by mistake), and that's the whole lifecycle — there are no approvals and nothing to respond to.

Scheduled Messages is on by default. The capability (flag scheduledMessagesEnabled) ships enabled for everyone — existing installs are flipped on once, respecting a later opt-out — so the background scanner runs and a fired note lands in your unified inbox whether or not you ever open the feature's UI. What is hidden by default is the standalone "Scheduled Messages" sidebar row and its compose surface, gated by a separate UI-only flag (scheduledMessagesSidebarEnabled, default off), exactly the way Alerts works. Reveal the row at Settings → Features → "Show Scheduled Messages in sidebar" (or from the discovery nudge, which flips the same toggle); hiding it never affects the scanner or the inbox delivery. Turning the capability itself off — the opt-out on the same screen — silences the scanner; messages and deliveries already in the inbox are preserved.

Not the same as "Send Later". Send Later (a.k.a. scheduled responses) defers a reply you are sending into a live Claude session — it queues your typed message and dispatches it to the agent at a chosen time. Scheduled Messages never touches a session and never talks to an agent: it delivers a note to you, into your inbox, full stop. If you want to nudge a running agent later, use Send Later; if you want to remind yourself of something later, use Scheduled Messages.

A scheduled message has two states: Active (enabled — the scanner fires it on its schedule and, for recurring messages, advances to the next fire time) and Paused (disabled — the schedule is suspended but the message is kept so you can resume it). Recurrence reuses Omniscio's shared recurrence vocabulary: once, daily, weekdays, weekends, or specific days of the week, each paired with a local time of day.

Where to find it

How to use it

  1. Reveal it in the sidebar. The feature is already on, but its sidebar row is hidden by default. Turn on Settings → Features → "Show Scheduled Messages in sidebar" to surface the "Scheduled Messages" row in the Omniscio group. (You can also jump straight in from the discovery nudge, which flips the same toggle.)
  2. Open the Scheduled Messages virtual project in the sidebar. The first launch shows an empty state with + New message.
  3. Compose a message. Give it a subject (up to 200 characters) and a Markdown body (rendered live in a preview pane via ProseBlock). Use Add image to embed an inline image — it is copied into the message's own attachment storage and referenced by an attachment:// URL, so the original file can move or be deleted later without breaking the message.
  4. Set the schedule. Pick a recurrence — Once, Daily, Weekdays, Weekends, or Custom days (choose which days of the week) — and a time of day (defaults to 08:00 local). Or, faster: type the timing in plain English into the Schedule (plain English) box above those controls — "every weekday at 8pm", "tomorrow at 2:30pm", "weekends at 9am" — and Omniscio fills the Time, Recurrence, and (for one-offs) Date for you, with a one-line preview of what it understood. The box only ever fills the schedule; your subject and body are never touched, and you can still adjust any field by hand. Save with the button or with Ctrl+Enter / Cmd+Enter.
  5. Receive it in your inbox. When the message fires, it appears in your unified inbox as a Scheduled Messages integration row. Clicking the row opens the delivery in the Scheduled message inbox viewer on the right: the subject as a heading, a "Delivered <timestamp>" line, and the Markdown body rendered as rich text. Archive it with the Archive button to clear it from the inbox — and if you archive one by mistake, press Ctrl+Z to bring it straight back (the archive is reversible).
  6. Act on it with one click. The card also carries a Start session button in its bottom bar (the same shared affordance drip and agent-alert cards have, keyboard shortcut N). Click it to spin up a new Claude session pre-filled with the reminder's subject and body, in the repo you pick — handy when the note is really a to-do. Starting a session leaves the reminder in your inbox (archive it yourself when you're done).
  7. Manage existing messages. The management pane (and the sidebar) split messages into Active and Paused sections with live search. Each row offers Pause / Resume and Delete (delete is confirmed via ConfirmDialog — it stops all future deliveries, but deliveries already in your inbox are kept).

How it behaves

Related docs

  • Integration registry contracts — the wiring assertions this feature's registry entry has to honor.
  • Drip — the queue-and-trickle inbox feeder this feature is modeled on (Drip is the richer, multi-item cousin).
  • Send Later — defers a reply into a live agent session; the distinct feature people most often confuse this with.

For agents

How it works

Data lives in two tables, added in schema migration v258 in src/main/db/incremental-migrations.ts:

  • scheduled_messages — one row per message: subject, body_md, the recurrence + days_of_week + fire_time_local schedule, attachment_scope_id (the folder its inline images live under), the computed next_fire_at, enabled, fire_count, and timestamps. Indexed on (enabled, is_deleted, next_fire_at) so the scanner's "what's due?" query is cheap.
  • scheduled_message_deliveries — one row per fired delivery, FK'd back to its message. Each delivery snapshots subject_snapshot + body_snapshot at fire time (so editing the message later never rewrites history) plus fired_at, read_at, and archived_at. Indexed on fired_at where is_deleted = 0 AND archived_at IS NULL — the unified inbox's "unarchived deliveries" query.

Soft-delete (is_deleted) applies to both tables. Query modules: src/main/db/queries-scheduled-messages.ts and src/main/db/queries-scheduled-message-deliveries.ts.

Shared types live in src/shared/scheduled-message-types.ts: ScheduledMessage, ScheduledMessageDelivery / ScheduledMessageInboxItem, the create/update input shapes, and the two push payloads (ScheduledMessageDeliveredPayload and ScheduledMessageChangedPayload, both carrying a messageId). Recurrence reuses the existing AlarmRecurrence union ('once' | 'daily' | 'weekdays' | 'weekends' | 'days-of-week') rather than inventing a parallel vocabulary.

The compose modal's plain-English schedule box reuses the same natural-language parser the Calendar and Alarm Quick Add features use — it calls the shared CALENDAR_PARSE_QUICK_ADD IPC (regex-first, with a Haiku fallback only on a regex miss), so there is no extra parsing code or AI cost specific to this feature. The pure adapter src/shared/scheduled-message-quick-add.ts maps the parser's interpretation into the four schedule fields, reusing the alarm mapper for the RRULE→legacy-enum collapse, and the box only ever fills the schedule (the parser's extracted title is discarded — the subject stays yours). Because a scheduled message can only repeat in the five AlarmRecurrence ways, a phrase the parser understands but the feature cannot store (e.g. "every 3 weeks" or "first Monday of the month") is degraded to a one-off on its first matching date, with a note in the preview saying the repeat could not be stored.

The background scanner is src/main/services/scheduled-message-scanner-service.ts, a 60-second periodic task. Each tick returns early when settings.scheduledMessagesEnabled is off, so the feature truly goes quiet when disabled. For each due message it runs a single transaction that inserts the snapshot delivery and advances next_fire_at (for a once message, it disables the message after firing). After the transaction commits it emits a SCHEDULED_MESSAGE_DELIVERED push and a SCHEDULED_MESSAGE_CHANGED push.

The ten IPC handlers live in src/main/ipc/scheduled-message-handlers.ts: message LIST / GET / CREATE / UPDATE / DELETE, inbox INBOX_LIST / INBOX_ARCHIVE / INBOX_UNARCHIVE / INBOX_MARK_READ, and SAVE_IMAGE (which enforces a 10 MB cap and returns an attachment://<scopeId>/<filename> URL). INBOX_UNARCHIVE is the inverse of archive that powers the Ctrl+Z undo — it clears archived_at so the delivery returns to the inbox feed. Create / update / delete emit SCHEDULED_MESSAGE_CHANGED; the idempotent inbox archive / unarchive / mark-read handlers deliberately do not push (mirroring Drip). On the renderer, src/renderer/src/stores/scheduled-message-store.ts holds the message list, the selected id, and the cross-message inbox slice, with optimistic create/update/delete + a debounced handlePushUpdate wired through src/renderer/src/hooks/useScheduledMessagePushEvents.ts. One intentional divergence from the Drip template: SCHEDULED_MESSAGE_UPDATE takes a flat wire payload ({ id, ...fields }), not Drip's nested { id, fields }, because the handler's .strict() Zod schema places id as a sibling of the field keys.

The integration is registered in src/shared/integration-registry.ts with kind: 'amc-builtin', virtualProjectPath: SCHEDULED_MESSAGES_PROJECT_ID (the __scheduled_messages__ sentinel), featureFlag: 'scheduledMessagesEnabled', settingsSearchId: 'scheduled-messages-enabled', inboxSourceIds: ['scheduled-message'], and approvalKinds: [] (one-way item — no approvals). Its two push channels are SCHEDULED_MESSAGE_DELIVERED and SCHEDULED_MESSAGE_CHANGED; only SCHEDULED_MESSAGE_DELIVERED is critical (Zod-validated on the emit side and able to wake mobile clients), because SCHEDULED_MESSAGE_CHANGED is a management-UI sync signal. The renderer UI wiring (sidebar + panel components, the CalendarClock icon) lives in src/renderer/src/integrations/ui-registry.ts. The integration-completeness contract test (tests/unit/lint/integration-completeness.test.ts) fails CI if any of these claims drifts from its backing wiring.

Related

drip.md is the queue-and-trickle inbox feeder this feature is modelled on, and send-later.md covers the distinct feature most often confused with it — deferring one of your replies into a live agent session rather than delivering a note to you.

Last verified 2026-09-28