---
title: Mission Control — templates, calendars, meetings and notifications (part 4)
---

# Mission Control — templates, calendars, meetings and notifications (part 4)

## What it is

This is part 4 of the [Mission Control](mission-control.md) page. It covers everything a board joins on to: other features inside Omniscio, and systems outside it.

## Where to find it

Mostly inside **Mission Control** (templates, the calendar overlay, notifications), with the outbound pieces configured in the integration or settings surface each one belongs to.

## How it behaves

### Calendar Overlay (Phase 5I)

PM due dates and sprint timelines appear as a visual overlay on the Calendar
alongside Google Calendar events. Items with `date` or `timeline` column
values render as CalendarEvents, color-coded by board with overdue items
highlighted in `status-error` red.

**How to use it:** enable **Settings -> Mission Control -> "PM due dates in Calendar"**
(on by default when Mission Control is enabled). Due dates appear as single-day or
timed events; sprint timelines appear as spanning bars across the calendar.
Click any PM event to see the board name, date info, overdue warning, and an
**"Open in PM"** button that navigates to the Mission Control panel.

**How it works (internals):** the `CALENDAR_LIST_PM_EVENTS` IPC handler queries
the pm_* SQLite mirror tables (joining pm_column_values with pm_items,
pm_columns, pm_boards, pm_groups), filters for `date` and `timeline` column
types, then transforms matching rows into CalendarEvent objects with PM
metadata fields (`source: 'pm'`, `pmBoardId`, `pmBoardColor`, `pmOverdue`,
`pmType`). The calendar store fetches PM events in parallel with Google Calendar
via `Promise.all` and listens to `pm:sync-updated` for live updates. The
`resolveEventColor()` dispatcher routes PM events to `getPmEventColor` (board
color or overdue red) while Google events use the existing cascade.

- **Contract:** `pm-calendar-overlay-contract.md`
- **Key files:** `src/main/services/pm/calendar/pm-calendar-queries.ts` (SQLite query), `src/main/services/pm/calendar/pm-calendar-service.ts` (transform), `src/main/ipc/calendar-handlers.ts` (handler), `src/renderer/src/features/calendar/calendar-colors.ts` (resolveEventColor)

### Session Linking

Sessions can be linked to PM items bidirectionally. A linked session shows a
**PM item chip** in the session header (accent-colored, displays the item name).
Clicking the chip navigates to the Mission Control board; right-clicking unlinks.

**Linking paths:**

- At session creation: pass `pmItemId` to `createSessionWithPrompt` (the `sessions.pm_item_id` FK is set in the INSERT)
- After creation: the `PM_SESSION_SET_LINK` IPC channel sets or clears the link
- From a PM item: `POST /pm/items/:id/start-session` CLI route spawns a new session pre-linked to the item, with PM context injected via `pmSessionContextProvider`

**Status sync:** `registerPmAgentLink()` listens to `sessionEvents.on('statusChanged')`.
When a linked session changes status, it maps to a closed vocabulary
(`idle` / `running` / `needs_you` / `finished` / `error`) and emits a
`PM_SESSION_LINK_CHANGED` push event. The chip subscribes via `usePushListener`
(300ms debounce) for live updates.

**Data model:** the FK is `sessions.pm_item_id` (nullable). A companion
`pm_item_links` row (entity_type = 'session') keeps the link browsable from
the item side. Both are written atomically in a SQLite transaction.

- **Contract:** `pm-session-link-contract.md`
- **Key files:** `src/main/services/pm/pm-agent-link.ts` (core service), `src/main/ipc/pm-session-link-handlers.ts` (IPC), `src/renderer/src/features/sessions/PmItemChip.tsx` (UI chip), `src/main/services/cli/cli-server-pm-routes.ts` (CLI route)

### Time Tracker Bridge (hub-spoke #3)

The item card's **Time tab** lets users start/stop timers and view logged time against any PM item — directly from the board, without switching to the Time Tracker panel. monday.com paywalls this behind Pro/Enterprise ($16–26/seat/mo); here it is free.

