
Beet
Verifiable health triage at your fingertips.
Demo
About
The problem it solves ## The Crisis No One Is Watching Every year, disease outbreaks kill **millions** of people - not because we lack medicine, but because we find out too late. The World Bank estimates **5 million people** in rural communities die annually from treatable conditions due to delayed detection. **50% of the world** lacks access to essential healthcare. In low-resource clinical settings across the Global South, triage is done on paper. Patient data lives in notebooks that never leave the clinic. Public health authorities have no real-time signal. By the time a regional outbreak is confirmed, it has already spread across borders. The existing tools fail in *three ways*: **1. No edge-level intelligence.** Patients in remote clinics are assessed by overstretched staff with no decision support. Misdiagnosis is common. Early warning signals are lost. **2. No privacy-preserving data sharing.** Sharing patient data across institutions requires trusting a central intermediary - which creates liability, HIPAA/GDPR risk, and in authoritarian contexts, real danger to patients. **3. No tamper-proof audit trail.** Aid organizations and governments can't verify that reported health data hasn't been manipulated - making resource allocation decisions unreliable. ## What Beet Does **Beet** is a decentralized public health triage infrastructure built for the edge. Imagine a patient walks into a clinic in Lagos, Nairobi, or Dhaka. They're handed a small device - a **Beet node** (ESP32 microcontroller). They answer a couple of yes/no symptom questions. In *under 60 seconds*, Beet: - Runs a **local weighted inference engine** (no cloud, no ML model, no data leak) to produce a diagnosis and confidence score - Computes a **SHA-256 hash** of the symptom bitmask - raw symptoms never leave the device - Posts the session to a **DAML smart contract on Canton Network** - where the clinic, patient, and public health authority each see *only* what they are entitled to see, enforced at the protocol level - **Anchors the record hash** on the ADI Chain - creating a tamper-proof, publicly verifiable integrity proof without storing any PHI on-chain The result: a global health surveillance network where **privacy is not a policy promise - it's a cryptographic guarantee.** **Who uses it:** - **Clinics** - submit and manage triage sessions, track patient load- **Governments/Gov Orgs** - allocate emergency resources based on verified, tamper-proof epidemiological data - **Public Health Authorities / NGOs -** monitor real-time outbreak signals, trigger escalation protocols - **Researchers** - audit record integrity via on-chain hashes without ever seeing patient data Use of AI tools and agents ### On-Device Inference Engine (ESP32) The core AI in Beet runs entirely on the microcontroller - with no cloud, no network call, and no data leaving the device. We implemented a **weighted rule-based inference engine** that maps six binary symptom inputs (fever, cough, fatigue, stomach pain, shortness of breath, sore throat) to four candidate diagnoses (Flu, Cold, COVID, Strep) using a hand-tuned scoring matrix derived from clinical triage guidelines. The engine runs `argmax` over the scores to select the most likely diagnosis and normalizes the winning score against the theoretical maximum to produce a confidence value between 0 and 1. This is intentionally lightweight - it runs in microseconds on a $3 chip with no GPU, no model weights, and no network dependency. The design philosophy is that edge inference must be **deterministic, auditable, and offline-capable.** A clinic with intermittent WiFi still gets a diagnosis. Only the result - and a hash of the inputs - ever leaves the device. The symptom bitmask is SHA-256 hashed before transmission, meaning the raw symptom responses never reach the backend, the blockchain, or any external system. Privacy-preserving by design.
How it's made
Challenges we ran into ## We Were New to Blockchain. Here's What Broke (And How We Fixed It.) ### 1. Our LCD Screen Died at ETHDenver We had everything working on our hardware setup back home - ESP32 with a 16x2 I2C LCD screen for the patient questionnaire interface. We got to Denver and the LCD stopped responding entirely. No backups, no replacement hardware on hand. **Fix:** We improvised with a smaller OLED screen we had spare. Different library, different resolution, different I2C address - but it gets the job done. The triage flow still works, the display is just more compact. Sometimes hackathon hardware just dies and you ship with what you have. ### 2. Learning DAML's Privacy Model From Scratch Neither of us had written DAML before this hackathon. The Canton privacy model - signatories, observers, controllers, two-phase contract workflows - is conceptually elegant but has sharp edges. We hit compile errors back to back: - `Archive` is a reserved keyword in DAML Prelude - had to rename our choice to `Discard` - `DA.Time` doesn't export `Time` as a named type - had to remove the import - `daml-script` must be explicitly declared as a dependency in `daml.yaml` - Party IDs reset on every sandbox restart, causing `UNKNOWN_SUBMITTERS` errors until we built proper re-allocation into our workflow **Fix:** Each error had a clear compiler message once we understood the mental model. The DAML compiler errors are actually very good - we just needed to learn the system. ### 3. Integrating Two Codebases Built Separately Our team split up - one person built the ADI anchor service in Node.js/viem, the other built the Flask backend in Python. The ADI service expected a specific payload shape with keccak256 hashing. We had a placeholder REST API sending a completely different format, and the two had never talked to each other. **Fix:** We read through `server.js`, reverse-engineered the exact payload schema from the `validate()` function and test JSON files, and rewrote our `anchor_to_adi()` function to match exactly. One curl later - a real blockchain tx hash came back. ### 4. API Compatibility - Every Python Library Was Wrong Our first instinct was to use **dazl** (the Python gRPC client for DAML ledgers) to talk to Canton. We installed it, wired it up, and got: ``` UNIMPLEMENTED: com.daml.ledger.api.v1.PackageService/ListPackages ``` After digging through the Canton changelog, we found that Canton 3.x only supports Ledger API v2, but dazl v8.3.0 still calls v1 internally. We also tried the HTTP JSON API on port 7575 - every path returned 404. There was no Python client that worked out of the box. **Fix:** We scrapped both approaches and drove Canton directly via `daml script` subprocess calls over gRPC. We wrote DAML Script helpers in `Scripts.daml` and had Flask invoke them via `subprocess.run()`, passing arguments through temp JSON files. Ugly, but battle-proven - and it worked.