---
title: Presentation Mode (recording-safe "show only what I pick")
---

# Presentation Mode (recording-safe "show only what I pick")

## What it is

**Presentation Mode** is a recording-safe screen for Omniscio: a single switch that hides everything private on your dashboard — your real products (projects) and their sessions, your account name/email/avatar, live cost and spend figures, and the leaky bits of header chrome — and reveals **only** the handful of items you explicitly pick, plus any session you personally start while it's on. It exists for the moment you screen-share, record a demo, or stream: flip it on and your client names, spend numbers, and identity stop showing on camera without you having to clean up your workspace first.

The core idea is an **allowlist**: while presenting, an item is hidden **unless** you have revealed it. That's the opposite of a blocklist (which would hide only what you remember to add), and it's the whole safety story — you can never accidentally leak a project you forgot about, because forgetting means it stays hidden.

Everything Presentation Mode does is **render-time only**. It never renames a project, never edits an account, never touches a message. It changes only what's drawn on screen, so the instant you turn it off, every real name, number, and identity snaps back exactly as it was. And because the on/off state is a saved setting, the mode **survives an app restart** — if you were presenting when Omniscio closed, it comes back up still presenting (with your notifications still held), so a crash mid-stream can't un-hide your data.

## Where to find it

There are four ways to reach it, and they all drive the same saved setting so nothing ever drifts out of sync:

1. **The Presentation Mode toolbar item.** "Presentation Mode" lives in the header's **"•••" overflow menu** (under _Sessions & workflow_) and can be pinned to the header like any other toolbar tool. Clicking it opens the **backstage staging panel** (below) — it does _not_ toggle the mode directly. When pinned it lights up accent-colored and shows a "Live" badge while the mode is on, so the on-air state stays glanceable; either way, the accent on-air ring around the screen always signals you're presenting.
2. **The backstage Staging panel.** The entry point where you decide what to show. Open it from the Presentation Mode toolbar item (or the command palette), pick your reveals, choose a hide style, optionally set a demo identity and content-scrub, then hit **Go live**.
3. **The command palette.** Two actions: **"Toggle Presentation Mode"** (flips it straight on/off) and **"Presentation Mode: open staging…"** (opens backstage). Search for `presentation`, `present`, `demo`, `screen share`, `blur`, or `redact`.
4. **The panic control — no default key.** The emergency "hide everything now" action (see below).

## How it behaves

### The backstage staging panel

The staging panel (`PresentationStagingPanel`) is a modal "backstage" — the one place you configure a presentation before going live. It contains:

- **Presentation mode** master toggle — turn the whole thing on/off.
- **Hide style** — a three-way tab (Remove / Blur / Placeholder) choosing how a _non-revealed_ item looks (see below).
- **Demo name (shown instead of your account)** — an optional stand-in name and avatar image shown in place of your real identity. Leave it blank and the account area shows a neutral "Presenter" placeholder instead of your name/email.
- **Also blur message content** — the optional content-scrub toggle (below).
- **Hide the account widget** — an optional toggle that removes the header account switcher / balancer pill _entirely_ while presenting (see _Account identity_ below), rather than just disguising the name on it. Off by default.
- **What to show on camera** — your project→session list. Each hub (project) row carries the project's **icon** and a reveal toggle, and **folds** to hide its sessions — a folded hub shows its session count, and the list **opens folded to just the hubs** so you land on a tidy overview instead of a long wall of sessions. A live summary tells you how many items will be visible ("2 items will be visible; everything else hidden"). Beside the heading sits a **Select all / Deselect all** button that flips the whole list at once — hubs _and_ the sessions folded underneath them — so you don't have to click through a workspace with hundreds of sessions one row at a time; the label reads "Deselect all" once everything is already revealed. It covers your real projects only, since the Integrations section below has its own master switch. Under the Placeholder hide style, each hidden row also gets an inline label field so you can name it whatever you want ("Client Project", "Demo Session").
- **Integrations** — a separate section listing your built-in Omniscio panels (Mail, Calendar, Tasks, Mind Map, KMS…), each with its icon. Unlike your real projects, these are **shown on camera by default** — so a live demo of Omniscio isn't an empty screen — behind a master "Show my integrations on camera" switch plus a per-integration on/off. Showing an integration reveals its **panel** in the sidebar; it never un-hides that integration's private **Inbox** rows (see the Inbox surface below).
- **Footer** — **Go live** (turns it on and closes) and, when already live, **Exit presentation**.