Starting a timer creates a `time_entries` row linked via `pm_item_id` (+ denormalized `pm_item_name` for display). The existing single-running invariant auto-stops any prior timer. The Time tab shows a timer control (Start/Stop with live elapsed), an entries list (newest-first, up to 100), and a summary strip (total time + billable amount using derive-once money). Entries also appear on the Time Tracker Today screen with a PM item name chip.

The bridge uses 5 methods on `window.__AMC_MISSION_CONTROL_SESSION__` (installed by `MissionControlPanel.tsx`): `startTimerForItem`, `stopTimer`, `getRunningTimer`, `getTimeForItem`, `getEntriesForItem`. Two new read-only IPC channels (`time-tracker:pm-entries`, `time-tracker:pm-total`) are web-access-blocked (desktop-only).

- **Contract:** `pm-time-tracker-bridge-contract.md`
- **Key files:** `src/plugins/mission-control/web/features/board/TimeTab.tsx` (UI), `src/plugins/mission-control/web/lib/session-bridge.ts` (bridge exports), `src/main/db/queries-time-tracker/index.ts` (queries), `src/main/ipc/time-tracker-handlers.ts` (IPC handlers)

### Meeting Bridge

Bridges PM boards and Meetings so action items flow from a meeting into board items and linked items are visible from both sides. Gated on `missionControlEnabled` AND `meetingsEnabled`.

**Flow 1 — Push action items to a board.** The **⋯ menu** on a finished meeting note has a **Send to board** item (shown when Mission Control is enabled AND the meeting has unchecked action items). It opens a `SendActionItemsModal` (board picker → group picker → preview of unchecked items). Sending creates one board item per unchecked action item on the chosen board/group via the Mission Control backend REST API, links each via `pm_item_links` (entity_type = 'meeting'), and triggers a board sync. Partial failures are tolerated — the result reports `{ created, failed, itemIds }`.

**Flow 2 — Bidirectional linking.** The finished note page shows a **Linked board items** section (`MeetingLinkedItems`) beneath the notes: chips for each linked PM item (navigates to Mission Control on click, X to unlink on hover), plus a toggle-open search bar that queries `PM_SUGGEST_ITEMS` with 250ms debounce and filters out already-linked items. From the PM item side, `GET /pm/items/:id/meetings` returns meetings linked to that item.

**CLI routes** (5 new routes under `/pm/meetings/`): `POST /pm/meetings/push-action-items`, `POST /pm/meetings/:meetingId/links`, `DELETE /pm/meetings/:meetingId/links/:pmItemId`, `GET /pm/items/:id/meetings`, `GET /pm/meetings/:id/items`. All feature-gated on both `missionControlEnabled` and `meetingsEnabled`.

**IPC:** 8 channels in `pm-meeting-bridge.ts` — push, list-boards, board-groups, link-set, link-remove, list-for-item, list-for-meeting, link-changed (push event). All blocked from mobile/web WS bridge.

- **Key files:** `src/main/services/pm/pm-meeting-bridge.ts` (service), `src/main/ipc/pm-meeting-bridge-handlers.ts` (IPC), `src/main/services/cli/cli-server-pm-meeting-routes.ts` (CLI), `src/renderer/src/features/meetings/MeetingLinkedItems.tsx` (linked items UI), `src/renderer/src/features/meetings/SendActionItemsModal.tsx` (push modal)

### Search & Knowledge Integration

PM items are discoverable through Omniscio's **global search** (Ctrl+K) alongside
sessions, SMS, Slack, and other channels. Search uses two stages: **FTS**
(LIKE on `pm_items.name`, enriched with status/assignee/due-date column values
for the snippet) and **semantic** (cosine similarity over 384-dim embeddings in
`pm_item_embeddings`). Results render with a KanbanSquare icon and navigate to
the Mission Control virtual project on click.

**Board-scoped and cross-board search:** `searchItems(db, query, filters)` in
`pm-queries.ts` accepts `boardId`, `assignee`, and `status` filters. The CLI
exposes these via `GET /pm/search?q=&boardId=&assignee=&status=`.

