An AI teammate for the HL7/FHIR integration engineer. Paste a broken message, get a root cause. Paste a batch of samples from a new trading partner, get an interface spec and a draft transformer. Paste a legacy v2 interface, get a FHIR migration plan.
MIT licensed. TypeScript on Bun. Runs fully local by default β no PHI leaves your machine.
β οΈ integrator is not itself a HIPAA-covered product. It's a tool for integration engineers, shipped AS-IS under the MIT license with no warranty (see LICENSE). Every output is a draft for a human to review, never auto-applied to a production interface. Compliance with HIPAA, GDPR, and your employer's security posture is your responsibility.
git clone https://github.com/toddegray/integrator
cd integrator
bun install
bun run src/cli.ts init # interactive; writes ~/.integrator/config.json
bun run src/cli.ts seed # load 10 publicly-cited spec gotchas into memoryRequires Bun 1.1+. That's it β no Docker,
no database server, no cloud account. The whole thing is one SQLite file at
~/.integrator/data/integrator.db.
To compile a standalone executable: bun run build β ./bin/integrator.
# Diagnose a malformed ADT
bun run src/cli.ts diagnose --file examples/fixtures/adt-a01-missing-msh12.hl7 --vendor epic
# Translate v2 β FHIR
bun run src/cli.ts translate --file examples/fixtures/oru-r01.hl7 --format bundle
# Validate strictly
bun run src/cli.ts validate --file examples/fixtures/observation-missing-code.json
# Explain a segment
bun run src/cli.ts explain PID-3
# Web UI β paste, click, done
bun run src/cli.ts web # http://127.0.0.1:4321All eleven skills ship with the repo. Every fixture under examples/fixtures/
is real, runnable, and included in the test suite.
integrator is one executable that wraps eleven deterministic skills:
| Skill | What it does |
|---|---|
diagnose |
Root-cause analysis on a malformed / rejected HL7 v2 message. Applies vendor-quirk memory. |
translate |
HL7 v2 β FHIR R4/R5 (both directions). Z-segments preserved as FHIR extensions. |
validate |
Strict v2 parse + structure + FHIR cardinality/reference/primitive checks. |
explain-segment |
Plain-English explanation of any segment / field / code with spec citations. |
synthesize |
PHI-safe synthetic HL7 v2 test data, reproducible by seed. |
diff-specs |
Compare two interface specs; flag breaking changes. |
map-interfaces |
Field-by-field mapping between sender and receiver. |
onboard-interface |
Infer a spec from a batch of samples. Detects message mix, version drift, Z-segments. |
generate-transformer |
Draft code for Mirth, Iguana, Cloverleaf, Rhapsody, Corepoint, generic JS, or generic Python. |
migrate-to-fhir |
End-to-end migration plan: resource mapping, Z-segment strategy, phased rollout. |
batch-report |
Run diagnose+validate across a directory; consolidated report. |
And one natural-language entrypoint:
ask |
Give it a question in English. Claude picks the right skill(s) and composes. Requires cloud inference opt-in. |
Four layers. Each one is small and replaceable.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Surfaces (src/cli.ts, src/mcp/, src/web/, src/agents/) β
β CLI Β· stdio MCP server Β· paste-and-go web UI Β· ask agent β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Skills (src/skills/*) β
β Pure functions. Return Brief<T> = { data, citations, md }. β
β No hidden I/O. Tested in isolation. β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Core (src/core/hl7.ts, fhir.ts, vendors.ts, config.ts) β
β HL7 v2 parser Β· FHIR validator Β· vendor/version metadata. β
β Zero dependencies on anything higher up. β
ββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββ
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Memory (src/db/*) β
β SQLite (bun:sqlite) with a Statement cache. β
β Nine tables: entities, briefs, vendor_quirks, β¦ β
β Everything stays on your machine. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Skills are pure. Every skill takes structured input and returns a
Brief<T>:
interface Brief<T> {
skill: string;
schema_version: number;
entity: EntityId; // kind + id + display
generated_at: string; // ISO-8601
data: T; // deterministic structured payload
citations: Citation[]; // every claim links to HL7.org / FHIR spec
markdown: string; // rendered report
}The data and citations fields are reproducible β same input, same output,
byte-for-byte. The markdown can be LLM-enhanced via Ollama; the structured
payload never is.
Memory is the moat. Every time you run a skill, what integrator learned goes into SQLite: vendor quirks, Z-segments seen in the wild, trading-partner notes, local-code mappings. The second diagnosis of an Epic ADT quirk is better than the first. After a month of real traffic, integrator knows your environment better than a new hire could in six months.
Local-first by default. The CLI, MCP server, and web UI don't require
network access. Ollama provides optional local LLM narrative. Anthropic or
OpenAI cloud inference is off by default; you opt in via integrator init --enable-cloud, and when on, PHI redaction (src/inference/redact.ts) runs
before any outbound call.
$ bun run src/cli.ts diagnose --file examples/fixtures/adt-a01-missing-msh12.hl7 --vendor epic# diagnose β ADT^A01
**Message type:** ADT^A01
**Version:** (empty)
**Sending app:** DEMO_SENDER
**Receiving app:** DEMO_RECEIVER
**Vendor:** epic (3 quirks matched)
## Root causes (1)
### 1. MSH-12 (Version ID) is empty; many receivers assume 2.3 and reject higher-version payloads
_Confidence: medium Β· Code: MSH.12_MISSING_
**Suggested fix**
Populate MSH-12 with the HL7 version, e.g. `2.5.1`.
Run it again after you record a vendor-specific quirk, and the second diagnosis surfaces that too.
$ bun run src/cli.ts translate --file examples/fixtures/oru-r01.hl7 --format bundle{
"resourceType": "Bundle",
"type": "collection",
"entry": [
{ "resource": { "resourceType": "Patient", "name": [{"family":"LOVELACE","given":["ADA"]}], β¦ } },
{ "resource": { "resourceType": "DiagnosticReport", "code": { β¦ LOINC 24323-8 β¦ }, "result": [...] } },
{ "resource": { "resourceType": "Observation", "code": { β¦ Sodium LOINC β¦ }, "valueQuantity": {"value": 140, "unit": "mmol/L"} } }
// β¦
]
}Both directions work. --direction fhir-to-v2 takes a FHIR Bundle and
infers the trigger (ADT^A01 / ORU^R01 / ORM^O01).
$ bun run src/cli.ts validate --file examples/fixtures/observation-missing-code.json# validate β Observation/obs-no-code
**Verdict:** invalid
**Findings:**
- [error] FHIR.MISSING_REQUIRED_FIELD β Observation.code is required but missing
Exit code 1 if invalid, so you can wire it into CI.
$ bun run src/cli.ts onboard --dir ./partner-samples --partner memorial-regional --vendor epicReads every .hl7 file in the directory, infers the interface spec
(message-type mix, version mix, Z-segments, field population rates), and
records what it saw into memory. Run integrator batch --dir ./partner-samples
afterwards for a consolidated diagnose+validate report.
$ bun run src/cli.ts generate-transformer \
--engine mirth \
--sender examples/fixtures/adt-a01.hl7 \
--receiver examples/fixtures/adt-a04-register.hl7 \
--label memorial-adt \
--output code// integrator-generated mirth transformer β review before deploying.
// Interface: memorial-adt
// Do not commit as-is; treat this as a starting point.
tmp['MSH']['MSH.3'] = msg['MSH']['MSH.3'];
tmp['MSH']['MSH.9'] = msg['MSH']['MSH.9'];
tmp['PID']['PID.3'] = msg['PID']['PID.3'];
tmp['PID']['PID.5'] = msg['PID']['PID.5'];
// β¦Also supports iguana, cloverleaf, rhapsody, corepoint,
generic-js, generic-py.
# You just figured out an Epic quirk. Save it so every future diagnose sees it.
bun run src/cli.ts quirks record --vendor epic --segment PID --field 3 --component 5 \
--behavior "uses PID-3.5 for MRN even though spec says PID-3.4" \
--citation "https://hl7-definition.caristix.com/v2/HL7v251/Fields/PID.3"
# Tag a trading partner with notes
bun run src/cli.ts partners add --id memorial-regional \
--vendor epic --notes "primary contact: Rhonda K. Β· prefers EDI cutover Fridays"
# See what you've accumulated
bun run src/cli.ts quirks # vendor quirks
bun run src/cli.ts partners # trading partners
bun run src/cli.ts quirks z-segments # custom Z-segments seen in the wild
bun run src/cli.ts recall # every brief ever generated| Surface | Command | Use |
|---|---|---|
| CLI | integrator <skill> |
Terminal-first, pipeable, scriptable |
| Web UI | integrator web |
Paste-and-go at http://127.0.0.1:4321 |
| Batch | integrator batch --dir <path> |
Run diagnose+validate across an inbox |
| MCP | integrator mcp |
stdio server for Claude Code, Claude Desktop, Cursor |
ask |
integrator ask "why β¦?" |
Natural language (needs cloud inference on) |
Add this to your MCP client config:
{
"integrator": {
"command": "bun",
"args": ["run", "/absolute/path/to/integrator/src/mcp/server.ts"]
}
}Every skill is exposed as a tool. Claude picks the right one and composes them for you.
A single SQLite file at ~/.integrator/data/integrator.db with nine tables:
- entities Β· messages, resources, bundles, interfaces, trading partners, vendors, Z-segments, code systems
- briefs Β· the latest output of every skill per entity
- vendor_quirks Β· observed behaviors per vendor / message-type / field; grows with use
- version_diffs Β· HL7 v2 version-over-version changes
- trading_partners Β· your specific partners + their quirks
- z_segments Β· every custom Z* segment encountered
- code_mappings Β· local codes β LOINC / SNOMED / RxNorm / ICD-10
- annotations Β· free-form notes on any entity
- user_context Β· your stack (engine, EMR, default versions)
Back up with:
sqlite3 ~/.integrator/data/integrator.db "VACUUM INTO '~/.integrator/backups/integrator-$(date +%F).db'"See docs/OPERATING.md for the full operating manual.
The existing FHIR MCP servers are data-access layers for building new apps β they don't help the integration engineer who's already running v2 traffic between legacy systems. integrator focuses on that work: diagnosis, translation, validation, transformer scaffolding, migration planning β all driven by a memory layer that learns the quirks of your specific environment as you use it.
- Local-first. No PHI leaves the machine unless the user explicitly opts into cloud inference.
- Public specs only. HL7.org, FHIR R4/R5, IHE, US Core, CARIN, Da Vinci, SMART Health IT, Synthea. No proprietary vendor documentation ingested.
- Every claim cites a spec. Narrative output links to HL7.org, the FHIR spec, or an IHE profile. Hallucinated segment definitions are unshippable.
- Reproducible. Same input, same structured output, byte-identical.
- User-settable config. Every knob goes through
integrator init. Env vars are the escape hatch, not the front door. - Vendor-agnostic code paths. No hard-coded Epic / Cerner / MEDITECH branches. Vendor quirks live as data in the memory layer, observed from user traffic.
- Outputs are drafts. The tool never auto-applies a transformer to a production interface.
- No clinical reasoning. integrator handles data about messages, not patient-level clinical logic.
src/
cli.ts entry point; dispatches to cli/*
cli/ one file per command
skills/ one file per skill (pure functions)
core/ HL7 parser, FHIR validator, config, types
db/ bun:sqlite engine + schema + typed repos
inference/ Ollama client + PHI redaction
mcp/ stdio MCP server
web/ Bun HTTP server + single-page UI
agents/ ask orchestrator (Anthropic SDK + prompt caching)
seeds/ curated starter vendor quirks
examples/
fixtures/ runnable HL7 + FHIR samples
*.md committed example briefs
test/ 64 passing tests (bun test)
docs/ ARCHITECTURE, OPERATING, DEMO
v1.0.0. 11 skills, 5 surfaces, 64 tests passing. See
CHANGELOG.md for what's in and what's known-thin. CI at
.github/workflows/ci.yml runs tsc, bun test,
and bun run build on every push.
Real feedback from integration engineers is what will make the memory layer compound. Issues and PRs welcome.
MIT.
