HealthChain v0.16.0
Agents are already good at reading clinical data β a model with a bundle in context can parse and summarize it without much help. Writing it is a different job. Clinical data has a bar that generic agent frameworks don't check: not just schema-valid, but the right code from the right system, on the right patient, with a status that means what you think it means. That write boundary is where healthcare AI earns trust, and it's what this release is about.
π€ FHIRToolkit β typed FHIR tools for agents
One toolkit, eight tools β build, validate, read, resolve, and code FHIR β served to whatever runs your agent:
from healthchain.tools import FHIRToolkit
kit = FHIRToolkit(bundle="patient_bundle.json")
kit.as_mcp().run() # serve to Claude or any MCP client
tools = kit.as_langchain() # or drop into a LangChain agentOr straight from the terminal, no code:
healthchain mcp --bundle patient_bundle.jsonEvery tool takes typed arguments and returns validated FHIR β when an agent writes something broken, it gets back a structured report of everything wrong, not a stack trace.
β¨ Highlights
FHIRToolkitβ agent tools for FHIR (#240, #244, #245, #246, #247). Build, validate, read, and code FHIR resources as typed agent tools:kit.as_mcp().run()serves them to Claude or any MCP client,kit.as_langchain()drops them into a LangChain agent, andhealthchain mcp --bundle patient_bundle.jsondoes it from the terminal with no code.- Validation as data (#240):
validate_resourcereturns aValidationReport(never raises) for agent build-validate-correct loops;load_bundlegives a single rich exception for loaders. - FHIR reading and referencing (#245):
resolve_reference(contained/fullUrl/urn:uuid/Type-id, never raises),get_coded_entries/get_medicationsreaders,create_dosage,onsetoncreate_condition. - Terminology lookup seam (#244):
LocalCodeLookup+ a runtime-checkableTerminologyLookupprotocol β agents use returned codes, never invented ones. - Lean core (#254β#257): spaCy, pandas, NumPy, python-liquid, xmltodict, Jinja2, and Faker are no longer core dependencies. Fresh-install footprint drops accordingly, and
import healthchainpulls none of them. - Extras architecture:
[mcp](MCP server),[langchain](LangChain views),[cda](CDA interop / NoteReader),[sandbox](synthetic test-data generators),[examples](run the NLP/ML cookbooks). - llms.txt: the docs site now publishes
llms.txtandllms-full.txtfor AI agents and assistants.
π₯ Breaking changes & migration
Every removed name below raises a guiding ImportError naming its replacement. These tombstones ship through 0.16.x and are removed in 0.17 β update imports now, don't rely on them. (The lazy guards for the [cda]/[langchain]/[sandbox]/[mcp] extras are permanent and idiomatic β a missing extra tells you the install line.)
| Removed | Migrate to |
|---|---|
ML feature layer: Dataset, FeatureSchema, FHIRFeatureMapper, BaseMapper, bundle_to_dataframe, TimeWindow, ValidationResult (pandas/NumPy out of core) |
Extract features with your own pandas code; convert predictions with create_risk_assessment_from_prediction β see the ml_risk_to_fhir cookbook |
NLP/LLM wrappers & routing: SpacyNLP, HFTransformer, LangChainLLM, ModelRouter, ModelRoutingMixin, ModelSource, ModelConfig, and the Pipeline.load / from_model_id / from_local_model / configure_pipeline classmethods (not tombstoneable β named here explicitly) |
Load models with the library you already use (spacy.load, transformers.pipeline, your LangChain chain) and wrap them with pipeline.add_node(...) |
Prebuilt pipelines: MedicalCodingPipeline, SummarizationPipeline, CdsCardCreator |
Copy a cookbook recipe: clinical coding, discharge summarizer β every step visible in ~20 lines |
DataContainer and Pipeline[T] generics |
Pipeline() (no subscript); Document is the container; raw input (str, Bundle, resource list) auto-wraps into a Document |
Document NLP surface: doc.nlp / NlpAnnotations, doc.models / ModelOutputs, word_count, update_problem_list_from_nlp |
doc.update_problem_list(entities, patient_ref=...) with explicit entity dicts ({"text": ..., "cui": ...}); patient_ref is required β the pipeline never guesses the patient |
Components: TextPreProcessor, TextPostProcessor, FHIRProblemListExtractor |
A plain function that takes and returns a Document, added with add_node |
| CDA interop in core | pip install "healthchain[cda]" β CdaAdapter, InteropEngine, and NoteReader need the extra; core imports of them raise a guiding error with the install line |
HL7v2 stubs (FormatType.HL7V2, parser/generator branches) |
Removed without replacement β both directions were NotImplementedError placeholders that never worked. CDA β FHIR is the supported interop path |
CDA allergy residue (filters, generator branches, severity_codes.yaml) |
Removed β bundled CDA configs cover problems, medications, and notes; unconfigured sections now log a warning naming the section and are skipped |
| Synthetic data generators in core (Faker) | pip install "healthchain[sandbox]" for load_free_text() / load_synthetic() |
LLMConfig.to_langchain() |
langchain.chat_models.init_chat_model(...) directly |
Dead code (#248, folded in): the healthchain.use_cases deprecation shim (already broken β its target module never existed), utils.search_key_breadth_first, print_supported_resources, 0-byte hook/wsgi stubs |
Removed without replacement β none of it worked or was called |
Behavior changes (landed via #245, #241):
create_medication_statementdefault status is now"unknown"(was"recorded", which is R5 vocabulary and spec-invalid on R4B) β passstatus="recorded"explicitly if you relied on it.create_*helpers no longer invent clinical timestamps; fields likeeffectiveDateTimestay unset unless you pass them.CodedEntry.dateβCodedEntry.authored_on.LLMConfig/ scaffold default model is nowclaude-opus-4-8(was the staleclaude-opus-4-6); docs and cookbook examples updated to match.- Helpers log a warning (never raise) when a built resource contains a code outside a required binding.
Dependency floor changes (#250): pydantic<3 (was <2.11), uvicorn>=0.31.1, mcp>=1.28; JWT auth migrated from python-jose to PyJWT.
π Docs
- Every cookbook rewritten against the 0.16 API and smoke-tested end-to-end; new research extract β validated FHIR API recipe for moving research-database extracts onto a live, validated FHIR API.
llms.txt/llms-full.txtpublished; docs nav gained Core Concepts; broken-link/anchor validation now fails the docs build.
What's Changed (full PR list)
- feat(fhir): validation spine β validate_resource, load_bundle, ValidationReport by @jenniferjiangkells in #240
- feat(terminology): terminology lookup seam with LocalCodeLookup by @jenniferjiangkells in #244
- feat(fhir): land stacked changes from #241, #242, #243 by @jenniferjiangkells in #245
- docs: document the agent-toolkit surface (validation, readers, terminology) by @jenniferjiangkells in #246
- feat(tools): agent tool layer β FHIRToolkit with MCP and LangChain views by @jenniferjiangkells in #247
- fix(deps): bump pydantic/uvicorn/mcp pins and migrate JWT auth to PyJWT by @jenniferjiangkells in #250
- docs: feature cards, quickstart streamlining by @jenniferjiangkells in #251
- refactor(slim): remove ML feature cluster; reconceive ML-deployment cookbook by @jenniferjiangkells in #254
- refactor(slim): de-wrapper pipeline β pure Document-centric primitives by @jenniferjiangkells in #255
- refactor(slim): move CDA interop behind [cda] extra; remove allergy residue by @jenniferjiangkells in #256
- refactor(slim): finalize extras architecture; rewrite cookbooks against the 0.16 API by @jenniferjiangkells in #257
- refactor(slim): docs alignment, llms.txt, tidy by @jenniferjiangkells in #258
- build(deps): bump pip from 26.1 to 26.1.2 in the uv group across 1 directory by @dependabot[bot] in #252
Full Changelog: 0.15.0...0.16.0