**Session-PM dedup:** when a session is linked to a PM item via `pm_item_id`,
the standalone PM result is removed from global search results — the session
result represents both.

**Embeddings:** the `pm_item_embeddings` table stores 384-dim float32 vectors
(1536-byte BLOBs) for each PM item, built from item name + board name + column
values. Embeddings are auto-refreshed after each board sync (500ms debounce per
item). Backfill runs in batches of 50. The embedding model runs in a
`utilityProcess` child (per the embedding-worker-offload contract).

**"Use as context":** the Mission Control Cloud item drawer has a clipboard button that
copies the full item context (fields, subitems, updates) for pasting into a
session. It NEVER spawns a session (cost-safety).

**PM_SUGGEST_ITEMS IPC:** takes `{ query, boardId?, limit? }` and returns
semantically matching PM items for proactive suggestions.

- **Contract:** `pm-search-integration-contract.md`
- **Key files:** `src/main/db/queries-pm-embeddings.ts` (CRUD), `src/main/services/pm/pm-embedding-service.ts` (lifecycle), `src/renderer/src/features/monday-cloud/pm-item-context.ts` (context builder), `src/renderer/src/features/monday-cloud/MondayCloudItemDrawer.tsx` (UI button)

### Voice actions (Batch 3)

Five **voice commands** let you manage PM items hands-free via the wake word or Alt+V:

| Phrase examples                                                       | Action                                | IPC channel              |
| --------------------------------------------------------------------- | ------------------------------------- | ------------------------ |
| "create a task called deploy API" / "add an item named review PR"     | Creates item on first board           | `pm:voice-create-item`   |
| "move deploy API to done" / "put review PR in backlog"                | Moves item to a named group           | `pm:voice-move-item`     |
| "mark deploy API as stuck" / "set review PR to working on it"         | Sets a status column value            | `pm:voice-status-update` |
| "read deploy API" / "what is review PR" / "show me the homepage task" | Reads item name + column values       | `pm:voice-read-item`     |
| "show all items" / "list my tasks" / "get the board"                  | Lists up to 20 items from first board | `pm:voice-list-items`    |

The regex engine (`voice-intent-regex-commands.ts`) pattern-matches the transcript; the IPC handlers (`pm-voice-handlers.ts`) resolve items by fuzzy name match against the local SQLite mirror and proxy writes to the Mission Control backend via `pmAuthedFetch`. The renderer dispatch (`voice-input-deps.ts`) wires the five commands into the existing voice action registry.

**Feature gating:** works whenever `missionControlEnabled` is on and a board has been synced locally.

- **Key files:** `src/main/ipc/pm-voice-handlers.ts` (IPC handlers), `src/main/services/voice/voice-intent-regex-commands.ts` (regex patterns), `src/renderer/src/components/ui/voice-input-deps.ts` (dispatch), `tests/unit/services/pm-voice-actions.test.ts`

### Semantic search / embedding pipeline (Batch 3)

An **on-device embedding pipeline** indexes PM item text (name + column values) using the shared ONNX embedding model, enabling **natural-language search** across all boards without API calls.

**How it works:**

1. Items are embedded on first sync via a **backfill** (batches of 50, respects model readiness).
2. On subsequent syncs, changed items are **re-embedded** (debounced 2s) automatically.
3. Search queries are embedded at query time and scored via **cosine similarity** against the stored vectors (threshold 0.5, top-K results).

**Access points:**

- **IPC:** `pm:semantic-search` — the renderer or voice can invoke it directly.
- **CLI:** `GET /pm/search/semantic?q=...&limit=N&board_id=...` — agents use this for natural-language item discovery.

**Storage:** `pm_item_embeddings` table (item_id, board_id, embedding BLOB as Float32Array, source_text). Reuses the shared `embed()` / `initEmbeddingModel()` from the embedding worker host. Deleted items have their embeddings removed automatically.

