{"id":47818633,"url":"https://github.com/queelius/chartfold","last_synced_at":"2026-04-03T18:59:58.599Z","repository":{"id":338742634,"uuid":"1150351161","full_name":"queelius/chartfold","owner":"queelius","description":"Patient-facing tool for consolidating personal health data from multiple EHR systems into a single SQLite database","archived":false,"fork":false,"pushed_at":"2026-02-24T20:36:05.000Z","size":1012,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-25T00:41:32.304Z","etag":null,"topics":["cda","ehr","epic","fhir","health-data","longecho-ecosystem","medical-records","meditech","personal-health","python","sqlite"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/queelius.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-05T07:08:40.000Z","updated_at":"2026-02-24T23:20:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/queelius/chartfold","commit_stats":null,"previous_names":["queelius/chartfold"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/queelius/chartfold","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queelius%2Fchartfold","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queelius%2Fchartfold/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queelius%2Fchartfold/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queelius%2Fchartfold/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/queelius","download_url":"https://codeload.github.com/queelius/chartfold/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queelius%2Fchartfold/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31371564,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T17:53:18.093Z","status":"ssl_error","status_checked_at":"2026-04-03T17:53:17.617Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cda","ehr","epic","fhir","health-data","longecho-ecosystem","medical-records","meditech","personal-health","python","sqlite"],"created_at":"2026-04-03T18:59:55.215Z","updated_at":"2026-04-03T18:59:58.594Z","avatar_url":"https://github.com/queelius.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chartfold\n\nPatient-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 self-contained HTML SPA.\n\n**Goal:** Patient empowerment through data ownership — enabling time-series analysis, intelligent querying with tools like Claude Code, and organized preparation for medical visits.\n\n## Features\n\n- **Multi-EHR data consolidation** — Import from Epic MyChart, MEDITECH Expanse, and athenahealth\n- **SQLite database** — 17 clinical tables with full audit trail\n- **MCP server** — 25 tools for LLM-assisted analysis with Claude\n- **Export formats** — Self-contained HTML SPA, Arkiv (JSONL + README.md + schema.yaml)\n- **AI chat** — Ask questions about your record in the HTML SPA via Claude, with inline charts (optional, requires proxy)\n- **Visit prep** — See what's new since your last visit, directly in the SPA\n- **Print summary** — One-page printable view for your doctor\n- **Personal notes** — Tag and annotate any clinical record\n\n## Installation\n\n```bash\npip install chartfold\n\n# With MCP server support (for Claude integration)\npip install \"chartfold[mcp]\"\n```\n\n### Development Setup\n\n```bash\ngit clone https://github.com/queelius/chartfold.git\ncd chartfold\npip install -e \".[dev,mcp]\"\n```\n\n## Quick Start\n\n### Load Data from EHR Exports\n\n```bash\n# Load from individual sources\nchartfold load epic ~/exports/epic/\nchartfold load meditech ~/exports/meditech/\nchartfold load athena ~/exports/athena/\n\n# Or load all at once\nchartfold load all \\\n  --epic-dir ~/exports/epic/ \\\n  --meditech-dir ~/exports/meditech/ \\\n  --athena-dir ~/exports/athena/\n```\n\n### Query and Inspect\n\n```bash\n# View database summary\nchartfold summary\n\n# Run SQL queries\nchartfold query \"SELECT test_name, value, result_date FROM lab_results ORDER BY result_date DESC LIMIT 10\"\n\n# What's new since your last visit\nchartfold diff 2025-01-01\n```\n\n### Export Your Data\n\n```bash\n# Self-contained HTML SPA with embedded SQLite (all data stays client-side)\nchartfold export html --output summary.html\nchartfold export html --output summary.html --embed-images --config chartfold.toml\nchartfold export html --output summary.html --ai-chat --proxy-url https://proxy.example.com/v1/messages\n\n# Arkiv universal record format — primary backup/restore (round-trip capable)\nchartfold export arkiv --output ./arkiv/\nchartfold export arkiv --output ./arkiv/ --embed          # inline base64 assets\nchartfold export arkiv --output ./arkiv/ --exclude-notes\n\n# Import from arkiv archive\nchartfold import ./arkiv/ --db new_chartfold.db\nchartfold import ./arkiv/ --validate-only\nchartfold import ./arkiv/ --db existing.db --overwrite\n```\n\n### AI Chat (Optional)\n\nThe HTML SPA export can include an AI chat interface that lets you ask natural-language questions about your medical record. The LLM runs SQL queries against the embedded database — all patient data stays in your browser.\n\n```bash\nchartfold export html --output summary.html --ai-chat --proxy-url https://proxy.example.com/v1/messages\n```\n\nRequirements:\n- A CORS proxy that forwards requests to the Anthropic Messages API (injects your API key and sets the model server-side)\n- The proxy URL can also be configured in the SPA via the \"Proxy settings\" link\n\nThe system prompt includes the full database schema, summary statistics, and any analyses marked `status: \"current\"` in their frontmatter. The chat interface supports multi-turn conversation with an agent loop — the LLM can issue multiple SQL queries per question and render inline charts for trend visualization.\n\n### Visit Prep\n\nThe SPA includes a \"Visit Prep\" section that auto-detects your most recent encounter date and shows everything new since then: lab results, encounters, medications, imaging, clinical notes, conditions, procedures, pathology, and genetic variants. The date is editable for custom ranges.\n\n### Print Summary\n\nThe \"Print Summary\" section generates a one-page printable view with patient demographics, active conditions, active medications, recent labs with trend indicators, and last 3 encounters. Click \"Print\" or use Ctrl+P to print or save as PDF.\n\n### Personal Notes\n\n```bash\n# List recent notes\nchartfold notes list --limit 20\n\n# Search by tag or query\nchartfold notes search --tag oncology --query \"CEA\"\n\n# Search by reference (notes linked to specific records)\nchartfold notes search --ref-table lab_results\n```\n\n## Supported EHR Sources\n\n| Source | Format | Description |\n|--------|--------|-------------|\n| **Epic MyChart** | CDA R2 XML | IHE XDM exports from Epic MyChart |\n| **Epic MyChart (MHTML)** | MHTML | Visit notes and genomic test results (e.g., Tempus XF) |\n| **MEDITECH Expanse** | CCDA XML + FHIR JSON | Dual-format bulk exports (merged and deduplicated) |\n| **athenahealth** | FHIR R4 XML | Ambulatory summary exports |\n\n### Expected Input Directory Structures\n\n```\nEpic:      input_dir/DOC0001.XML, DOC0002.XML, ...\nMEDITECH:  input_dir/US Core FHIR Resources.json\n           input_dir/CCDA/\u003cuuid\u003e.xml\nathena:    input_dir/Document_XML/*AmbulatorySummary*.xml\n```\n\n## Database Schema\n\nchartfold stores data in 17 clinical tables:\n\n| Category | Tables |\n|----------|--------|\n| **Core** | `patients`, `documents`, `encounters` |\n| **Labs \u0026 Vitals** | `lab_results`, `vitals` |\n| **Medications** | `medications`, `allergies` |\n| **Conditions** | `conditions` |\n| **Procedures** | `procedures`, `pathology_reports`, `imaging_reports` |\n| **Genomics** | `genetic_variants` |\n| **Notes** | `clinical_notes` |\n| **History** | `immunizations`, `social_history`, `family_history`, `mental_status` |\n| **System** | `load_log` (audit), `notes`, `note_tags` (personal), `source_assets`, `analyses`, `analysis_tags` |\n\nAll dates are stored as ISO `YYYY-MM-DD` strings. Every record carries a `source` field for provenance tracking.\n\n## MCP Server\n\nchartfold includes an MCP (Model Context Protocol) server with 25 tools for LLM-assisted health data analysis:\n\n```bash\nchartfold serve-mcp --db chartfold.db\n```\n\n### Available Tools\n\n| Category | Tools |\n|----------|-------|\n| **SQL \u0026 Schema** | `run_sql`, `get_schema`, `get_database_summary` |\n| **Labs** | `query_labs`, `get_lab_series_tool`, `get_available_tests_tool`, `get_abnormal_labs_tool` |\n| **Medications** | `get_medications`, `reconcile_medications_tool` |\n| **Clinical** | `get_timeline`, `search_notes`, `get_pathology_report` |\n| **Visit Prep** | `get_visit_diff`, `get_visit_prep`, `get_surgical_timeline` |\n| **Cross-source** | `match_cross_source_encounters`, `get_data_quality_report` |\n| **Source Assets** | `get_source_files`, `get_asset_summary` |\n| **Personal Notes** | `save_note`, `get_note`, `search_notes_personal`, `delete_note` |\n| **Analyses** | `save_analysis`, `get_analysis`, `search_analyses`, `list_analyses`, `delete_analysis` |\n\nClinical data is read-only (`?mode=ro` enforced at the SQLite engine level). Write operations are limited to personal notes and structured analyses.\n\n### Claude Code Configuration\n\nDrop a `.mcp.json` in any directory where you run Claude Code:\n\n```json\n{\n  \"mcpServers\": {\n    \"chartfold\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"chartfold\", \"serve-mcp\", \"--db\", \"/path/to/chartfold.db\"]\n    }\n  }\n}\n```\n\n### Claude Desktop Configuration\n\nAdd to your `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"chartfold\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"chartfold\", \"serve-mcp\", \"--db\", \"/path/to/chartfold.db\"]\n    }\n  }\n}\n```\n\n## Configuration\n\nGenerate a personalized config from your data:\n\n```bash\nchartfold init-config\n```\n\nThis creates `chartfold.toml` with lab tests to chart based on what's in your database:\n\n```toml\n[[lab_tests]]\nname = \"CEA\"\nmatch = [\"CEA\", \"Carcinoembryonic Antigen\"]\n\n[[lab_tests]]\nname = \"Hemoglobin\"\nmatch = [\"Hemoglobin\", \"Hgb\", \"HGB\"]\n```\n\n## Architecture\n\nchartfold uses a three-stage pipeline for each EHR source:\n\n```\nRaw EHR files (XML/FHIR)\n    ↓\n[Source Parser]  → source-specific dict\n    ↓\n[Adapter]        → UnifiedRecords (normalized dataclasses)\n    ↓\n[DB Loader]      → SQLite tables\n```\n\n### Key Design Decisions\n\n- **Idempotent loading** — Re-running `load` for a source replaces its data\n- **Cross-source deduplication** — Adapters deduplicate records using composite keys\n- **Date normalization** — All dates normalized to ISO format at adapter stage\n- **Provenance tracking** — Every record tracks its source for cross-source analysis\n\n## Testing\n\n```bash\n# Run all tests (1120+ tests)\npython -m pytest tests/\n\n# Run a single test file\npython -m pytest tests/test_adapters.py\n\n# Run with coverage\npython -m pytest tests/ --cov=chartfold --cov-report=term-missing\n```\n\n## Project Structure\n\n```\nsrc/chartfold/\n├── sources/        # EHR-specific parsers (epic.py, meditech.py, athena.py, mhtml_*.py)\n├── adapters/       # Normalize to UnifiedRecords (epic_adapter.py, etc.)\n├── analysis/       # Query helpers (lab_trends.py, medications.py, etc.)\n├── extractors/     # Specialized parsers (labs.py, pathology.py)\n├── core/           # Shared utilities (cda.py, fhir.py, utils.py)\n├── mcp/            # MCP server (server.py)\n├── spa/            # HTML SPA export with embedded SQLite (sql.js) and optional AI chat\n├── db.py           # Database interface\n├── models.py       # Dataclass models\n├── config.py       # Configuration management\n├── cli.py          # Command-line interface\n├── export_arkiv.py # Arkiv export (JSONL + README.md + schema.yaml)\n└── import_arkiv.py # Arkiv import with validation and FK remapping\n```\n\n## Adding a New EHR Source\n\n1. Create `sources/newsource.py` with `process_*_export(input_dir)` returning a dict\n2. Create `adapters/newsource_adapter.py` with `*_to_unified(data) -\u003e UnifiedRecords`\n3. Add a `SourceConfig` in `sources/base.py`\n4. Wire into `cli.py` (add subcommand)\n5. Add tests in `tests/`\n\n## Requirements\n\n- Python 3.11+ (uses `tomllib` from stdlib)\n- Dependencies: `lxml`, `pyyaml`\n- Optional: `mcp` (FastMCP) for MCP server\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqueelius%2Fchartfold","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqueelius%2Fchartfold","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqueelius%2Fchartfold/lists"}