Site Training, Integration, Transfer, and Collaborative Harmonization.
Federated AI/ML training across CLIF consortium sites that coordinate through a shared storage object (Azure Blob) instead of a live server — so participating hospitals need only outbound HTTPS to one container, no inbound firewall rules or hosted coordinator.
STITCH is the communication + file-sync + logging layer. It moves two files per pass (an
opaque model.<ext> + a fixed metrics.json) between a local mirror and the blob, hashes the
bytes, and returns a Status. It never opens a model. You supply two hooks — train and
aggregate — and STITCH drives the federated loop around them. See docs/ for the
full design (DESIGN · FLOW · SCAFFOLD).
📖 Read the docs site → — function reference, flow diagrams, and a step-by-step how-to guide (how a run is made in the blob, how models pass & retrieve, and failure & revival).
uv add clif-stitch # core (localfs backend, runs fully offline)
uv add 'clif-stitch[azure]' # + Azure Blob backend for productionFor a real multi-site run on Azure (no CLI needed; lead mints a full token, sites get a
limited no-delete token), see docs/AZURE.md.
uv run clif-stitch init # scaffold project/ + stitch.lead.yaml here
# edit project/train.py, project/aggregate.py, project/data.py
uv run clif-stitch launch --config stitch.lead.yaml # create the run
uv run clif-stitch gen-configs --config stitch.lead.yaml --out ./dist # per-site configs
uv run clif-stitch run --config ./dist/stitch.lead-run.yaml # lead: train + aggregate
uv run clif-stitch run --config ./dist/stitch.site.UCMC.yaml # a local site
uv run clif-stitch status --config stitch.lead.yaml # pass/phase + per-site stateA complete runnable example is in examples/synthetic/ (3 sites, FedAvg
logistic regression on generated data — no PHI, no Azure).
You write plain functions that read/write model files at the paths STITCH hands them:
def train(global_path, out_path, data_dir): # runs on every site, every pass
model = load(global_path) if global_path else fresh_model() # global_path is None on pass 0
model.fit(load_cohort(data_dir)) # YOUR data never leaves the site
save(model, out_path)
return {"n_samples": n, "auc": auc} # n_samples REQUIRED; the rest is free
def aggregate(site_dir, out_path): # lead only, once per pass
save(fedavg(read_models(site_dir)), out_path)
return {"n_samples": total} # optionally {"should_stop": True} to converge earlySTITCH owns transport, orchestration, resume, integrity, and the security whitelist; you own the
model, its (de)serializer, and the data. Everything is a resumable reconciler — re-run
clif-stitch run after a crash and it continues from the last completed pass.
uv venv && uv pip install -e ".[dev]"
pytest # 22 tests, all on the offline LocalFsBackend