Get started

From clone to a routed message in five minutes

MessageFoundry installs from source and runs locally. You'll need Python 3.11+ and git. The engine serves a localhost API; the console and editor tooling attach to it.

Use synthetic data. The sample generators and dry-run output can contain full message bodies — only ever run them against synthetic, PHI-free HL7.

Clone and install

Create a virtual environment and install the package (with the dev extras) in editable mode.

terminal
# clone
git clone https://github.com/wshallwshall/MessageFoundry.git
cd MessageFoundry

# virtual environment
python -m venv .venv
# macOS / Linux:   . .venv/bin/activate
# Windows (PS):    .venv\Scripts\Activate.ps1

pip install -e ".[dev]"

Run the engine

Load the sample config, open the store, and serve the localhost API on 127.0.0.1:8765.

terminal
python -m messagefoundry serve --config samples/config --db messagefoundry.db

# API on http://127.0.0.1:8765
#   GET /connections   GET /messages   GET /stats   WS /ws/stats

Send a test message

The sample config's IB_Test_ADT listens for MLLP on port 2575. Send it an ADT and watch it route.

terminal
python samples/send_mllp.py samples/messages/adt_a01.hl7

# A01/A04/A08 → archived to ./out/adt/<MSH-10>.hl7
# other events → logged FILTERED; non-ADT → logged UNROUTED

Open the admin console

A separate PySide6 process that attaches to the API — dashboard, message browser, parse-tree viewer, and replay.

terminal
pip install -e ".[console]"
python -m messagefoundry.console --url http://127.0.0.1:8765

Author your own route

Drop a Python module into your config directory. Name an inbound and outbound Connection, then wire a Router and Handler by name.

config/IB_Lab_ORU.py
from messagefoundry import MLLP, Send, inbound, outbound, router, handler

inbound("IB_Lab_ORU", MLLP(port=2580), router="oru_router")
outbound("OB_EHR_ORU", MLLP(host="10.0.0.21", port=6661))

@router("oru_router")
def route(msg):
    if msg["MSH-9.1"] != "ORU":
        return []                    # UNROUTED
    return ["to_ehr"]

@handler("to_ehr")
def to_ehr(msg):
    if msg["OBR-25"] == "X":       # drop corrected-in-error
        return None                  # FILTERED
    return Send("OB_EHR_ORU", msg)

Validate it before it ships with the commit gate:

terminal
python -m messagefoundry check --config samples/config

Go deeper

The full documentation lives in the repository.