Whisper UX: surfacing background intelligence without interrupting flow
The problem: proactive AI that doesn't annoy
"You have an estimate that's been sitting in draft for nine days."
"This customer hasn't been contacted in 30 days."
"Two jobs on tomorrow's schedule overlap by an hour."
These are the moments where the system knows something the user should act on. The contractor is busy — driving between jobs, measuring a kitchen, writing up a quote on-site. They're not going to open the app and ask "hey, do I have any estimates expiring soon?" They need the system to surface that on its own.
The challenge is doing this without becoming Clippy. Without interrupting someone who's actively quoting a job. Without training users to ignore everything the app says because it won't stop talking.
There's a spectrum from helpful to hostile, and the difference comes down to three things: timing, modality, and dismissibility.
The Vigiles architecture: awareness without LLM cost
We named this system Vigiles, after the Roman night watch — the corps that patrolled the streets of Rome, raising the alarm only when something was actually wrong. They didn't stop every citizen to ask if they'd remembered to lock their door. They watched, and they acted when it mattered.
Vigiles is a background scheduler. It runs cron-driven Postgres queries. No LLM calls. No inference. Just straightforward conditional checks:
- Estimate created more than 7 days ago AND status is still draft AND no follow-up scheduled
- Job completed more than 3 days ago AND no review request sent
- Two schedule items overlapping on the same day for the same pro
- Customer's last service was 11+ months ago with a detected annual pattern
When a condition matches, Vigiles creates a whisper — a lightweight notification object queued for the user. The LLM only gets involved if the user engages. The detection itself is just SQL.
Running GPT-4 on a cron job to check if estimates are expiring would be absurd — and expensive. The intelligence is in knowing what to check and when to show it, not in the check itself.
The whisper pattern
A whisper has four defining characteristics:
- Non-modal — never takes over the screen or blocks interaction
- Dismissible — a single tap makes it go away
- Contextually timed — appears during natural pauses, not mid-action
- Low-priority by design — meant to be ignorable
In practice: a small badge on a tab, a dot on a customer card, a quiet count in a section header. It doesn't pop up. It doesn't slide in. It's just there, when you look.
Timing is where most proactive notification systems fail. We surface whispers at specific moments:
- After completing a task — brief cognitive pause before the next action
- When returning to the dashboard after being idle — user is re-orienting anyway
- Never during active data entry — if someone is filling out line items, the last thing they need is an unrelated notification
- Never during voice conversation — whispers wait
The notification hierarchy
| Level | Modality | Example | Dismiss effort |
|---|---|---|---|
| Whisper | Inline badge/dot | "2 estimates expiring" | Single tap |
| Toast | Temporary banner | "Estimate sent" | Auto-dismisses (5s) |
| Card | Persistent in feed | "Follow up with Johnson" | Swipe or archive |
| Modal | Overlay dialog | "Subscription expires tomorrow" | Explicit close |
| Blocking | Full-screen | "Update required" | Must complete action |
Whispers sit at the bottom. Designed to be ignorable. That's the point.
Critical rule: if a user ignores a whisper 3 times, it doesn't escalate — it goes away. Three passes, permanently dismissed for that item. No guilt trip. No passive-aggressive badge. The AI takes the hint.
Real examples from HomeGuild Pro
Estimate expiry. Draft estimates older than 7 days. Badge on the estimates tab. No popup, no interruption — the contractor notices it when they're already thinking about estimates.
Follow-up reminder. Job completed 3 days ago, no review request sent. Small dot on the customer card. One tap to send. Agent can draft the message if asked.
Schedule conflict. Two jobs overlap tomorrow. Whisper appears when the user views the schedule — not before, because it's not actionable until they're looking at the calendar.
Revenue opportunity. Customer's last service was 11 months ago, annual pattern detected. Speculative — pattern matching, not certainty. Low confidence gets low modality. If we're wrong, the user barely notices. If we're right, it feels like the app is paying attention.
What we learned
The hardest part of proactive AI isn't the intelligence — it's the restraint. Every background check went through the same filter: "If this appeared while a contractor was on a ladder, would they be annoyed?" If the answer was even maybe, it got cut.
Background queries for detection, LLM only on engagement. Vigiles checks are cheap Postgres queries. The LLM only spins up when a human decides to engage.
The "3 ignores and stop" rule was essential. Whispers that persisted until dismissed felt like a guilt trip. Auto-dismissal changed the entire feel — from nagging to suggesting.
Timing is everything. Immediate delivery had a 70% dismiss rate. Contextually timed delivery had a 40% dismiss rate and significantly higher engagement. Same notification, same content, same UI — different moment.
Low confidence gets low modality. Speculative signals stay at whisper level. If we're wrong, the user barely notices.
The whisper pattern isn't complicated. It's a queue, a badge, and a set of rules about when to show and when to stop. The technology is the easy part. The restraint is what makes it useful.