### The three hide styles

A **revealed** item always shows its real name as-is. For everything _not_ revealed, the hide style decides what the viewer sees:

- **Remove** (the default, and the safest) — the item is **filtered out of the list entirely**. It simply isn't there. Nothing to read, nothing to leak, and the cleanest look. This is the default precisely because a filtered-out row can't leak anything on any surface.
- **Blur** — the item **stays in place but its name is visually blurred** (a CSS blur, with text selection disabled so the real text can't be dragged out). Use this when you want the audience to see that _something_ is there without reading it.
- **Placeholder** — the item's name is **replaced with a neutral label**: either an auto-generated "Project 1" / "Session 2" (numbered by position) or a custom label you typed in the staging panel.

Because Remove drops the whole row, a few surfaces that can't drop a row — like the header of a session you have open — treat Remove as Blur instead, so the name is still masked rather than mysteriously blank.

### The reveal model — what shows while presenting

Three things are visible while presenting:

1. **Anything you explicitly reveal** in the staging panel (a project or a session). Revealing a project shows the project; revealing a session shows that session. You can also toggle reveals live from the staging panel mid-presentation.
2. **Any session you personally start while the mode is on.** If you launch a session yourself — from the UI or from Quick Launch — it's your live demo work, so Omniscio auto-reveals it the moment it's created. This keys strictly on _who started it_: only genuine user-initiated foreground launches are auto-revealed. Every automation, recipe, cron, away-mode, background, or council-panelist spawn carries a different origin and so **stays hidden** — an agent kicking off a session in the background can never pop a private session onto your screen.
3. **Your integration panels, by default.** The built-in Omniscio panels (Mail, Calendar, Tasks, Mind Map, KMS…) show on camera by default so a product demo isn't empty — toggleable per integration in the staging panel's Integrations section. This reveals only their **sidebar presence** (a generic name like "Mail"), never their private **Inbox** rows: your real SMS contacts and email senders stay off-camera (the Inbox uses a separate reveal config that deliberately skips this — see the Inbox surface below).

### What's hidden (the leak surfaces covered)

Presentation Mode was built against a "what could leak on camera?" checklist. Each surface below is neutralized while presenting and restored the instant it's off:

- **The sidebar (projects + sessions).** Non-revealed products and sessions are filtered/disguised per the hide style. This is enforced at the sidebar visibility chokepoints — the desktop projects rail + agent-driven group, the desktop main session list (the per-project "Needs You / Live / Paused / Snoozed / Archived" panel), the mobile session list, and the mobile PROJECTS list — the same lists that already hide silent recipe sessions. (The mobile projects list joined them on 2026-09-05; before that your phone showed real project names while the desktop rail hid them.)
- **A list that goes empty says so.** If Remove hides _every_ project, neither surface just sits there blank: it says Presentation Mode is on, confirms nothing has been deleted, and offers a one-click way out. A PARTIAL hide instead shows the ordinary "Showing X of Y" strip, whose reveal button turns off whichever thing is actually doing the hiding. The empty state deliberately shows no count and no names — that screen is on camera. (The collapsed icons-only rail is the exception: it is a narrow icon strip with nowhere to put a sentence, so expand it to see the message.) (The integration side-panels — SMS / KMS / Mind Map / AI-Coaching — are deliberately out of scope; close them or reveal what you need before presenting.)
- **The Inbox (rows + group headers).** Your home Inbox is disguised too, on both desktop and mobile: a non-revealed session's row, a project/client name in a group header, and the message content of non-session rows (SMS, GitHub, alerts, digests) are all hidden or masked per the hide style. It uses the _same_ allowlist as the rest of the mode — a session row shows only if that session is revealed; every other row and every header shows only if its project is revealed. Non-session sources live in behind-the-scenes "virtual" projects, and the Inbox keeps their rows **hidden while you present even when you show those integrations on camera**: the integration's panel appears in the sidebar, but its real Inbox rows (your SMS contacts, email senders) stay off-camera — the full-privacy Inbox. This works because the Inbox derives its disguise from a **base reveal config that deliberately skips the integration reveal** (`useInboxPresentationConfig`), while the sidebar rail uses the merged one — so under the default Remove style those rows simply drop off the Inbox while you present.
- **Account identity.** The header account chip and its popover rows never show your real name, email, or avatar — they render your demo identity, or a neutral "Presenter" placeholder, via a single shared mapper so the chip and rows can never disagree. If you'd rather the chip not show at all, flip **"Hide the account widget"** in the staging panel: while presenting, the whole account switcher / balancer pill (including the ⚖️ "N accounts in use" load-balancer count) is removed from the header entirely — handy when you don't want the audience to see that you're running a fleet of accounts. It's off by default, and the pill returns the instant you exit or turn the toggle off.
- **Cost / spend.** Live dollar figures in always-visible chrome keep their formatted text but are blurred in place (no layout shift), so a "$X spent today" figure can't be read off the screen.
- **The window title.** The OS title bar is forced to the neutral app name ("Omniscio") and _held_ there by a MutationObserver — so even if the app's own title updater fires with a real project/session name mid-recording, it's re-neutralized instantly.
- **Leaky header controls.** The notifications bell, recipes, feedback, and settings buttons are hidden (they can open panels full of private data). The account chip and the Presentation Mode entry point deliberately stay by default — Presentation Mode is a toolbar item in the "•••" menu (reachable to open backstage or exit while presenting), so the header still looks intact. (The account chip is the one exception you can opt to remove too, via **"Hide the account widget"** above.)
- **Toasts.** Every routine, non-severe toast (a "Settings saved" receipt, a spawn confirmation, a session name flashing by) is **suppressed** while presenting — nothing routine flashes on camera. Errors and warnings are the exception: they bypass the gate and still show, so a real failure is never hidden from you.
- **Notification badges.** The desktop app-icon / taskbar badge (the "3 sessions need you" count) is **clamped to 0** while presenting — a count baked onto the app icon on camera is a leak. The real counts stay untouched in the database and return the moment the mode is off.
- **OS / mobile push.** Web push delivery is **held** while presenting, so a paired phone doesn't fire a notification carrying a session name or message during a recording.
- **On-air indicator.** A slim accent ring hugs the viewport edge so _you_ always know you're presenting (it's pointer-events-none and never intercepts a click).

