Proactive Molly
When something on your server spikes or an alert fires, Molly takes a look immediately. She names the likely cause in one sentence, and (when confident) suggests a one-click fix. Phase Б.2 of the roadmap — the second instalment of “AI as operational plane” after zero-shot provisioning.
What you get
- Spike triage — every CPU / RAM / disk spike captured by SpikeDetector triggers a one-shot Molly classifier turn. Confidence > 0.7 → push notification with the diagnosis and a suggested Apply action.
- Alert-event triage — same treatment for every event in the alerting evaluator. 5-minute dedup window per alert ID prevents spam from a noisy alert.
- Hourly cap with digest fallback — 5 triage calls/hour on Free, 10/hour on Pro+. Past the cap, additional diagnoses fold into a single end-of-hour digest notification (Pro+ only).
- Molly noticed — the Molly insight block on the Server Overview (and the Molly Noticed widget) shows the latest diagnosis in one sentence. Click it to ask Molly about it.
How it works
1. Hooks
The Triager subscribes to two event streams the OS already produces:
SpikeDetector.Subscribe(handler)— the long-running monitoring subsystem fires aSpikeEvent{NodeID, Metric, Value, TopProcesses}when a per-metric threshold trips. The Triager handler runs in its own goroutine outside the SpikeDetector mutex, so a slow Molly call cannot stall the sample loop.alerting.Evaluator.SetTriageHook— the alerting evaluator calls the hook after channel notifications fire. The hook runs in a goroutine with panic-recover.
No always-on subsystem; everything is event-driven.
2. One-shot classifier
For each incoming event the Triager builds a short prompt:
- 5-minute system context snapshot (from the existing
internal/ai/molly.ContextCollector). - Spike or alert payload.
- Top-3 processes (for spikes).
- An instruction to respond in JSON only, with
{diagnosis, confidence, action?}.
Free tier uses local Ollama; Pro+ unlocks cloud models if you’ve enabled them as your default. The parser is tolerant — markdown-fenced responses get unwrapped, and inner JSON objects get extracted from chatty prose.
3. Push or store
- Confidence > 0.7 → push notification through the existing
SystemNotificationssurface (web + mobile). The notification carries the proposed Apply action when the model returned one. - Confidence ≤ 0.7 → log only; kept in the insights history (
GET /api/molly/insights/recent) but no push. - Tool-name whitelist — only tools the existing Molly registry recognises are kept on the Apply button. If the model hallucinates a bogus tool, the action is dropped and the diagnosis text remains.
4. Hourly cap + digest
Each node has an in-memory ring counter. Once full:
- Free tier: subsequent diagnoses are silently dropped (with a log entry visible in Insights). Upgrade for the digest.
- Pro+: subsequent diagnoses queue into
pendingDigest. Atime.AfterFuncre-arms each hour; ifpendingDigestis non-empty, a single digest notification fires summarising what happened.
Where insights appear
- Overview → Molly insight. The Server Overview shows a Molly noticed block with the most recent diagnosis. If there is none, it falls back to a disk forecast (“Disk will reach 90% in about N days”) plus the Docker space that can be freed. The block is hidden when nothing needs attention, and you can turn it off under Customize.
- Molly Noticed widget. The same insight as a widget on the Overview board.
- Notifications. Pushed diagnoses and digests arrive in the notifications popover (the bell in the menu bar) and on paired phones.
Clicking the insight opens the Molly window with the question pre-filled. When Molly proposes an action, it appears as a tool-call card in the window; actions that change the system ask you to approve or deny them and then run through the standard sysctl chokepoint. Applying an action needs the proactive_ai gate on your plan and the operator role (or higher) on the node.
API surface
GET /api/molly/insights/recent— returns the last 5 diagnoses (max 20). Auth-gated.
No new database tables. The Insights live in the Triager’s in-memory ring buffer and are wiped on restart — that’s by design for triage data.
Plans
| Tier | Triage / hour | Cloud model | Hourly digest |
|---|---|---|---|
| Free | 5 | ❌ (local Ollama only) | ❌ |
| Pro | 10 | ✅ | ✅ |
| Team / Enterprise | 10 | ✅ | ✅ |
Surfaced in /api/license/orbit-features as proactive_ai (true on every plan, with different caps) and proactive_ai_digest (Pro+ only).
Answer integrity on proactive answers
Since 0.9.1, every proactive triage and digest answer is run through the AI Response Integrity pipeline before being stored as a notification. This means push alerts — not just interactive Molly chat — now carry the same accuracy guarantee:
- Every metric or figure in the notification has been verified against the tool results from that triage turn.
- Unverifiable figures are marked with ⚠️ and are not presented as authoritative.
- A transient provider failure triggers a retry with exponential backoff rather than producing a garbled notification.
No configuration is needed. The integrity pipeline is on by default. Operators can disable it globally with QUAZZAR_AI_INTEGRITY=off (see AI Integrity configuration).
Limitations & roadmap
- One-click Apply directly from the Overview — the insight hands off to the Molly window, where you approve the tool call.
- No DB persistence for diagnoses — by design. Restart wipes the ring.
- No cross-node correlation — phase Г cluster scope. A diagnosis on node A doesn’t reference an earlier spike on node B yet.
- No anomaly prediction — the Triager reacts to events; forecasting before a spike is a v2 surface.
- Control Panel relay — the CP AI chat relays Molly answers from the OS node. Integrity runs on the OS node (upstream), not at the CP relay layer. The guarantee is present but is not double-verified at the CP layer.