Skip to main content

chartfold

Patient-facing tool for consolidating personal health data from multiple EHR (Electronic Health Record) systems into a single SQLite database. Query, analyze, and export your aggregated clinical data via CLI, MCP server (for LLM-assisted analysis), or export to Markdown, HTML, or Hugo static sites.

Goal: Patient empowerment through data ownership — enabling time-series analysis, intelligent querying with tools like Claude Code, and organized preparation for medical visits.

Features

  • Multi-EHR data consolidation — Import from Epic MyChart, MEDITECH Expanse, and athenahealth
  • SQLite database — 16 clinical tables with full audit trail
  • MCP server — 22 tools for LLM-assisted analysis with Claude
  • Export formats — Markdown, self-contained HTML with charts, Hugo static sites, JSON
  • Personal notes — Tag and annotate any clinical record
  • Visit preparation — Generate visit diffs and clinical summaries

Installation

pip install chartfold

# With MCP server support (for Claude integration)
pip install "chartfold[mcp]"

Development Setup

git clone https://github.com/queelius/chartfold.git
cd chartfold
pip install -e ".[dev,mcp]"

Quick Start

Load Data from EHR Exports

# Load from individual sources
chartfold load epic ~/exports/epic/
chartfold load meditech ~/exports/meditech/
chartfold load athena ~/exports/athena/

# Or load all at once
chartfold load all \
  --epic-dir ~/exports/epic/ \
  --meditech-dir ~/exports/meditech/ \
  --athena-dir ~/exports/athena/

Query and Inspect

# View database summary
chartfold summary

# Run SQL queries
chartfold query "SELECT test_name, value, result_date FROM lab_results ORDER BY result_date DESC LIMIT 10"

# What's new since your last visit
chartfold diff 2025-01-01

Export Your Data

# Markdown summary for your doctor (last 6 months)
chartfold export markdown --output summary.md --lookback 6

# PDF via pandoc
chartfold export markdown --output summary.pdf --pdf

# Self-contained HTML with charts
chartfold export html --output summary.html --lookback 6

# Full HTML export (all data)
chartfold export html --full --output full.html

# JSON for backup/restore
chartfold export json --output data.json

# Hugo static site
chartfold export hugo --output ./site

Personal Notes

# List recent notes
chartfold notes list --limit 20

# Search by tag or query
chartfold notes search --tag oncology --query "CEA"

# Search by reference (notes linked to specific records)
chartfold notes search --ref-table lab_results

Supported EHR Sources

Source Format Description
Epic MyChart CDA R2 XML IHE XDM exports from Epic MyChart
MEDITECH Expanse CCDA XML + FHIR JSON Dual-format bulk exports (merged and deduplicated)
athenahealth FHIR R4 XML Ambulatory summary exports

Expected Input Directory Structures

Epic:      input_dir/DOC0001.XML, DOC0002.XML, ...
MEDITECH:  input_dir/US Core FHIR Resources.json
           input_dir/CCDA/<uuid>.xml
