Amber turns lab report PDFs (LifeLabs / Dynacare) into a single, fully offline HTML dashboard: every family member gets a tab, every blood marker gets a trend chart against its reference range, and after each new report an LLM writes a plain-English recommendation that builds on the previous one — what improved, what needs attention, what to ask your doctor.
Pipeline: extract → verify → validate → recommend → build
- 📄 Extract — a deterministic parser reads the PDF into a draft JSON report (values, units, ranges, flags) plus the raw text
- 🔍 Verify — an LLM cross-checks every value against the raw text, maps missed markers, fixes units (the printed value is never trusted blindly)
- ✅ Validate — schema, plausibility bounds, duplicate detection; a report that can't be validated is never stored
- 🩺 Recommend — an LLM writes a recommendation that explicitly builds on the previous one, so guidance has memory
- 📊 Build — one self-contained
index.html: person tabs, in-range ring, report timeline, reference-band trend charts with tooltips, guidance history, all-values table, light/dark
🎭 Live demo (fictional data) · 📖 Project write-up
Scripts do everything deterministic (parsing, validation, HTML generation);
the LLM is used only where judgement is genuinely needed — verifying an
extraction against messy source text, and writing guidance that reflects on
history. The dashboard is a single offline file with zero external
requests, because health data should not touch a network to be viewed. And
the extractor never trusts itself: every stored value carries its raw_text,
plausibility bounds catch narrative lines masquerading as results (a guideline
sentence mentioning "2013" will never become an HbA1c of 2013), and a printed
H/L flag that disagrees with the computed one is surfaced for review.
Amber ships as a Hermes skill —
bloodwork-dashboard — so an agent runs the whole pipeline conversationally.
git clone https://github.com/vimal-tech-pm/Amber.git ~/amber
pip install -r ~/amber/requirements.txt # pdfplumber, jsonschemaRegister the skill in ~/.hermes/config.yaml:
skills:
external_dirs:
- /home/you/amber/skillsThen drop a PDF into data/inbox/<Person>/ (the folder decides whose report it
is; the filename can be anything) and, in a Hermes chat with a strong model
active, say "process the new bloodwork report." The session's model does
the verification and writes the recommendation — model quality is your choice,
per run.
Optional scheduled processing:
hermes cron create "0 8 * * *" \
"Check data/inbox recursively for new bloodwork PDFs; if any are present, run \
the full bloodwork-dashboard procedure end to end; if none, stay silent" \
--skill bloodwork-dashboard --model <your-frontier-model>Reports usually arrive every few months, so on-demand chat triggering is the sensible default; a paused cron makes a fine safety net.
The scripts are plain Python with no agent dependency:
# 1. Parse a PDF into a draft report (+ raw text for cross-checking)
python3 skills/health/bloodwork-dashboard/scripts/extract_bloodwork.py \
data/inbox/Alex/2026-Jan-15.pdf --out draft.json --print-text
# 2. Verify the draft against the raw text — yourself, or with any LLM
# (the SKILL.md "Verify" step is the prompt); save the final report to
# data/reports/<person>/<date>-<lab>.json
# 3. Validate it
python3 skills/health/bloodwork-dashboard/scripts/validate_report.py \
data/reports/alex/2026-01-15-lifelabs.json --reports-dir data/reports
# 4. (Optional) write a recommendation to data/recommendations/<person>/<date>.md
# using templates/recommendation.template.md — any LLM, or by hand
# 5. Rebuild the dashboard
python3 skills/health/bloodwork-dashboard/scripts/build_dashboard.py --root .Steps 1, 3, and 5 are fully deterministic — you get extraction, validation, and the dashboard with no LLM at all. Steps 2 and 4 are judgement steps: bring any model you like (the skill file documents exactly what each step must do).
| Path | What |
|---|---|
skills/health/bloodwork-dashboard/ |
the skill: SKILL.md procedure, scripts/ (extract / validate / build), templates/ (report schema, recommendation skeleton), references/ (marker dictionary, lab-layout notes) |
data/ |
your data lives here — gitignored by default (people.example.json shows the shape) |
demo/ |
the live demo dashboard, built entirely from fictional data |
samples/ |
synthetic PDF generator + golden extraction fixtures (fictional people: Alex Chen, Jordan Lee) |
tests/test_pipeline.py |
43 checks: unit tests, extraction regression vs goldens, validation, dashboard build |
python3 samples/make_samples.py # regenerate the fictional PDFs (needs reportlab)
python3 tests/test_pipeline.py # run the suiteNew marker, new alias, new lab quirk? Edit references/markers.json (aliases,
units, ranges, plausibility bounds) and note the layout in
references/lab-formats.md — the scripts are driven by those files, so most
extensions need no code. New lab format entirely: the extractor's
order-independent token parser (value / range / unit / flag in any order)
usually covers it already.
data/is gitignored by default — your reports, recommendations, and archive never leave your machine unless you deliberately change that.- The dashboard is one offline HTML file: no CDN, no fonts, no analytics, no requests of any kind.
- Everything in this repository — including the live demo — is fictional data
generated by
samples/make_samples.py. No real health information is, or ever was, in this repo's history.
Amber visualizes lab trends for personal tracking. It is not medical advice and does not replace consultation with a qualified healthcare professional.
Built for Hermes by Nous Research. Designed and implemented in collaboration with Claude (Anthropic).
MIT © Vimal Sekar