#### The optional content-scrub

By default Presentation Mode hides _chrome_ — the sidebar, identity, cost, title. If you also open a session and want its **conversation** hidden, flip **"Also blur message content"** in the staging panel. This blurs the message text, file paths, and names _inside_ an open session (a stronger blur than the name-blur, and non-interactive so nothing under it can be selected or copied on camera). It's off by default because most presentations want the chrome hidden but the actual demo conversation visible.

### Suppressing transient leaks (reuses Do Not Disturb)

The toast/badge/push suppression above isn't a new muting system — Presentation Mode **reuses Omniscio's existing Do Not Disturb** (the `silenceUntil` "Silence notifications" switch). When the mode turns on, it silences notifications exactly as the notifications bell does; when it turns off, it **restores your previous silence state** (so if you were already on Do-Not-Disturb, you stay that way). This is crash-safe: it stashes a restore marker in config so that if Omniscio crashes while presenting, the next boot un-silences you rather than leaving notifications muted forever. It also stacks cleanly with the screen-recorder's own auto-DND — both restore to the same prior value.

### Two optional switches: a quiet inbox and paused automatic sessions

Both are **off by default** and both only do anything while Presentation Mode is on, so turning the mode off restores everything with no second switch to remember. You'll find them in the staging panel beside "Also blur message content".