- **Key files:** `src/main/services/pm/pm-embedding-service.ts` (pipeline + search), `src/main/db/queries-pm-embeddings.ts` (CRUD), `src/main/db/migrations/20260718180128-add-pm-item-embeddings-for-semantic-search.ts`

### Outbound webhooks (Batch 3)

Register **webhook endpoints** that receive signed `POST` payloads when board events fire (the same `BoardEvent` objects the automation engine uses).

**CLI routes** (bearer + rate-limited):

| Route                       | Action                                                                                                 |
| --------------------------- | ------------------------------------------------------------------------------------------------------ |
| `POST /pm/webhooks`         | Register: `{ boardId, callbackUrl, events?, secret }` → returns `{ id, boardId, callbackUrl, events }` |
| `GET /pm/webhooks?boardId=` | List active webhooks for a board (or all)                                                              |
| `DELETE /pm/webhooks/:id`   | Soft-delete a webhook                                                                                  |

**Delivery model:**

- Payloads are JSON-signed with HMAC-SHA256 (`X-AMC-Signature` header, `X-AMC-Event: pm.board.event`).
- Up to 3 retries with exponential backoff (1s / 4s / 16s).
- After 3 consecutive failures a webhook is **auto-disabled** and an inbox alert surfaces via `inbox-pm:updated`.
- On successful delivery the failure counter resets.
- Event filtering: if `events` is set at registration, only matching event types are delivered; empty = all events.

**Storage:** `pm_webhooks` table (id, board_id, callback_url, event_filter JSON, secret, is_active, failure_count, last_failure_at, soft-delete).

- **Key files:** `src/main/services/pm/webhooks/pm-webhook-service.ts` (delivery engine), `src/main/services/pm/pm-queries.ts` (webhook CRUD), `src/main/services/cli/cli-server-pm-routes.ts` (CLI routes), `src/main/db/migrations/20260718180136-add-pm-webhooks-for-outbound-event-delivery.ts`

### Project Templates (Phase 5E)

Save a board's full structure as a reusable template and deploy it into new
boards. Right-click a board in the left nav → "Save as template" opens a
dialog (name, description, shared/private visibility, include-items toggle).
Templates are stored on the backend and browsable via a **Template Category
Picker** (opened from the "T" button in the left nav header). The picker
shows a two-level modal: first a grid of project category tiles (Boards,
Dashboards, Documents, Spreadsheets, Forms) plus a "My Saved Templates"
tile, then clicking a category drills into its templates. Documents,
Spreadsheets, and Forms each have built-in templates that deploy as their
respective entity types (not boards) via `EntityTemplateDeployPreview`. A
back arrow returns to the category grid. Each template carries a
`projectCategory` field tying it to a category (defaults to `'boards'`).
Categories are defined in `src/shared/types/pm-template-categories.ts`.

**Deploy preview** shows the template's groups, columns, views, and
automations. Each automation has a toggle and a **cost badge** (`$`) on
actions that invoke AI or spawn sessions (detected by `isCostBearingAction`
checking the action array for `cli_session`, `auto_respond`, `summarize`,
`ai_classify`, `ai_extract`).
Users can disable cost-bearing automations before deployment.

**Template editor** lets owners update name, description, icon, visibility,
and the template's structure (rename/remove groups, columns, views,
automations). Changes autosave with an 800ms debounce.

**Portability**: column references inside automations are replaced
with stable `templateKey`s (`col_1`) on save and remapped back to
real IDs on deploy (direct dictionary lookup via a caller-supplied key→ID map).

- **Contract:** `pm-board-templates-contract.md`
- **Key files:** `src/shared/types/pm-template-categories.ts` (category definitions), `src/shared/pm-built-in-template-catalog.ts` (built-in templates for all entity types), `src/main/services/pm/templates/pm-template-portability.ts` (portability engine), `src/main/services/cli/cli-server-pm-template-routes.ts` (7 CLI routes), `src/plugins/mission-control/web/features/templates/` (category picker, deploy preview, entity deploy preview, save dialog, editor)

### Recipe templates (bundled patterns)