athena:    input_dir/Document_XML/*AmbulatorySummary*.xml

Database Schema

chartfold stores data in 16 clinical tables:

Category Tables
Core patients, documents, encounters
Labs & Vitals lab_results, vitals
Medications medications, allergies
Conditions conditions
Procedures procedures, pathology_reports, imaging_reports
Notes clinical_notes
History immunizations, social_history, family_history, mental_status
System load_log (audit), notes, note_tags (personal), source_assets

All dates are stored as ISO YYYY-MM-DD strings. Every record carries a source field for provenance tracking.

MCP Server

chartfold includes an MCP (Model Context Protocol) server with 22 tools for LLM-assisted health data analysis:

chartfold serve-mcp --db chartfold.db

Available Tools

Category Tools
SQL & Schema run_sql, get_schema
Labs query_labs, get_lab_series_tool, get_available_tests_tool, get_abnormal_labs_tool
Medications get_medications, reconcile_medications_tool
Clinical get_timeline, search_notes, get_pathology_report
Analysis get_visit_diff, get_visit_prep, get_surgical_timeline
Cross-source match_cross_source_encounters, get_data_quality_report
Summary get_database_summary
Personal Notes save_note, get_note, search_notes_personal, delete_note

Claude Desktop Configuration

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "chartfold": {
      "command": "python",
      "args": ["-m", "chartfold", "serve-mcp", "--db", "/path/to/chartfold.db"]
    }
  }
}

Configuration

Generate a personalized config from your data:

chartfold init-config

This creates chartfold.toml with lab tests to chart based on what's in your database:

[[lab_tests]]
name = "CEA"
match = ["CEA", "Carcinoembryonic Antigen"]

[[lab_tests]]
name = "Hemoglobin"
match = ["Hemoglobin", "Hgb", "HGB"]

[hugo]
dashboard_recent_labs = 10

Architecture

chartfold uses a three-stage pipeline for each EHR source:

Raw EHR files (XML/FHIR)
    ↓
[Source Parser]  → source-specific dict
    ↓
[Adapter]        → UnifiedRecords (normalized dataclasses)
    ↓
[DB Loader]      → SQLite tables

Key Design Decisions

  • Idempotent loading — Re-running load for a source replaces its data
  • Cross-source deduplication — Adapters deduplicate records using composite keys
  • Date normalization — All dates normalized to ISO format at adapter stage
  • Provenance tracking — Every record tracks its source for cross-source analysis

Testing

# Run all tests (700+ tests)
python -m pytest tests/

# Run a single test file
python -m pytest tests/test_adapters.py

# Run with coverage
python -m pytest tests/ --cov=chartfold --cov-report=term-missing

Project Structure

src/chartfold/
├── sources/        # EHR-specific parsers (epic.py, meditech.py, athena.py)
├── adapters/       # Normalize to UnifiedRecords (epic_adapter.py, etc.)
├── analysis/       # Query helpers (lab_trends.py, medications.py, etc.)
├── extractors/     # Specialized parsers (labs.py, pathology.py)
├── core/           # Shared utilities (cda.py, fhir.py, utils.py)
├── formatters/     # Output formatters (markdown.py)
├── hugo/           # Hugo site generator (generate.py)
├── mcp/            # MCP server (server.py)
├── db.py           # Database interface
├── models.py       # Dataclass models
├── config.py       # Configuration management
├── cli.py          # Command-line interface
├── export.py       # Markdown export
├── spa/            # HTML SPA export with embedded SQLite (sql.js)
└── export_full.py  # Full JSON/markdown export

Adding a New EHR Source

  1. Create sources/newsource.py with process_*_export(input_dir) returning a dict
  2. Create adapters/newsource_adapter.py with *_to_unified(data) -> UnifiedRecords
  3. Add a SourceConfig in sources/base.py
  4. Wire into cli.py (add subcommand)
  5. Add tests in tests/

Requirements

  • Python 3.11+ (uses tomllib from stdlib)
  • Dependencies: lxml, mcp (optional)
  • Optional: pandoc for PDF export, hugo for static site generation

License

MIT

Release files for chartfold 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for chartfold 1.1.0
File Size Uploaded
chartfold-1.1.0.tar.gz 4.0 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for chartfold 1.1.0
File Interpreter ABI Platform
chartfold-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 4.5 MB

Release files / chartfold-1.1.0.tar.gz

Download URL chartfold-1.1.0.tar.gz
Size 4.0 MB
Tags Source
SHA-256 checksum
How to use checksums
45bbb6106d4fd4ba569155286dd75ad3d2a759a2e4e532250d745f99b2a98182
BLAKE2b-256 checksum
How to use checksums
b1999fdc029aa94e63562dedb3421bc31046c9557129aef814863a3c2c32d1d5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.3

Release files / chartfold-1.1.0-py3-none-any.whl

Download URL chartfold-1.1.0-py3-none-any.whl
Size 497.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e2cfe0a75282c5c9b6eebf5310989db63d4f42859cc58933f5b44c20c4eaf23a
BLAKE2b-256 checksum
How to use checksums
5caee4bc71ee9045f1b94125a9ac105604af2298167393e5ba7718fcfcab2613
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page