**Keep the inbox quiet** empties your inbox on camera — every source at once: sessions that need you, agent alerts, email, SMS, Telegram, GitHub PRs, Jira, approvals, digests and plugin rows. The inbox badge goes to zero with it. Nothing is deleted, archived, or delayed: every row still exists the whole time and comes straight back the moment you turn the switch (or the mode) off. That's why it hides at display time rather than blocking alerts at the source — a blocked alert would be gone for good, and some are one-shot. While it's on, every inbox screen says _why_ it's quiet and offers a one-click **Show my inbox**, so an empty inbox is never mistaken for "all clear".

**Pause automatic sessions** stops Omniscio starting new work while you present — schedules, automations, away-mode, the auto-lander, inbound email, bug intake, and sessions other agents ask for. Two things it deliberately does _not_ do:

- **It never blocks you.** Anything you launch yourself — "+ New Session", a quick-launch button — starts normally. Omniscio uses the same test here that it uses to decide a session you start should be visible on camera, so the two can never disagree.
- **It doesn't throw the work away.** Sessions requested through the command line or by another agent are genuinely queued and start the moment you exit. Scheduled jobs are skipped rather than failed, so they run on their next tick with no failure recorded against them.

**If Omniscio restarts while you're still presenting, your own interrupted sessions come back** — crash recovery, restart recovery and suspended-session recovery all run as normal. Only _new_ automatic work keeps waiting. That's deliberate: it means a crash mid-presentation can never leave your real work parked behind a switch you forgot to turn off.

### The panic control — "hide everything now"

**Hide everything now** is the emergency control. It's deliberately blunt: it **forces the mode on, clears every reveal, and switches integrations off**, so a single stray item — a project, a session, or an integration panel — can't stay on camera for another second. After a panic, you re-reveal what you want from the staging panel. It's a one-shot action (a held key won't re-fire it).

