Modern radiocarbon calibration with LLM-powered narrative explanations, Bayesian modelling, and GIS curve selection.
Libby is a full-featured web application for calibrating radiocarbon dates with a modern Svelte 5 frontend, a Python/FastAPI backend, and unique features — including plain-English narrative explanations of calibration results, summed probability distributions, and a lat/lng-based curve selector for IntCal vs SHCal vs mixed curves.
Calibrating the Shroud of Turin (691 ± 31 BP) — from input to narrative result
- Single-date calibration — BP age + σ → calibrated PDF chart with 1σ/2σ HPD ranges
- Batch calibration — paste multiple dates at once, view SPD/KDE chart and results table
- Kernel Density Estimation (KDE) — alternative to SPD for batch date visualisation; avoids artifactual peaks from calibration curve steepness
- LLM-powered narratives — plain-English explanation of every calibration result
- Multi-language support — narratives in 12 languages (English, French, German, Spanish, Italian, Portuguese, Japanese, Arabic, Chinese, Dutch, Swedish, Polish)
- Multi-provider LLM support — Nvidia NIM (free tier, 40 req/min), Anthropic Claude
- Bayesian Phase & Sequence modelling — Metropolis-Hastings MCMC with Agreement Index (validated against known references)
- GIS curve selector — Leaflet map pin-drop auto-suggests the appropriate calibration curve based on latitude
- Marine reservoir correction (ΔR) — automatic ΔR lookup from the 14CHRONO Marine Reservoir Database (calib.org); Bevington error-weighted mean, deposit-feeder filtering, 24h cache
- Project management — group dates by site, context, or research project
- Summed Probability Distribution (SPD) — combined probability across all dates
- Taphonomic warnings — material-aware notes (old-wood effect, collagen preservation, marine reservoir effect, etc.)
- CRM report automation — generate Section 106 (US), UK HER, and generic compliance reports (PDF + DOCX)
- Export: formatted PDF report, CRM compliance reports (PDF/DOCX), CSV, OxCal CQL2 script, publication-ready text, publication-quality figures (PNG/SVG/TIFF), auto-generated journal captions
- Multi-chart output — tab-selectable chart types: interactive PDF curve, OxCal-style calibration plot (curve + measurement overlay), multi-panel publication figure (curve overview + SPD)
- Dynamic curve registry — SQLite-backed curve metadata; add new curves (IntCal25, SHCal25) by dropping .14c files into the curves directory — no code changes needed
- Calibration curves: IntCal20, SHCal20, Marine20 (CC BY 4.0)
- GIS map — OpenStreetMap with zone overlays (journal-safe, no Google Maps)
- Docker deployment and pip install packaging
- 127 tests — 64 unit (fast, no network) + 9 live calib.org integration + 54 full E2E API tests
| Layer | Technology |
|---|---|
| Backend | Python 3.13+ / FastAPI |
| Frontend | Svelte 5 / SvelteKit / Chart.js / Leaflet |
| Calibration engine | iosacal + direct IntCal curve data |
| Bayesian MCMC | Pure numpy/scipy Metropolis-Hastings (validated) |
| KDE | Pure numpy/scipy Gaussian KDE (Silverman's rule) |
| Delta-R | calib.org on-the-fly proxy query + Bevington weighted mean |
| LLM | Nvidia NIM (OpenAI-compatible) or Anthropic Claude |
| Database | SQLite (aiosqlite) — curves, projects, calibrations, ΔR cache |
| ReportLab (academic + CRM reports) | |
| DOCX | python-docx (CRM compliance reports) |
| Charts | Chart.js (frontend), matplotlib (figure export + PDF reports) |
| Curve registry | DB-backed with auto-ingestion; IntCal25-ready |
pip install libby
libbyOpen http://localhost:50001 in your browser.
docker compose up -d
# Open http://localhost:50001Or pull from GitHub Container Registry (once published):
docker pull ghcr.io/mabo-du/libby:latest
docker run -p 50001:50001 ghcr.io/mabo-du/libby:latestTo publish the Docker image yourself:
docker build -t libby .
docker tag libby:latest ghcr.io/mabo-du/libby:latest
docker push ghcr.io/mabo-du/libby:latestgit clone https://github.com/mabo-du/libby.git
cd libby
# Backend + frontend (single server)
uv sync
uv run uvicorn libby.main:app --reload --port 50001
# Open http://localhost:50001
# Frontend dev server (for UI development, requires backend on 50001)
cd frontend
npm install
npm run dev -- --port 50002
# Open http://localhost:50002 (points at backend API on :50001)Libby works without any LLM — a deterministic fallback generates coherent narratives from the numbers alone. For AI-powered narratives, set:
# Nvidia NIM (free — sign up at build.nvidia.com)
echo 'LIBBY_NIM_API_KEY=nvapi-...' > .env
# Or Anthropic Claude
# echo 'LIBBY_LLM_PROVIDER=anthropic' >> .env
# echo 'LIBBY_ANTHROPIC_API_KEY=sk-ant-...' >> .envEnter a BP age and standard deviation, select a curve, click Calibrate. View the probability distribution chart, 1σ/2σ ranges, and plain-English narrative.
Chart types — use the tabs above the chart to switch between:
- PDF Curve — interactive probability density with hover crosshair and HPD fills
- OxCal Plot — publication-style calibration plot showing the IntCal curve with graduated uncertainty bands, your radiocarbon measurement overlaid, and the calibrated probability distribution (matching the format archaeologists expect in journal publications)
- Multi-Panel — double-column publication figure with calibration curve overview and summed probability distribution
Export options — once calibrated, download your results as:
- PNG / SVG / TIFF figures (300–600 DPI) in your selected chart type
- Journal-compliant figure caption with CC BY 4.0 curve attribution
- Publication-ready text block
- PDF report, CSV data, OxCal CQL2 script
Click Batch in the nav, paste dates as CSV-like text, calibrate all at once with Summed Probability Distribution.
On the calibration page, expand Curve selector by site location. Click anywhere on the map to place a pin — Libby suggests the correct curve based on latitude and explains the reasoning.
When calibrating marine samples against Marine20, Libby automatically looks up the local ΔR (Delta-R) correction from the 14CHRONO Marine Reservoir Database at calib.org. Enter your site coordinates and Libby:
- Queries nearby ΔR measurements within 500 km
- Filters out deposit feeders (organisms that ingest old carbonates)
- Computes the Bevington error-weighted mean and conservative uncertainty
- Displays source citations per the database's attribution requirements
- Caches results for 24 hours for speed and resilience
- Falls back to manual ΔR entry if no data is available
Generate compliance-ready radiocarbon dating appendices for:
- US Section 106 (NHPA) — letter-size, regulatory language
- UK HER — A4, NPPF-compliant formatting
- Generic CRM — grey literature appendix
Output as PDF or editable DOCX. Each report includes project metadata, a date table with calibrated 2σ ranges, contextual notes, and methodology boilerplate with CC BY 4.0 curve citations.
Create projects to group dates by site. Each project shows:
- All dates with full calibration data
- Summed Probability Distribution chart
- Project summary narrative
- Bayesian modelling (Phase or Sequence)
- PDF report, publication-quality figures, OxCal export, CSV export
With 2+ dates in a project:
- Phase model — estimates start/end boundaries for an activity period
- Sequence model — applies stratigraphic ordering constraints
- Agreement Index (A) per date, following OxCal's convention (A ≥ 60 = acceptable)
Navigate to Import, paste CSV/TSV from your radiocarbon lab. Auto-detects columns, handles "3000±30" embedded sigma format, previews all rows, then batch-calibrates with one click.
libby/
├── src/libby/ # Python backend
│ ├── main.py # FastAPI app factory and routes
│ ├── calibration.py # iosacal integration (async, curve-resolver)
│ ├── bayesian.py # MCMC Phase/Sequence models (validated)
│ ├── kde.py # Kernel Density Estimation (Silverman's rule)
│ ├── reservoir.py # ΔR marine correction (calib.org proxy)
│ ├── crm.py # CRM report generation (PDF + DOCX)
│ ├── narrative.py # LLM + fallback narrative generation
│ ├── models.py # Pydantic schemas
│ ├── database.py # SQLite (projects, calibrations, curves, ΔR cache)
│ ├── curve_registry.py # DB-backed dynamic curve discovery
│ ├── gis.py # Curve suggestion by latitude
│ ├── spd.py # Summed Probability Distribution
│ ├── export.py # CSV/text formatters
│ ├── figures/ # Multi-chart figure generation (PDF, OxCal-style, multi-panel, KDE)
│ ├── figure.py # Backward-compat shim → figures/
│ ├── oxcal.py # OxCal CQL2 script export (forward-compatible)
│ ├── report.py # Academic PDF report generation
│ ├── importer.py # Lab report CSV/TSV parser
│ └── providers/ # LLM providers (NIM, Anthropic)
├── scripts/
│ └── ingest_curve.py # CLI tool for registering .14c curve files
├── frontend/src/ # Svelte 5 frontend
│ ├── routes/ # Pages (/, /batch, /import, /projects)
│ └── lib/ # Components (form with ΔR panel, chart, map, etc.)
├── tests/ # pytest (73 tests: 64 unit + 9 live)
├── docs/research/ # Deep research reports + risk assessments
├── Dockerfile # Multi-stage Docker build
├── docker-compose.yml # Docker deployment
└── MANIFEST.in # PyPI package manifest
This tool uses the internationally ratified calibration curves:
- IntCal20 — Northern Hemisphere terrestrial (Reimer et al. 2020)
- SHCal20 — Southern Hemisphere terrestrial (Hogg et al. 2020)
- Marine20 — Global marine (Heaton et al. 2020)
All curves are CC BY 4.0 licensed. Calibration engine: iosacal (GPLv3).
MIT License. See LICENSE for details.
If you use Libby in published research, please cite:
- IntCal20: Reimer et al. 2020, Radiocarbon 62(4)
- SHCal20: Hogg et al. 2020, Radiocarbon 62(4)
- Marine20: Heaton et al. 2020, Radiocarbon 62(4)