14 bundled recipe patterns under `resources/recipe-patterns/pm-*.pattern.json` combine the PM CLI routes with the Recipe system for daily workflow automation. All use `same-session` execution mode with a single step that reads a bearer token from `~/.amc/cli-token` and calls `GET /pm/boards`, `GET /pm/boards/:id/items`, etc. to produce markdown reports.

**Daily workflows:** `pm-daily-standup`, `pm-whats-due-today` (cross-board), `pm-my-work-summary` (cross-board), `pm-end-of-day-report`. **Sprint/planning:** `pm-sprint-retro`, `pm-sprint-planning-prep`, `pm-workload-balance`. **Task management:** `pm-task-decomposition` (the only write pattern — creates subtasks), `pm-blocked-items-report`, `pm-overdue-items-digest`. **AI analysis:** `pm-board-health-check`, `pm-priority-recommendation`, `pm-status-update-drafter`, `pm-meeting-agenda`.

Pattern details: `recipe-authoring-guide-patterns.md`.

### Data Import — tooling removed

A one-time Python migration tool formerly at `monday-exports/` imported Monday.com xlsx board exports into the Mission Control backend via REST (discover → `column-map.json` → import). It successfully imported 29 boards (~1,900 items) across all 18 column types before removal.

**The `monday-exports/` tooling and its committed data were REMOVED from the repo for privacy** — `column-map.json` was a real production Monday.com workspace export (59 real boards + real collaborators' first names committed as swimlane labels). Do not re-add a real workspace export to the repo; use synthetic data if the migration is ever re-run. Design spec (retained for reference): `docs/superpowers/specs/mission-control-data-import-design.md`.

### Data import/export (Phase 5G)

Two CLI routes let agent sessions move data between files and Mission Control boards:

- **Export** (`GET /pm/data/export/:boardId?format=csv|xlsx|json|txt`) — fetches the board from the Mission Control backend, transforms to the requested format, writes a temp file, returns the path. Includes CSV formula injection defense.
- **Import** (`POST /pm/data/import { filePath, newBoardName?, boardId?, format? }`) — reads a local file (CSV/XLSX/JSON/TXT), auto-detects format from extension, infers column types (14 types: status, priority, date, numbers, email, phone, link, checkbox, dropdown, rating, long-text, text, plus header-name heuristics), detects groups from a "Group"/"Section" column, and creates boards/groups/columns/items on the Mission Control backend. Caps: 5000 rows, 50MB file size, 20K chars per cell.

Works independently of the Phase 5A local mirror — calls the Mission Control backend REST API directly via `pm-auth`.

- **Contract:** `pm-data-transfer-contract.md`
- **Key files:** `src/main/services/pm/data-transfer/` (export, import, column inference, xlsx bridge, types), `src/main/services/cli/cli-server-pm-data-transfer-routes.ts`

### Notification Intelligence (G4)

An additive notification layer (shipped, active for all users) that routes PM board changes to inbox alerts with session-scoped batching, per-board mute/promote preferences, and due-date alerting. Runs alongside the existing `pm-inbox-event-detector`; uses its own `pm_events` and `pm_notification_preferences` tables.

**Session-scoped batching:** board changes are written to `pm_events` immediately (write-through, never in-memory). When a session reaches a terminal status (ended/error/archived/paused), all unnotified events for that session are grouped by board, filtered (mute, never-notify-actor), and surfaced as one inbox alert per board. Two listeners cover all engine types (Claude sessions via `sessionEvents`, external engines via `SESSION_STATUS_CHANGED` push).

**Routing rules:** (1) muted boards mark events notified without alerting; (2) the actor who caused the event (`local-user`) is never notified about their own action; (3) promoted boards upgrade digest events to inbox severity.

**Due-date notifier:** a 15-minute timer scans all boards for overdue and due-approaching items (within 24h), deduplicates within a 24h window, and raises individual inbox alerts via `raiseAgentAlert()`. Overdue takes priority if both apply.

**Per-board preferences UI:** `PmNotificationPrefsPanel` (React) with board notification mode (normal/muted/promoted), email mode (off/instant/digest), and digest frequency (daily/weekly). IPC channels: `PM_NOTIFICATION_PREFS_GET/SET/LIST`, `PM_EVENTS_RECENT`, `PM_NOTIFICATIONS_UPDATED` push.

**CLI routes:** `GET /pm/notification-preferences`, `PUT /pm/notification-preferences`, `GET /pm/events`.

- **Contract:** `pm-notification-intelligence-contract.md`
- **Key files:** `src/main/services/pm/pm-event-service.ts` (core), `src/main/services/pm/date-scanning/pm-due-date-notifier.ts`, `src/main/db/queries-pm-events.ts`, `src/main/ipc/pm-notification-handlers.ts`, `src/renderer/src/features/pm-notifications/PmNotificationPrefsPanel.tsx`

### Inbox source (Phase 5D)

Phase 5D adds a **"board" inbox source** that surfaces Mission Control board events as
unified inbox rows. Six event types create rows: **assigned to you**,
**mentioned in an update**, **status changed on your item**,
**due date approaching** (1 day), **due date passed**, and
**automation fired**. Events are detected locally from the Phase 5A SQLite
mirror tables on each sync -- no Mission Control API polling beyond what the sync
service already does.

**How to use it:** enable **Settings → Features -> "Mission Control board events
in inbox"** (on by default when Mission Control is enabled). Events appear as inbox rows
with a status-coloured dot routed through the `status-*` tokens (so custom themes
recolour it): the **needs-you** attention colour for most events, and the
**error** colour for overdue items. Items are **grouped by board** (each board
gets its own collapsible section) and **sorted by priority** (overdue first, then
due-approaching, then assigned, then status-changed, mentioned, automation-fired).

Click a row to open a **rich detail card** showing the item title, board name,
event type, status chip (with before→after transition for status changes),
assignee name, and due date with urgency display (overdue in red, approaching
in amber). The card has five **inline actions**:

- **Mark Done** — transitions the item via the Mission Control API and dismisses the card
- **Snooze** — dismiss and re-surface later (tomorrow, next week, custom)
- **Reassign** — dropdown of board members, updates the people column via API
- **Change Date** — inline date picker, updates the date column via API
- **Open in Board** — navigates to the Mission Control board panel

**Per-board notification preferences:** configure each board to receive **all**
events (default), **assigned-only**, or **none** via `pmInboxBoardPreferences`.

**Quiet Hours:** suppress PM inbox notifications during a configured time window
(`pmInboxQuietHoursStart` / `pmInboxQuietHoursEnd`, e.g. 22:00–07:00). Events
still persist and the store still updates; only toasts and OS notifications are
suppressed. Overdue items always pierce quiet hours.

**Daily Digest:** PM events participate as a `pm-events` source in the daily
digest system. When digest mode is active (`pmInboxDigestMode`), individual
notifications are suppressed in favor of the combined daily summary. Overdue
items always pierce digest mode.

**How it works (internals):** the main-process `pm-inbox-event-detector`
subscribes to the `pm:sync-updated` push. On each sync it queries the pm_*
mirror tables, resolves the current user (cached from `GET /auth/me`), extracts
rich card fields (assignee, status, due date, column IDs for mutations), detects
which events are active, upserts them into `pm_inbox_events` (dedup on
`event_type + item_id`), soft-deletes cleared events, and emits
`inbox-pm:updated` if changed. The renderer's `pm-inbox-store`
(`createDerivedInboxStore`) listens for the push and projects events as
`integration: 'board'` items in the unified inbox with per-board projectIds
for smart grouping. Dismiss uses the universal far-future snooze pattern
(kind `'board'`). The detail pane routes through `BoardDetailPane` (wrapped
in `ApprovalPaneShell`).

## Related

- [Mission Control](mission-control.md) — the overview page this continues.
- [mc-templates.md](mc-templates.md) — the template picker and the deploy preview in full.
- [outbound-webhooks.md](outbound-webhooks.md) — pushing app events to your own server.

