End-to-end: vitals watch
You will build: the deterioration-watch pipeline from the Healthcare use case — vitals windowed per patient, escalation thresholds with no model in the alarm path, and a situation summary drafted by a local Ollama so PHI never leaves the machine.
Prerequisites
- The quickstart completed.
- A local Ollama for step 4 — the point of this pipeline is that the model runs inside your perimeter. (Without it, stop after step 3: escalation already works.)
1 · Scaffold
pulse new vitals --source webhook \
--stage streaming:trend --stage rule-based:escalate --stage llm:summarize \
--sink webhook
2 · The trend stage — per-patient windows
stages:
- name: trend
engine: streaming
operators:
- { type: keyBy, field: patient_id }
- type: window
spec: "sliding(10m,1m)"
aggregations:
hr_avg: "avg(heart_rate)"
hr_stddev: "stddev(heart_rate)"
spo2_min: "min(spo2)"
3 · The escalation stage — deterministic, microseconds, auditable
- name: escalate
engine: rule-based
rules:
- { condition: "spo2_min < 92 || hr_stddev > 15", action: flag }
The alarm path contains no model: thresholds your clinical governance signed off, applied identically every time.
4 · The summary stage — a local model drafts the context
- name: summarize
engine: llm
systemPrompt: |
Draft a one-paragraph situation summary for the
responding clinician: what crossed the line, the
trend, and the window it happened in.
Point Pulse's LLM provider at your local Ollama — the event data is summarized without leaving the machine.
5 · Sink to the unit board and deploy
pulse secret set UNIT_BOARD_WEBHOOK https://webhook.site/<your-id>
pulse secret set PULSE_WEBHOOK_SECRET dev-secret # the scaffolded webhook source requires it
pulse deploy .
6 · Simulate a deteriorating patient
for spo2 in 97 96 95 93 91 90; do
pulse events publish --topic vitals.in --value '{"patient_id":"p-12","heart_rate":'"$((RANDOM % 40 + 80))"',"spo2":'"$spo2"'}'
done
pulse events tail --topic vitals.escalate.out
The moment spo2_min drops under 92 inside the window, the escalation fires; vitals.summarize.out carries the drafted paragraph; the unit board webhook receives both.
What just happened
The clinical constraints shaped the architecture: rules decide, the model only describes, the human acts — and every step landed on an auditable topic. Because the LLM is local, the privacy property is architectural, not contractual. The system surfaced attention; it never acted on a patient.
Troubleshooting
No escalation fires
The window needs readings below 92 within the sliding window — send the burst within a couple of minutes. Check vitals.trend.out to see the computed spo2_min per window.
summarize is unhealthy
Ollama isn't reachable. That stage stays visibly unhealthy — escalation (the safety-critical part) keeps working without it.
Next
- Keyed timers — a monitor that goes silent is a signal too
- Crash-resume — baselines that survive a restart