PocketTriage v0.1 · 2026.05
00 · Decision support · Health & Sciences · Apache 2.0

Offline WHO IMCI paediatric triage. On the device.

Community health workers in low-connectivity settings type the symptoms. Gemma 4 on-device returns the IMCI tier and a structured referral pathway. A non-bypassable safety layer catches general danger signs even when the model is wrong. Nothing leaves the device.

Apache 2.0 Gemma 4 · on-device Phase 1 Gate · 4 / 4
IMCI scenarios
4/4 PASS
Network packets
0non-localhost
Safety tests
17passing
Latency · M-series
9.8s median
Case · severe pneumonia
Airplane mode · 0 packets
PATIENT 11-month-old boy.
Cough for 3 days. Breathing 58/min.
Chest is sucking in. Restless and refusing to drink.
TierPINK

Refer urgently. Give first dose of injectable ampicillin + gentamicin (or oral amoxicillin if no injectable available). Transport to the nearest hospital immediately.

section Section 2 · severe pneumonia / very severe disease
danger_signs { chest_indrawing: true, refusing_to_drink: true }
confidence 1.00 safety_overrides none
backend = ollama → gemma4:e2b · 5.1 B · Q4_K_M latency = 10.6 s
01 · Evidence

Four canonical IMCI scenarios. Wi-Fi off. tcpdump running.

Scenarios drawn from the WHO IMCI Chart Booklet 2014. The product was gated on this verifiable airplane-mode test before any polish work.

eval/airplane-test-log.md
#ScenarioExpectedActualLatencyResult
S1Severe pneumonia · chest indrawing + refusing to drinkPINKPINK10.6 sPASS
S2Some dehydration · diarrhoea + restless + sunken eyes + slow skin pinchYELLOWYELLOW10.7 sPASS
S3Uncomplicated malaria · RDT-positive fever, no danger signsYELLOWYELLOW9.3 sPASS
S4Cough or cold · cough + drinking well + no chest indrawingGREENGREEN8.4 sPASS
tcpdump$ wc -l /tmp/airplane-net.log  →  0  //  zero non-localhost packets across the entire run
02 · Architecture

One narrow path. No server. No analytics.

No fallback to anyone else's cloud. The same JSON output contract is designed for laptop V1 (Ollama, shipped) and Android V2 (LiteRT, roadmap).

infer.py · backends.py · safety.py
01 · Input
CHW symptom text (+ optional photo)
In-process. Never persisted to disk; never sent to any network address.
02 · Model
Ollama @ 127.0.0.1:11434 → gemma4:e2b · 5.1 B · Q4_K_M
Native gemma4 architecture in Ollama ≥ 0.23.1. Avoids the iSWA-attention bug present in older llama-cpp GGUF distributions.
03 · Parse
_extract_first_json · _validate_shape
Tolerant JSON coercion with a deterministic fallback so malformed model output cannot crash the UI.
04 · Safety
safety.apply_safety_layer
R13 danger-sign keyword → force PINK · R14 confidence < 0.4 → append escalation · R15 adult case → refusal · R16 disclaimer banner.
05 · Render
Gradio · tier card + pathway + reasoning + flags
On laptop, served on 127.0.0.1:7860. On Android (roadmap), the same JSON contract renders in a Kotlin native layout via LiteRT.
03 · Safety

Four invariants. Enforced after the model speaks.

17 unit tests cover the safety layer (laptop/test_safety.py). PocketTriage treats the classifier as fallible and never lets it have the final word.

laptop/safety.py
R13 · Danger-sign force-PINK
Override the model when general danger signs appear.
Keywords: unable to drink, vomits everything, convulsions, lethargic, unconscious, stiff neck, chest indrawing. Negation-aware: "no chest indrawing" does not fire. The tier is forced to PINK even if the model said GREEN.
R14 · Confidence floor
Escalate every low-confidence case to a human.
If the model self-reports confidence < 0.4, "Escalate to medical officer" is appended to the pathway regardless of tier.
R15 · Adult refusal
Adult conditions are out of scope — full stop.
Adult-specific terms (chest pain in adult, stroke in adult, pregnancy emergency) trigger a refusal with a referral to adult emergency protocol. Paediatric scope, hard boundary.
R16 · Non-dismissable disclaimer
The clinical-judgment ribbon is part of the layout.
"Decision support based on WHO IMCI 2014. Does NOT replace clinical judgment. Paediatric only (2 months – 5 years)." Always visible. Never closeable.
04 · Distribution

Outreach drafted with named contacts.

Three letters with full email bodies, shorter LinkedIn / WhatsApp variants, and send-log tables. Sending now that the submission is in and the demo URL is live.

outreach/*.md
Geneva
WHO Digital Health & Innovation
Dr. Alain Labrique · Director, DHI. Backup: Bernardo Mariano Jr.
Letter drafted
New Delhi · Mumbai
India NHM · ASHA programme
Smt. Roli Singh, IAS · Add. Secretary & Mission Director. + NHSRC + Maharashtra state Mission Director.
Letter drafted
Abuja · Awka
Nigerian NPHCDA
Dr. Muyi Aina · Executive Director NPHCDA. + Anambra SPHCDA + FMoH Coordinating Minister Pate.
Letter drafted
05 · Run locally

Clean clone to first triage — about fifteen minutes.

The same code path you see on the live Space, but on your own hardware. No network during inference. On Apple Silicon expect 8–11 seconds per triage.

README.md
# 1 · Install Ollama (macOS shown · Linux: install.sh from ollama.com)
brew install ollama
ollama serve &

# 2 · Pull the model (one-time, ~7 GB)
ollama pull gemma4:e2b

# 3 · Clone & install
git clone https://github.com/yonkoo11/pockettriage
cd pockettriage/laptop
python3.12 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

# 4 · Phase 1 Gate · same 4/4 you saw in the evidence table above
python eval_runner.py     # → 4 / 4 PASS

# 5 · Launch
python app.py             # → http://127.0.0.1:7860
Decision support based on WHO IMCI 2014. Does NOT replace clinical judgment. Paediatric only (2 months – 5 years). Photo input is treated as a supplementary signal; the pathway must always be groundable in the text description alone.