**It ships with no default key, on purpose.** It used to be bound to `Ctrl+Shift+X` — the same chord VS Code uses for its Extensions panel — and it fired even while you were typing in a text box. One mistyped chord silently switched the privacy screen on and cleared every reveal, which emptied a user's entire hub sidebar for a day with no notice explaining it. Now it's opt-in: give it a key in **Settings → Keyboard Shortcuts** if you want one, and it will never fire from a text field. The plain **Toggle presentation mode** shortcut likewise ships with no default key (it's an infrequent set-once action, discoverable via the header button and command palette).

_(If you ever pressed "Reset to defaults" in Keyboard Shortcuts, `Ctrl+Shift+X` is saved against your account as your own choice, so it still works for you — clear or change it there if you'd rather it didn't.)_

### Persistence

The mode and all its settings (hide style, revealed ids, demo identity, custom labels, content-scrub) live in the encrypted `config.json` as flat `presentation*` settings, so they **survive an app restart**. The mode only turns off on an explicit exit — never on its own. On boot, Omniscio reconciles the notification-silence side of it: still on → re-arm the silence; off → make sure notifications aren't stuck silenced from a crash-while-presenting. Because the settings are non-secret (a demo name and a list of ids — no credentials), they sync safely to a paired phone.

### Known limitation

Presentation hiding is scoped to the **on-camera sidebars** (the desktop projects rail + agent-driven group, the desktop main session list, the mobile session list, and — since 2026-08-11 — the unified **Inbox** rows + group headers) plus the identity / cost / title / toast / badge / push chrome above. A few things are still deliberately out of scope:

- **Inbox counters / badges** (the per-group "(N)" and the sidebar Inbox count). A number isn't a name, so it's handled by the badge freeze, not by filtering the Inbox — it stays narrower than the silent-session gate, which also governs those counts and the Ask-Omniscio `/state` snapshot.
- **Inbox detail / reading panes.** The Inbox _list_ (rows + headers) is disguised, but _opening_ an inbox item still shows its real content in the main panel — an SMS thread, an alert body, a recipe error — the same way an open session's messages are only hidden by the optional content-scrub. Close the item, or reveal what you need, before presenting. (Extending the disguise into the inbox detail panes is a planned follow-up.)
- **Integration sub-sidebars** (SMS / KMS / Mind Map / AI-Coaching session lists) — they render through the same session-list component but with presentation left off, so opening one on camera can still show real session names. Keep those closed while presenting, or reveal what you need first.

## For agents

### Where it lives in code

- **The pure visibility core** — [src/shared/presentation/presentation-visibility.ts](../../src/shared/presentation/presentation-visibility.ts). The single source of truth for "what does presentation mode do to this project/session" — `isPresentationHidden` (the sidebar filter predicate), `presentationVisibility` (the per-item show/filter/blur/placeholder decision), `isPresentationRevealed`, and `toPresentationConfig`. Pure and dependency-light so it's safe in main _or_ renderer, and short-circuits to "show" with zero work when the mode is off.
- **The flat settings schema** — [src/shared/types/settings/presentation-mode-settings.ts](../../src/shared/types/settings/presentation-mode-settings.ts). `presentationModeEnabled`, `presentationHideStyle` (default `'remove'`), `presentationRevealedProjectIds` / `presentationRevealedSessionIds`, `presentationDemoIdentity`, `presentationCustomLabels`, `presentationContentScrub`, `presentationHideAccountWidget` (default `false` — opt-in "hide the account widget while presenting"), `presentationRevealIntegrations` (default `true` — the master "show integration panels on camera" switch) and `presentationHiddenIntegrationIds` (the per-integration opt-out blocklist).
- **The renderer hook + actions** — [src/renderer/src/features/presentation/use-presentation-mode.ts](../../src/renderer/src/features/presentation/use-presentation-mode.ts) (`usePresentationConfig` — the rail/mobile/session config, unions the integration panels into the revealed set; `useInboxPresentationConfig` — the Inbox's config, the base reveals with NO integration union; `mergeIntegrationReveals` — the pure union helper; `setPresentationEnabled`, `revealPresentationItem`, `setPresentationRevealIntegrations`, `setIntegrationRevealed`, `panicHidePresentation`, …).
- **The chrome controller** — [src/renderer/src/features/presentation/PresentationChrome.tsx](../../src/renderer/src/features/presentation/PresentationChrome.tsx) (the `.amc-presenting` root class, the on-air ring, and the window-title neutralizer).
- **The backstage panel** — [src/renderer/src/features/presentation/PresentationStagingPanel.tsx](../../src/renderer/src/features/presentation/PresentationStagingPanel.tsx).
- **The toolbar entry point** — the `presentation` item in [src/renderer/src/features/toolbar/toolbar-catalog.ts](../../src/renderer/src/features/toolbar/toolbar-catalog.ts) (opens the staging panel via the `presentation` case in [useToolbarActions.ts](../../src/renderer/src/app/useToolbarActions.ts); the pinned render reuses [PresentationToggleButton.tsx](../../src/renderer/src/features/presentation/PresentationToggleButton.tsx)).
- **The main session-list disguise** — [src/renderer/src/features/session-host/SessionSectionList.tsx](../../src/renderer/src/features/session-host/SessionSectionList.tsx) (the `applyPresentation` gate: filters 'remove' + threads the config) plus the per-row blur/placeholder computed centrally in [SessionRow.tsx](../../src/renderer/src/features/session-host/SessionRow.tsx).
- **The Inbox disguise** — the shared helper `presentInbox` in [src/renderer/src/features/dashboard/inbox-presentation.ts](../../src/renderer/src/features/dashboard/inbox-presentation.ts) (session row → its own id, every other row + group header → its project; filters 'remove' rows + drops empty groups; returns the same groups reference when the mode is off). Consumed by the desktop [SidebarInboxContent.tsx](../../src/renderer/src/features/dashboard/SidebarInboxContent.tsx) and the mobile [MobileInboxGroups.tsx](../../src/renderer/src/features/dashboard/MobileInboxGroups.tsx) via [MobileSessionsList.tsx](../../src/renderer/src/features/dashboard/MobileSessionsList.tsx); the per-row blur/placeholder is applied by [UnifiedInboxRow.tsx](../../src/renderer/src/features/dashboard/UnifiedInboxRow.tsx).
- **The identity disguise** — [src/renderer/src/features/presentation/presentation-identity.ts](../../src/renderer/src/features/presentation/presentation-identity.ts).
- **The cost mask** — [src/renderer/src/components/ui/account/PresentationCost.tsx](../../src/renderer/src/components/ui/account/PresentationCost.tsx).
- **The CSS (hide styles + chrome hiding + scrub)** — [src/renderer/src/features/presentation/presentation-mode.css](../../src/renderer/src/features/presentation/presentation-mode.css).
- **Toast suppression** — the presentation gate in [src/renderer/src/stores/toast-store.ts](../../src/renderer/src/stores/toast-store.ts).
- **Badge clamp** — the presentation check in [src/main/services/notification-service.ts](../../src/main/services/notification-service.ts).
- **Push hold** — the presentation hold in [src/main/services/web/web-push-service.ts](../../src/main/services/web/web-push-service.ts).
- **DND reuse (arm/disarm/boot-reconcile)** — [src/main/services/presentation/presentation-dnd.ts](../../src/main/services/presentation/presentation-dnd.ts) + [presentation-dnd-wiring.ts](../../src/main/services/presentation/presentation-dnd-wiring.ts), driven by the `presentationModeEnabled` transition in [settings-apply.ts](../../src/main/services/settings-apply.ts).
- **Reveal-on-create** — the auto-reveal block (gated on session `source` of `'ui'` / `'quick-launch'`) in [src/main/services/session/session-create.ts](../../src/main/services/session/session-create.ts).
- **The keybindings** — [src/shared/keybindings/presentation-mode.keybindings.ts](../../src/shared/keybindings/presentation-mode.keybindings.ts).
- **The command-palette actions** — the `toggle-presentation-mode` / `open-presentation-staging` entries in [src/shared/app-commands.ts](../../src/shared/app-commands.ts).
- **The coverage lint** (privacy-critical) — [tests/unit/lint/presentation-filter-coverage.test.ts](../../tests/unit/lint/presentation-filter-coverage.test.ts) fails the build if a sidebar visibility chokepoint forgets the presentation filter, AND (for the Inbox) if either the `presentInbox` helper stops carrying the filter or an inbox renderer stops calling the helper.

The invariants are locked in the [presentation-mode contract](../../.claude/memory/contracts/presentation-mode-contract.md).

## Related

[notifications-and-silence.md](notifications-and-silence.md) covers the "Silence notifications" (Do Not Disturb) switch Presentation Mode reuses to hold toasts, badges, and push. [focus-mode.md](focus-mode.md) is a different "quiet the noise" feature — it batches alerts, where Presentation Mode is about _hiding data on camera_. [screen-recorder.md](screen-recorder.md) covers Omniscio's built-in recorder, which has its own auto-DND that stacks cleanly with Presentation Mode. [silent-recipe-sessions.md](silent-recipe-sessions.md) is the sibling render-time hide (`isSilentlyHidden`) whose sidebar chokepoints Presentation Mode piggybacks on. And [keyboard-shortcuts.md](keyboard-shortcuts.md) is where you give the panic control a key, or add one to the plain toggle, in Settings → Keyboard Shortcuts.
