---
title: Feature Discovery Nudges
---

# Feature Discovery Nudges

## What it is

A gentle, roughly-daily inbox card that pitches one Omniscio feature you have never used —
_"Here's a feature you're missing, and here's why it'd help."_ Selecting the card opens its
detail **in the main panel**: the feature's name, a short hand-written pitch, a clean
animation, and two buttons: **"Start using it"** turns the feature on (if it's off) and
takes you straight to it, while **"Maybe later"** dismisses the card for good — the same as
the X. Nudges rotate through the features you don't use, release
**at most one per ~24 hours**, **auto-stop** once you've seen them all, and each card is
dismissible and snoozeable like any other inbox row.

Some nudges open a full **landing page** instead of the short pitch card — see below.

It is **off by default — opt-in**: the registry entry `feature-discovery-nudge` carries
`status: 'in-development'`, so nobody sees a nudge until they turn on **Feature Discovery
Nudges** in Settings → Lab (which flips `featureDiscoveryNudgeEnabled`;
`AMC_SHOW_FEATURE_DISCOVERY_NUDGE=1` is the dev-only reveal). Once enabled, the built-in
bounds are the user controls: at most one card per ~24 hours, never the same card twice,
features you already use are skipped, every card is dismissible and snoozeable, and the
rotation auto-stops once every card has been seen.

## Where to find it

### Landing pages — the richer sell-and-teach detail

Catalog entries can ship a **landing page**: opening the card shows a hero tagline, a
**self-running animated demonstration** of the feature in a miniature Omniscio, two-to-four
benefit cards (why you'd want it), numbered "How to use it" steps with keyboard-shortcut
chips, and a tailored call-to-action. Entries without a landing page keep the classic
short pitch card. If your system has "reduce motion" turned on, the animation is replaced
by a calm three-panel storyboard that teaches the same thing with nothing moving.

**Snooze is the first landing page.** Its demonstration loops a noisy miniature inbox:
press `H` (or right-click → Snooze), type a time in plain English ("tomorrow 9am"), watch
the card glide away — and return exactly on time. Its call-to-action is **"Try it on this
card"**: instead of navigating anywhere, it opens the real snooze palette _on the nudge
card itself_. Pick a time and the card vanishes from your inbox, then comes back when you
said — the feature demonstrates itself on a zero-risk target. (Trying it does not dismiss
the nudge; the card's return completes the lesson, and you can dismiss it then.)

Under the hood the landing content lives in the same hand-authored catalog
([src/shared/feature-nudges/catalog.ts](/src/shared/feature-nudges/catalog.ts)); each
demo is a lazy-loaded component keyed by the entry
([FeatureNudgeLandingContent.tsx](/src/renderer/src/features/feature-nudge/FeatureNudgeLandingContent.tsx),
[SnoozeDemo.tsx](/src/renderer/src/features/feature-nudge/demos/SnoozeDemo.tsx)).

> **Fixed alongside this feature:** snoozing a feature-nudge card from the right-click
> menu (or `H`) used to be a silent no-op — the snooze was recorded under the wrong key,
> so the card never hid. Nudge cards now snooze like every other inbox row, and the
> detail pane closes itself once its card is snoozed.

### Inline on/off toggle nudges

Some nudges don't send you anywhere — they put a **live on/off switch right in the card**.
Instead of "Start using it", the card shows the feature's current state as a real toggle you
can flip either way, plus a **"Done"** button that just closes it (your choice is already
saved). The first one is the **desktop icon badge**: your app icon (Windows taskbar / macOS
dock) normally shows a little count of sessions that need you — this nudge lets you keep it
or turn it off without leaving the card. The same switch also lives in Settings →
Notifications ("App icon attention count"), and flipping it in either place updates the badge
immediately. Under the hood this is the catalog's `toggleSettingKey` start-action bound to a
boolean setting (read `!== false` so an existing install with no saved value defaults ON); the
nudge auto-stops once you've engaged the control.

## How it behaves

### How it works

- **What it knows you've used** comes from the existing on-master `feature_events`
  telemetry — a curated feature with zero matching events is "never used" and eligible to
  pitch. No new tracking; nothing leaves the device for this decision.
- **What it can pitch** is a hand-authored catalog ([src/shared/feature-nudges/catalog.ts](/src/shared/feature-nudges/catalog.ts)) — a curated set of notable features (including Snooze and a "Check in on your Stats & Records" card), each with a one-line pitch and a one-click start action (enable a toggle, navigate to the feature, flip a live on/off switch right in the card, or — for try-it-live entries like snooze — act right on the card). The catalog is the single source of nudge wording and landing-page content.
- **The daily scanner** ([feature-nudge-scanner-service.ts](/src/main/services/feature-nudge-scanner-service.ts)) runs hourly: if the feature is enabled and the last nudge was ≥24h ago, it picks the first catalog entry you haven't used and haven't already been pitched, inserts a row in its own `feature_nudge_releases` table, and pushes it to the inbox. When nothing is left it simply stops.
- **The inbox card** is a standalone inbox source (its own `feature_nudge_releases` table — it does NOT use the shared alert/Drip table). It groups under a "DISCOVER" header. Dismissing archives it; snoozing rides the universal inbox-snooze table; a dismissed feature is never pitched again.
- **The in-pane detail** ([FeatureNudgeDetailPane.tsx](/src/renderer/src/features/feature-nudge/FeatureNudgeDetailPane.tsx)) renders in the main panel via the generic `activeInboxDetail` route (like recipe / pr-inbox rows), so the inbox cursor can land on it. "Start using it" flips the feature's setting on (if gated), marks the nudge accepted, and navigates you to the feature; if turning it on fails it shows an error instead of leaving you stranded. **"Maybe later"** archives the card (same as the X) AND advances the inbox to the next item — it routes through the one shared inbox-dismiss chokepoint (`dismissActiveInboxItem`) that every reading pane uses, which captures the visually-next card and moves you to it, exactly like archiving an SMS or a weekly summary. (It does NOT merely deselect: a plain deselect would leave nothing selected and the inbox would re-open the newest card, bouncing the panel straight back open on this same nudge.)

### Seeing whether nudges are working — the Nudges tab

Once Feature Discovery Nudges is on, a **Nudges** tab appears in **Stats** (it stays hidden
otherwise, so it never clutters Stats for people who don't use nudges). Per nudge you've been
shown, it puts how much you used the pitched feature **before** the nudge next to how much
**after** it — side by side, with the difference — plus where the nudge landed (shown →
**accepted** / **dismissed** / still-**pending**) and a "still filling" marker while the after
window hasn't fully elapsed.

The **"before" figure is ~0 by design**: a nudge only ever fires for a feature you've never
used, so the honest signal is the **after** adoption and the accept/dismiss funnel — a
non-zero "before" is a red flag that a nudge was mis-targeted, not a bug. The window is a fixed
14 days on either side of when the nudge was shown, anchored on the show date (so every nudge
gets a row, not just accepted ones).

This reads existing data — the `feature_nudge_releases` rows plus the same `feature_events`
telemetry the nudge system already uses — and adds **no new tracking**
([queries-nudge-effectiveness.ts](/src/main/db/queries-nudge-effectiveness.ts)). The same
per-nudge numbers, scrubbed to anonymous counts (no timestamps, no personal data), also ride
the daily fleet digest so the product team can see fleet-wide which nudges actually move people
to adopt a feature.

### Seeing what WILL happen — the preview

The Nudges tab above looks **backwards** at nudges already shown. The preview is the look
**forwards**, and it exists because nudge delivery is otherwise almost unobservable: at most one
card every 24 hours, chosen in catalog order, and off by default — so "is this actually working?"
could only be answered by waiting a day to see whether anything turned up.

```
GET /feature-nudge/preview          (bearer read, like GET /feature-nudge)
```

It answers three questions at once:

- **Would anything land at all right now?** `canLand`, plus `blockedBy` naming the specific gate
  when the answer is no — `flag-off` (the feature is switched off, the usual answer), `paused`
  (the scanner service is paused), or `cadence` (a card already went out; the next is not due
  yet). `explanation` says the same thing in plain English.
- **Which card is next, and when?** `next`, plus the full projected `schedule` — every remaining
  card, one per 24 hours, in the order they will actually fire.
- **Why is a card NOT in the list?** `skipped` gives a reason per entry: `already-pitched` (spent
  — a nudge is never re-pitched, even after you archive it), `already-used` (you already use that
  feature, so there is nothing to discover), or `ineligible`.

Two honesty details worth knowing. Each schedule entry is a **window** (`earliestAt` to
`noLaterThan`), not a single time — the scanner wakes hourly, so a card fires at the first wake-up
at or after its due mark. And the schedule **assumes the app keeps running**: the scanner only
advances while Omniscio is open, so a machine left closed for two days shifts everything later.

The preview reports the **same rotation the scanner itself uses**
([queue.ts](/src/shared/feature-nudges/queue.ts)) rather than keeping its own copy of the rules,
so it cannot drift into describing a schedule that never happens — a guard test fails the build if
either side stops using it. It is also read-only: previewing never creates a card, never notifies
you, and never marks a feature as shown.

Because the rotation is computed independently of the gates, the preview still shows the full
schedule **while nudges are switched off** — which is the point: you can see exactly what you
would get before deciding to turn them on.

### Relationship to the Workflow Coach

This is separate from the weekly AI **Workflow Coach** "feature-discovery" suggestions.
The Workflow Coach is weekly, LLM-generated (costs money, needs an API key) and lives in
the coach surface. Feature Discovery Nudges is the daily, deterministic, hand-curated
(free) surface with a richer popup and one-click enable. They're complementary.

## For agents

### Full invariants

See the contract: [.claude/memory/contracts/feature-nudge-contract.md](/.claude/memory/contracts/feature-nudge-contract.md).

## Related

[Feature Suite Recommendations](feature-suite-recommendations.md) groups the same features into themed suites and is what the proactive recommenders consult; [Empty-inbox discovery tip](empty-inbox-tip.md) is the other one-time, teach-by-doing card Omniscio puts in the Inbox.
