Concepts
Proactive Triggers
A raw LLM is reactive — it only speaks when spoken to. Humane's Proactive Engine watches behavioral state and reaches out when thresholds are crossed. Mood crashes, silent users, trust milestones, escalating task reminders — your product can act without the user initiating.
Built-in triggers
| Trigger | Fires when | Default cooldown |
|---|---|---|
| proactive.mood_drop | mood < 0.3 | 60m |
| proactive.energy_low | energy < 0.25 | 120m |
| proactive.trust_milestone | trust > 0.7 & interactions > 10 | 1440m |
| proactive.user_inactive | last_seen > 48h | 1440m |
| proactive.engagement_drop | compound: interactions > 5 & familiarity > 0.3 & last_seen > 24h & mood < 0.5 | 720m |
| proactive.task_reminder | Task Engine cron sweep, escalation level L1 or L2 | per-task |
| proactive.task_escalation | Task Engine cron sweep, escalation level L3 or L4 | per-task |
Dual-event delivery
Every proactive opportunity fires both a granular event and an umbrella event. Subscribers pick whichever they consume — granular for precise routing, umbrella for catch-all dashboards:
proactive.{trigger_name}— granular (e.g.proactive.mood_drop)proactive.triggered— umbrella, identical payload
What happens when a trigger fires
- Both events above are dispatched to your subscribed webhook endpoints (HMAC-signed).
- If you have a Slack / Discord integration, the rich message lands in your channel with an "Open patient session" deep-link.
- A row is written to
proactive_triggerswith the timestamp — powers cooldowns, survives restarts. - The event is returned inline on the SDK response as
response.proactive.
Event payload
{
"event": "proactive.mood_drop",
"timestamp": "2026-04-17T14:22:10Z",
"data": {
"trigger": "mood_drop",
"description": "User mood dropped below critical threshold",
"suggested_action": "Send empathetic check-in message",
"end_user_id": "patient_42",
"user_state": {
"mood": 0.18,
"energy": 0.42,
"trust": 0.55,
"interaction_count": 7,
"last_seen": "2026-04-17T14:19:40Z"
},
"timestamp": "2026-04-17T14:22:10Z"
}
}Task Engine — 5-level escalation
Tasks escalate on a fixed schedule once remind_atis reached. The cron sweep transitions levels and emits the matching proactive event for each fire:
| Level | Fires at | Tone | Event |
|---|---|---|---|
| L0 | passive | silent | — |
| L1 | remind_at | cordial nudge | task_reminder |
| L2 | +5m | firmer | task_reminder |
| L3 | +20m total | escalated | task_escalation |
| L4 | +50m total | caregiver-grade | task_escalation |
L4 refires hourly until max_fire_count = 8, then the task auto-stalls and is dropped from the active sweep.
Auto-detection from messages
Brain step 10 runs task_detector.py against the incoming message text. Patterns matched:
"remind me to X at Y""I'll do X tomorrow""schedule X""take MEDICATION at TIME"
A row is inserted with end_user_id + theremind_at parsed by the standalone time parser. Detected tasks are surfaced on the response underauto_created_tasks:
"auto_created_tasks": [
{
"title": "Take blood pressure meds",
"remind_at": "2026-05-19T20:00:00Z",
"priority": "high",
"detector": "medication_pattern"
}
]Cooldowns (persisted)
Each (end_user, trigger) pair has an explicit cooldown window. The proactive_triggers table keyed by these two columns stores last_fired_at. Until the cooldown elapses, the trigger won't re-fire for that user — even across backend restarts or multiple worker processes.
fire_event action becomes a trigger. The cooldown is configured per-rule in the YAML. See Policy Engine .Delivery channels
Any active webhook subscribed to the event type receives it. That includes:
- Your custom HTTPS endpoint (via
/api/webhooks) - Slack / Discord Incoming Webhooks (via
/api/integrations) - The tenant's Signals page (live SSE stream)