Pipeline & CLI¶
TrialMatchAI is one end-to-end pipeline built from an ordered registry of idempotent stages. Every command is a slice of this pipeline. Because each stage detects and skips work that is already done, a run "just works" from any starting state — finished stages are cheap no-ops, unfinished ones run.
The stages¶
| # | Stage | What it does | Idempotency check |
|---|---|---|---|
| 1 | prepare |
embed + entity-annotate the trial corpus | per-trial prepared file |
| 2 | concepts |
build the entity-linking concept store | concept table present |
| 3 | index |
build the LanceDB search tables | both tables present |
| 4 | ingest |
import patient inputs into canonical profiles | per-patient profile |
| 5 | expand |
CoT query expansion of patient summaries | query_expanded marker |
| 6 | match |
retrieval + reranking + CoT eligibility + ranking | per-patient ranked_trials.json |
| 7 | eval |
score results against qrels (benchmark runs) | benchmark-only |
The single command¶
Selection — run any subset (the unit of modularity is the stage):
| Flag | Meaning | Example |
|---|---|---|
| (none) | run every stage, skipping what's done | trialmatchai pipeline |
--only |
run exactly these stages | --only match,eval |
--from / --to |
run a contiguous slice | --from index --to match |
--skip |
omit stages (great for ablation) | --skip expand |
--force |
redo stages even if done (all = everything) |
--force match |
Options: --input (repeatable patient files/dirs), --format,
--trials-json-folder, --processed-trials-folder, --processed-criteria-folder,
--concepts / --concepts-csv / --synonym-csv, --config.
trialmatchai pipeline --only prepare,index # build the search index
trialmatchai pipeline --input patient.fhir.json # ingest + match one patient
trialmatchai pipeline --skip concepts,expand # leaner run for an ablation
trialmatchai pipeline --force all # rebuild everything from scratch
Ablation¶
Stage flags double as ablation knobs — toggle a component and compare:
trialmatchai pipeline --skip expand # matching without LLM query expansion
trialmatchai pipeline --skip concepts # without entity-concept linking
Component backends (reranker, CoT, search mode bm25/vector/hybrid) are set in
the config; see Architecture.
Presets (the same pipeline, named)¶
These are thin wrappers over the pipeline that add their own setup:
| Command | Equivalent slice | Adds |
|---|---|---|
trialmatchai build |
--to index |
build manifest; bootstrap-aware prepare |
trialmatchai e2e |
--from index --to match |
patient ingestion convenience |
trialmatchai trec |
--from index --to eval (per track) |
official topics + qrels + corpus restriction |
trialmatchai run |
--only match |
match already-staged profiles |
trialmatchai index |
--only prepare,index |
— |
Every command is idempotent and resumable: re-running continues from the last completed work.
Reports¶
Matching writes a self-contained, offline HTML report (no server, no build step,
no CDN). It is emitted automatically at the end of a run —
<output_dir>/<patient_id>/report.html per patient and <output_dir>/index.html
as a front page across all patients — and can be regenerated from existing results
without re-matching:
trialmatchai report --patient 1009 # one patient -> <output_dir>/1009/report.html
trialmatchai report --all # unified front page -> <output_dir>/index.html
Auto-emit is gated by reporting.emit_html (default true; disabled for trec
benchmark sweeps).
Python API¶
from trialmatchai.config.config_loader import load_config
from trialmatchai.pipeline import StageContext, run_pipeline
ctx = StageContext(config=load_config(), inputs=["patient.txt"])
run_pipeline(ctx, from_stage="index", to_stage="match")
See the API reference for StageContext, Stage, select_stages, and
run_pipeline.
Assessment modes¶
This section describes the assessment behavior introduced in 0.9.1.
Eligibility assessment is enabled by default. rag.enabled controls whether it
runs; use_cot_reasoning selects the CoT prompt (true) or direct JSON prompt
(false). Both prompts request per-criterion classifications and justifications.
Set rag.enabled: false for retrieval-only execution, as the synthetic CPU demo does.
rag.no_think remains a separate model thinking-mode setting.
ranked_trials.json now carries a Run object with assessment controls, result mode,
output availability, and assessed trial IDs. Reports show retrieval-only and partial
assessment states, and do not join old assessments into a retrieval-only result.
These fields describe available outputs, not verified clinical completeness.
When upgrading from 0.9.0, configurations that disabled CoT to skip the whole stage
must explicitly disable rag.enabled. Legacy results without this metadata are
recomputed on resume. Assessment-control changes, including rag.max_trials_rag,
invalidate both match completion and per-trial assessment reuse. Unavailable or
partial assessments stay pending; a resumed attempt reuses compatible successful
outputs and retries the remaining trials. Missing or corrupt saved assessments
also trigger retries. An empty shortlist or explicitly disabled assessment is a
completed run. Each attempt stages its outputs separately, so an early return or
failed write cannot associate old verdicts with new controls. Full
evidence/config/model identity and atomic publication of an entire patient run
remain P02 work.