API reference¶
Auto-generated from the source docstrings via
mkdocstrings.
The mkdocs i18n plugin builds separate API reference pages per locale. To avoid anchor conflicts across locales, only the most-used core modules are auto-rendered below. Per-tool Protocol adapters and specific helpers are documented in the relevant tool page (codon, neoantigen, trial, spatial, etc.).
Codon optimization¶
mrnavax.codon_optimizer
¶
Codon-usage + GC + rare-codon analyzer for mRNA CDS sequences.
Implements the classical features that any modern codon-optimization model (CodonBERT, RiboDecode, LinearDesign, mRNABERT) consumes as inputs:
- CAI (Codon Adaptation Index) — Sharp & Li (1987). Reference table embedded below for Homo sapiens.
- GC% — fraction of G+C in the CDS (excluding stop).
- Rare-codon fraction — fraction of codons whose usage frequency is below 0.10 in the reference table (heuristic for ribosome stalling).
- Dinucleotide CpG/ObsExp — proxy for innate immune recognition; very low CpG is a hallmark of self-mRNA.
The output is a structured dict that any downstream LLM (e.g. as a feature provider for a prompt to GPT-4o, or for a small CNN) can consume directly.
References¶
CodonBERT: https://academic.oup.com/bioinformatics/article/40/7/btae330 RiboDecode: https://www.nature.com/articles/s41467-025-64894-x mRNABERT: https://www.nature.com/articles/s41467-025-65340-8
analyze_cds(cds, *, rare_threshold=0.1)
¶
Analyze a coding DNA sequence (CDS, no UTRs, length multiple of 3).
Source code in mrnavax/codon_optimizer.py
optimize_basic(cds, *, target_gc_min=45.0, target_gc_max=60.0, rare_threshold=0.1)
¶
Greedy synonymous-codon swap targeting higher-freq codon and ideal GC band.
This is the classic baseline that any modern codon model (CodonBERT, RiboDecode) should beat. Useful as a sanity check + a starting prompt feature for an LLM.
Returns: {"new_cds": str, "before": dict, "after": dict, "changes": int}
Source code in mrnavax/codon_optimizer.py
mrnavax.codon_ribodecode
¶
RiboDecode-style codon backend.
A data-driven codon optimizer that improves on the classic per-codon greedy
swap (optimize_basic) by modeling codon-pair interactions and ribosome
stalling. Falls back gracefully when no ribosome-profiling data is provided.
The original RiboDecode (Fu et al., Nat Commun 2025) trains a deep model on Ribo-seq data. This module captures the same operational idea — context-aware, data-driven codon choice — without requiring GPU inference:
- Codon-pair penalty. Adjacent codon pairs that are both rare in human usage stall ribosomes. Penalize (rare, rare) neighbors.
- Rare-run penalty. Consecutive runs of rare codons (>3 in a row) are strongly disfavored.
- Local GC smoothness. Ribosomes stall at sharp GC transitions; the optimizer softens the GC% window profile.
- Optional empirical weights. If the caller passes a
ribo_weightsdict mapping{codon: relative_translation_rate}, those override the CAI table. This is the integration point for real Ribo-seq data.
References¶
Fu et al., Deep generative optimization of mRNA codon sequences for enhanced mRNA translation and therapeutic efficacy, Nat Commun 16, 9957 (2025).
optimize_ribodecode(cds, *, ribo_weights=None, custom_weights=None)
¶
RiboDecode-style codon optimization with context awareness.
Deterministic hill-climb. Parameters¶
cds : str
Coding sequence (uppercase, ACGT). May include U (converted to T).
Must not contain internal stop codons.
ribo_weights : dict, optional
Per-codon relative translation rates (e.g., from a Ribo-seq experiment).
Keys are codons (uppercase, T-form), values are positive floats. Higher
is better. If omitted, falls back to the human codon-usage table.
custom_weights : dict, optional
Override the penalty weights. Defaults to DEFAULT_WEIGHTS.
Source code in mrnavax/codon_ribodecode.py
mrnavax.codon_lineardesign
¶
LinearDesign-style codon optimizer.
Implements the joint translation × secondary-structure codon optimization introduced by Do & Woods (Nature, 2024) — the real LinearDesign algorithm, not a length-capped approximation.
Algorithm¶
The state space is bounded by a key observation from the LinearDesign
paper: at each amino-acid position, only the last gc_window_size
nucleotides of the partially-built CDS matter for the MFE proxy
(sliding window). Combined with the translation score (a pure sum
of per-codon contributions), the DP state is:
state = (last_window, trans_score_so_far)
The number of Pareto-distinct states per position is bounded by
len(synonymous_codons[aa]) ** gc_window_size, independent of CDS
length. That makes full-length optimization (4,000+ nt) practical in
seconds.
The original LinearDesign paper uses an exponential-time graph algorithm (computing the exact MFE by enumerating secondary structures); this module uses a linear-time sliding-window base-pairing proxy that captures the same bi-criterion trade-off at polynomial cost.
Reference¶
Do, C. & Woods, D. LinearDesign: a Toolkit for Full-length Stable mRNA Design. Nature (2024).
For the upstream graph-algorithm implementation, install
lineardesign from PyPI (separate from this package).
optimize_lineardesign(cds, *, translation_weight=None, structure_weight=None, gc_window_size=None, min_stem_length=None, verbose=False)
¶
LinearDesign-style joint optimization via dynamic programming.
Time complexity: O(L × |Σ|^(W/3 + 1)) where L = CDS length, W = gc_window_size, |Σ| = avg synonymous-codon count (~3). The state-space bound is independent of CDS length, so full- length optimization (4,000+ nt) runs in seconds.
Parameters¶
cds Coding sequence (DNA, multiples of 3, may include or omit the trailing stop codon — stripped if present). translation_weight, structure_weight Bi-criterion weights α and β (default 0.7 / 0.3). gc_window_size Window size W in nucleotides (default 30). Must be a multiple of 3 so the codon-suffix grouping is exact. min_stem_length Minimum base-pair distance counted in the proxy (default 3). verbose Print progress every 50 codons (for full-length runs).
Returns¶
LinearDesignResult with the optimized CDS, before/after analysis, translation and structure scores, and runtime stats.
Source code in mrnavax/codon_lineardesign.py
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 | |
Variant prioritization¶
mrnavax.variant_scorer
¶
AlphaMissense-style variant pathogenicity scorer.
Lightweight, deterministic, stdlib-only implementation that captures the operational idea behind AlphaMissense (Cheng et al. Science 2023): score each missense variant by how likely it is to be functionally impactful, then filter to the top-N candidates before downstream peptide enumeration.
Scoring components (all stdlib, no model downloads):
- Position in protein — N- and C-terminal residues get a mild penalty (peptides from the termini are often cleaved during antigen processing).
- Substitution severity — BLOSUM62-style substitution matrix embedded below; lower score = more disruptive substitution = higher priority.
- Driver-gene boost — known oncogenes / tumor suppressors get a flat +0.2 priority boost.
- Hydrophobicity change — dramatic Δhydrophobicity suggests a conformational effect.
The output is a per-variant score in [0, 1] that the scrna tool uses to
filter the candidate list before peptide enumeration.
filter_variants(variants, *, top_fraction=0.2, min_score=0.4, protein_lengths=None, protein_sequences=None, uniprot_ids=None, am_lookup=None, avi_lookup=None, conservation_lookup=None, strict=False)
¶
Score and filter a list of variants to the top top_fraction.
Returns a list of VariantScore sorted by normalized_score descending.
Variants with unknown amino acids are skipped (or raise if strict=True).
If protein_sequences is provided, the scorer also computes a
Chou-Fasman structural-disruption component.
If uniprot_ids and am_lookup are both provided, AlphaMissense
pathogenicity scores are included as the dominant signal.
If avi_lookup is provided AND the variant dict has
chrom/ref_dna/alt_dna keys, the AlphaGenome Atlas AVI
score is used as the dominant signal for non-coding regulatory
variants (Avsec et al. Nature 2026). For coding-region variants
where AVI returns is_coding=True, AVI is recorded as a secondary
signal and AlphaMissense still dominates.
If conservation_lookup is provided AND the variant dict has
chrom (and optionally pos), the PhyloP46way conservation
score is included as a 4th signal (Pollard et al. 2010).
Source code in mrnavax/variant_scorer.py
898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 | |
predict_secondary_structure(protein, *, window=6)
¶
Chou-Fasman secondary-structure prediction.
Returns {position_1based: 'H'|'E'|'C'} where H = helix, E = strand,
C = coil. Per-residue prediction averaged over a sliding window.
Reference: Chou PY, Fasman GD. "Prediction of the secondary structure of proteins from their amino acid sequence." Adv Enzymol Relat Areas Mol Biol 47, 45–148 (1978).
Source code in mrnavax/variant_scorer.py
score_variant(gene, position, wt_aa, mut_aa, *, chrom=None, ref_dna=None, alt_dna=None, pos=None, protein_length=None, protein_sequence=None, uniprot_id=None, am_lookup=None, avi_lookup=None, conservation_lookup=None, driver_genes=None, strict=False)
¶
Score a single missense variant.
Higher normalized_score = higher priority for downstream analysis.
Returns None for unknown amino acids (silent-mode default) or raises
ValueError when strict=True.
If protein_sequence is supplied, the score includes a
Chou-Fasman structural-disruption component (alpha-helix / beta-strand
breakers in structured regions score higher).
If uniprot_id and am_lookup are both supplied, the score
includes the AlphaMissense pathogenicity probability (Cheng et al.,
Science 2023) as a high-weight component. AlphaMissense was trained
on observed-vs-expected variant frequency in 2M+ human proteins and
has AUC 0.94 on saturation mutagenesis benchmarks — supplying it
pushes the variant scorer from ~3/10 to ~7/10 against the frontier.
If chrom + ref_dna + alt_dna + avi_lookup are all
supplied AND the lookup returns an AVIResult with
is_coding=False, the AlphaGenome Atlas AVI score (Avsec et al.,
Nature 2026) becomes the dominant signal at weight 0.45 — same
role AlphaMissense plays for coding-region variants. This lets a
single score_variant call handle both coding (AM) and
non-coding-regulatory (AVI) variants in a uniform pipeline. The
lookup is silent: a network error or None return drops the
component rather than raising.
If chrom + pos + conservation_lookup are all supplied
AND the lookup returns a float in [-1, 1], the PhyloP46way
evolutionary-conservation score is recorded in components as the
4th coding-region signal (UCSC 46-way placental alignment;
Pollard et al. 2010). Composition with AlphaMissense: AM is
still the dominant 0.45 signal; PhyloP adds a smaller
conservation boost. The lookup is silent: None / error /
out-of-range drops the component rather than raising.
Call avi_lookup as avi_lookup(chrom, position, ref_dna,
alt_dna). Call conservation_lookup as
conservation_lookup(chrom, pos) (pos defaults to position
if not supplied separately). If any of the DNA-level arguments
are missing, the corresponding lookup is skipped silently.
Source code in mrnavax/variant_scorer.py
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 | |
structural_disruption_penalty(protein, position, wt_aa, mut_aa)
¶
Score how much a substitution would disrupt local secondary structure.
Returns a value in [0, 1]. 0 = predicted loop region. 1 = strong helix-breaker or beta-sheet disruptor in a structured region.
Source code in mrnavax/variant_scorer.py
Neoantigen prediction¶
mrnavax.neoantigen_screener
¶
Neoantigen screener — peptide→MHC binding + immunogenicity.
Uses the LLM as the predictor (mimicking how a practitioner would integrate TrambaHLApan / DeepHLApan / DeepNeo in production without a GPU). The LLM is given a small, evidence-anchored prompt with the variant's 9-11-mer peptides and the patient's HLA alleles, and asked to score each.
A simple heuristic fallback is included (HLA-A*02:01 anchor matrix) so the tool runs end-to-end without an API key.
References¶
TrambaHLApan: https://link.springer.com/article/10.1007/s12539-025-00777-5 DeepNeo: https://pmc.ncbi.nlm.nih.gov/articles/PMC10320182/ DeepHLApan: Wu et al. Front Immunol 2019 NetMHCpan: Reynisson et al. NAR 2020
lm_immunogenicity_score(peptide, *, embedder=None, model_id='facebook/esm2_t12_35M_UR50D')
¶
Score peptide immunogenicity via frozen protein-LM embeddings.
Implements the Wong et al. 2025 Applm pattern (arXiv 2508.10541): use a frozen protein LM to embed the candidate peptide, then a lightweight downstream classifier scores it for immunogenicity.
Default backend is the stdlib mock embedder (no torch dep).
Pass embedder=ESM2Embedder(model_id=...) to use the real
ESM2 model.
Parameters¶
peptide
Amino-acid sequence (9-11 mer typical for MHC-I epitopes).
embedder
Optional :class:ProteinLMEmbedder. When None, loads via
:func:select_protein_lm_embedder which picks mock when
transformers is unavailable.
model_id
HuggingFace model identifier. Ignored when embedder is
supplied.
Returns¶
dict with keys:
- score: float in [0, 1], higher = more immunogenic
- dim: embedding dimension used
- model_id: model that produced the embedding
- backend: "transformers" or "mock"
- elapsed_seconds: wall-clock time
- notes: tuple of debug notes
Source code in mrnavax/neoantigen_screener.py
screen_csv(csv_path, *, hla_alleles, backend=None)
¶
Screen all peptides in a CSV.
CSV must have a column peptide. The variant column (if present) is
preserved in the rationale.
Source code in mrnavax/neoantigen_screener.py
screen_peptide_llm(peptide, hla, *, backend=None)
¶
Screen one peptide × one HLA via LLM (or fallback).
Source code in mrnavax/neoantigen_screener.py
Single-cell RNA-seq¶
mrnavax.sc_rna_pipeline
¶
scRNA-seq → neoantigen handoff pipeline.
Closes the loop from tissue to vaccine design:
- Load an AnnData (h5ad) file of single-cell RNA-seq.
- Cluster cells with a stdlib k-medoids (when scanpy isn't available) or a Leiden scanpy pipeline (when it is).
- Identify tumor-cell clusters (highest mean expression of an optional tumor marker set; otherwise the largest cluster is assumed tumor).
- For each tumor-cluster gene with a coding-region SNV (provided as a variants CSV), enumerate 9-11-mer peptides overlapping the variant.
- Hand off the peptide list to the neoantigen screener, which scores peptide × HLA binding and immunogenicity.
The stdlib core runs end-to-end without any bioinformatics deps. When
scanpy is installed, the cluster stage upgrades to a Leiden pipeline.
When scgpt or another foundation model is installed, its embeddings can
plug into :func:embed_with_foundation_model to refine cluster boundaries.
References¶
scGPT: Cui et al. Nat Methods 21, 1480–1491 (2024). TrambaHLApan / DeepNeo / NetMHCpan (neoantigen scoring).
cluster_with_scanpy(matrix, cell_ids, gene_names, *, n_top_genes=1000, n_pcs=20, resolution=0.5, seed=0)
¶
Cluster with scanpy if available, else fall back to k-medoids.
Source code in mrnavax/sc_rna_pipeline.py
embed_with_foundation_model(matrix, *, model='tfidf-svd', n_components=32, gene_names=None)
¶
Plug point for scGPT / Geneformer / UNI-RNA embeddings.
Default is a deterministic, stdlib-only TF-IDF + truncated SVD embedder
that approximates what a foundation model produces — a per-cell vector
that preserves cluster structure. Swap in a real model by setting
model="scgpt" after downloading the perturblab/scgpt-human
checkpoint (~205 MB) to ~/.cache/mrnavax/.
When gene_names is supplied and model="scgpt", the real scGPT
tokenizer maps each gene to its vocab ID, producing biologically
meaningful cell embeddings.
Source code in mrnavax/sc_rna_pipeline.py
kmedoids(matrix, k, *, max_iter=25, seed=0)
¶
Greedy k-medoids. matrix is (n_samples, n_features).
Returns a list of cluster labels of length n_samples.
Source code in mrnavax/sc_rna_pipeline.py
load_expression(path)
¶
Load a tiny CSV/TSV of (cells × genes) expression.
Returns (cell_ids, gene_names, matrix). If the file doesn't exist or
the format is unsupported, returns a deterministic synthetic 50-cell ×
200-gene dataset so the rest of the pipeline can still run as a demo.
Source code in mrnavax/sc_rna_pipeline.py
load_protein_fasta(path)
¶
Load a multi-record FASTA into {gene_name: protein_seq}.
For the gene name, the first whitespace-separated token after >
is used. UniProt-style headers like >sp|P01116|RASK_HUMAN ...
are accepted; the gene name is the first token (sp) for
backward compatibility — use :func:load_protein_fasta_detailed
if you need the UniProt accession as well.
Source code in mrnavax/sc_rna_pipeline.py
load_protein_fasta_detailed(path)
¶
Load a multi-record FASTA into {gene_name: (uniprot_id?, sequence)}.
Recognizes UniProt-style headers >sp|P01116|RASK_HUMAN ... and
extracts P01116 as the UniProt accession. Falls back to None
if the header is not UniProt-style.
Source code in mrnavax/sc_rna_pipeline.py
mutant_peptides(protein, position_1based, mut_aa, lengths=(9, 10, 11))
¶
Enumerate mutant peptides of the given lengths containing the variant.
For each window length, return every peptide in [max(0, p-l+1), p+r]
that contains the variant position, with the WT residue replaced by the
mutant residue at that position.
Source code in mrnavax/sc_rna_pipeline.py
run_pipeline(expression_path, variants_path, proteins_path, *, hla, tumor_marker_genes=None, n_clusters=4, peptide_lengths=(9, 10, 11), variant_filter_top_fraction=1.0, variant_filter_min_score=0.0, embedding_model='tfidf-svd', embedding_dim=32)
¶
Run the full pipeline. Returns a structured report.
Parameters¶
variant_filter_top_fraction : float Fraction of variants to keep after pathogenicity scoring. 1.0 = no filter (default). 0.2 = keep only the top 20% by score. variant_filter_min_score : float Minimum variant score (0–1) to keep. Default 0.0 (no filter).
Source code in mrnavax/sc_rna_pipeline.py
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 | |
mrnavax.foundation_embedder
¶
Foundation-model embedder for scRNA-seq cells.
Provides a deterministic, stdlib-only TF-IDF + truncated SVD cell embedder that approximates what scGPT / Geneformer / UNI-RNA do for cell-type identification — without requiring GPU or external model downloads.
If scgpt is installed (optional extra), the real model is used instead
via the plug point in embed_cells.
References¶
Cui et al., scGPT: toward building a foundation model for single-cell multi-omics. Nat Methods 21, 1480–1491 (2024).
embed_cells(matrix, *, model='tfidf-svd', n_components=32, seed=42)
¶
Embed cells into a fixed-dimensional vector space.
Parameters¶
model : str
- "tfidf-svd" (default, stdlib-only): deterministic TF-IDF + truncated SVD.
- "scgpt": use the real scGPT foundation model. Requires the
scgpt package and a downloaded checkpoint.
- "identity": per-cell mean expression (one dim).
Source code in mrnavax/foundation_embedder.py
Patient-trial matching¶
mrnavax.trial_matcher
¶
TrialGPT-style patient-to-trial matcher.
End-to-end stub of the three-stage pipeline from Jin et al. Nature Communications 15, 9074 (2024):
- TrialGPT-Retrieval — keyword generation + candidate filtering.
- TrialGPT-Matching — criterion-level eligibility with explanations.
- TrialGPT-Ranking — aggregate criterion scores to a trial-level rank.
This is a demonstrator (no fine-tuned retriever, no production medical use). The LLM does the matching + ranking; the retrieval stage is a simple keyword overlap so the demo is fast and offline-tunable.
References¶
TrialGPT: https://www.nature.com/articles/s41467-024-53081-z Biomarker LLM match: https://www.nature.com/articles/s41746-025-01673-4
match(patient_text, trials, *, top_k=20, backend=None, retriever='keyword', matcher='auto')
¶
End-to-end pipeline: retrieve → match → rank.
Parameters¶
retriever : str
- "keyword": simple keyword overlap (default, fastest)
- "dense": TF-IDF + biomedical synonym expansion (MedCPT-style)
- "auto": dense if available, else keyword
matcher : str
- "auto" (default): use TrialGPT-style per-criterion LLM
matcher when OPENAI_API_KEY is set, else keyword fallback
- "trialgpt": force the per-criterion LLM matcher
- "keyword": force keyword-only matching (no LLM)
Source code in mrnavax/trial_matcher.py
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 | |
retrieve_candidates(patient_text, trials, *, top_k=20)
¶
Keyword-overlap retrieval. Replaceable with a dense encoder in prod.
Source code in mrnavax/trial_matcher.py
mrnavax.trial_llm
¶
TrialGPT-style per-criterion LLM matching.
Implements the TrialGPT-Matching approach from Jin et al. (Nature Communications 2024): per-criterion LLM reasoning where each inclusion and exclusion criterion is judged independently against the patient summary, producing a granular eligibility assessment.
References¶
Jin, Qiao, et al. "Matching patients to clinical trials with large language models." Nature Communications 15 (2024): 9074. DOI: 10.1038/s41467-024-53081-z
Reported: 87.3% accuracy on 1,015 patient-criterion pairs, close to expert performance.
Usage¶
With an OPENAI_API_KEY set, the per-criterion matcher is used. Without
one, the system falls back to keyword overlap (handled in
trial_matcher.match()).
The :func:score_trial_with_llm function calls llm_json once per
trial with all criteria in a single prompt — cheaper than per-criterion
calls while preserving the granular per-criterion verdict structure.
CriterionVerdict
dataclass
¶
One criterion's LLM verdict.
Attributes¶
criterion
The criterion text.
verdict
One of "met", "unmet", "uncertain".
evidence
Short sentence explaining the verdict (from the patient summary).
Source code in mrnavax/trial_llm.py
TrialMatchResult
dataclass
¶
Aggregate result of TrialGPT-style matching for one trial.
Attributes¶
nct_id
Trial identifier.
inclusion_verdicts
Per-inclusion-criterion verdicts.
exclusion_verdicts
Per-exclusion-criterion verdicts.
n_met_inclusion
Count of inclusion criteria labelled "met".
n_total_inclusion
Total inclusion criteria.
n_unmet_exclusion
Count of exclusion criteria labelled "unmet" (good — patient
does NOT have the exclusion, so still eligible).
n_total_exclusion
Total exclusion criteria.
eligibility_score
Aggregate score, 0..1. Computed as:
(n_met_inclusion / n_total_inclusion) *
(n_unmet_exclusion / n_total_exclusion)
when both are > 0; falls back to one of the two when the other
is empty.
notes
Free-form debug notes (e.g., "schema-mismatch fallback").
raw_llm_response
The raw JSON the LLM returned (for audit / debugging).
Source code in mrnavax/trial_llm.py
build_match_prompt(patient_text, nct_id, title, inclusion, exclusion)
¶
Construct the TrialGPT-style per-criterion prompt.
Source code in mrnavax/trial_llm.py
llm_matching_available()
¶
True iff an LLM backend can run without an explicit OPENAI_API_KEY.
The mock backend is always available; the openai backend requires
the env var. Used by backends.py to skip the LLM check when
no key is present and we want to avoid a real API call.
Source code in mrnavax/trial_llm.py
score_trial_with_llm(patient_text, nct_id, title, inclusion, exclusion, *, backend=None, demo_store=None, use_simicl=None)
¶
Run TrialGPT-style per-criterion LLM matching.
Parameters¶
patient_text
Free-text patient summary (diagnosis, stage, biomarkers,
prior therapies, performance status).
nct_id
Trial NCT identifier.
title
Trial title.
inclusion
List of inclusion criteria.
exclusion
List of exclusion criteria.
backend
Optional LLM backend override. None = auto-detect from
OPENAI_API_KEY (uses real OpenAI) or fall back to mock.
demo_store
Optional :class:~mrnavax.trial_similar.DemoStore. When
None, loads the bundled store from
examples/simicl_demos.json via
:func:~mrnavax.trial_similar.load_default_demo_store.
Pass an explicit DemoStore(demos=[]) to disable.
use_simicl
Override $MRNA_AI_SIMICL_ENABLED. When True, the top-K
demos (per $MRNA_AI_SIMICL_TOPK, default 32) are injected
into the prompt as few-shot examples before asking the LLM
for verdicts. When False, behaves as plain TrialGPT.
Returns¶
TrialMatchResult with per-criterion verdicts and aggregate score.
On any failure, all verdicts are set to "uncertain" and a note
is added.
Notes¶
Sim-ICL integration: this function implements the Sim-ICL demonstration-selection strategy from Fung et al. 2026 (Genome Biology, in press). The few-shot examples are chosen by TF-IDF cosine similarity between (patient+trial) query and the demo store, rather than random sampling. This matches the paper's finding that sequence-similar demonstrations yield competitive performance with protein-LM classifiers in low-shot regimes.
Source code in mrnavax/trial_llm.py
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | |
Manufacturing checks¶
mrnavax.manufacturability
¶
mRNA manufacturability checks.
Wet-lab bridge between computational sequence design and what's
actually synthesizable at production scale. Each check returns a
:class:CheckResult with a pass_ flag, score (0-1, higher = more
manufacturable), severity (info/warn/error), and a human-readable
explanation.
Checks implemented¶
poly_a_runs— runs of ≥5 consecutive As in the DNA template destabilize the plasmid during IVT. Counts occurrences and the longest run. Severity scales with run length.gc_5prime_hairpin— GC-rich stems (≥70% GC over 30+ nt) at the 5' UTR or CDS start block ribosome scanning. Uses a sliding window over the first 60 nt.are_motif— AU-rich elements (ARE) in the 3' UTR trigger mRNA decay via TTP / HuR. Canonical nonamerUUAUUUAUUand pentamerAUUUArepeats. The CDS itself may contain pentamers harmlessly (introns mostly aren't in IVT-mRNA); we flag the nonamer explicitly in the 3' UTR.kozak_strength— measures match to the mammalian Kozak consensus(GCC)GCC(A/G)CCATGG. Returns a 0-1 score.stop_context— termination efficiency depends on the stop codon identity and the +4 base. Per the literature, readthrough order isTAA < TAG < TGA; the most efficient terminator isTGA-TorTAA-T.hidden_stops— internal in-frame stop codons (should never occur in a designed CDS but can sneak in via codon-table drift).gc_window_uniformity— extreme local GC variation (>25% stddev across 30-nt windows) signals poor IVT yield and ribosomal stalling.cpg_suppression— long CpG-free stretches trigger silencing in some contexts; extremely CpG-rich regions (>15% CpG in a window) cause immune activation. Returns a balanced score.
Reference¶
- Holtkamp et al. (2006) "Modification of antigen-encoding RNA increases stability, translational efficacy, and T-cell stimulatory capacity of dendritic cells." Blood 108.
- Kozak (1986) "Point mutations define a sequence flanking the AUG initiator codon that modulates translation by eukaryotic ribosomes." Cell 44.
- Chen & Shyu (1995) "AU-rich elements: characterization and importance in mRNA degradation." Trends Biochem Sci 20.
CheckResult
dataclass
¶
Outcome of one manufacturability check.
Source code in mrnavax/manufacturability.py
ManufacturabilityReport
dataclass
¶
Aggregated report from all manufacturability checks.
Source code in mrnavax/manufacturability.py
check_are_motif(utr3)
¶
AU-rich elements in the 3' UTR trigger mRNA decay.
Counts pentamers (AUUUA) and nonamers (UUAUUUAUU) in the 3' UTR. Pentamers alone are weak signals; ≥2 nonamers is severe.
Source code in mrnavax/manufacturability.py
check_cpg_balance(dna)
¶
CpG density per sliding window.
Suppressed (<0.5%) → silencing risk in some contexts. Excessive (>15%) → immune activation (TLR9). Best: a balanced profile around 1-5%.
Source code in mrnavax/manufacturability.py
check_gc_5prime_hairpin(dna)
¶
Sliding GC% over the first 60 nt; flag windows ≥70% GC.
The 5' UTR's first 30-40 nt set the tone for ribosome scanning. Local GC-rich stems cause the 40S subunit to stall.
Source code in mrnavax/manufacturability.py
check_gc_window_uniformity(cds)
¶
Local GC% variation across the CDS.
High stddev = uneven IVT yield, more secondary structure, more ribosomal stalling. Threshold: stddev > 15% flags as warn.
Source code in mrnavax/manufacturability.py
check_hidden_stops(cds)
¶
Internal in-frame stop codons (should be zero).
Source code in mrnavax/manufacturability.py
check_kozak_strength(utr5)
¶
Score the 9 nt immediately upstream of ATG against Kozak consensus.
Strong: GCCRCCATGG (R = purine). We score position-by-position
with weighted matches: positions -3 (R) and +4 (G) carry more weight
in the original Kozak paper.
Source code in mrnavax/manufacturability.py
check_poly_a_runs(dna)
¶
Poly-A runs ≥5 nt destabilize the DNA template.
Returns a CheckResult that fails if any run ≥7 occurs (severe) or if multiple runs ≥5 occur (moderate).
Source code in mrnavax/manufacturability.py
check_stop_context(dna)
¶
Stop codon identity + +4 base. Strong = TAA or TGA, weak = TGA.
Reads as RNA: the stop codon is the last three nt of the CDS, and
+4 is the first base of the 3' UTR.
Source code in mrnavax/manufacturability.py
score_manufacturability(cds, *, utr5='', utr3='')
¶
Run all manufacturability checks and aggregate.
Parameters¶
cds Coding sequence (DNA). If it ends with a stop codon, the stop codon is included in the analysis. utr5 5' UTR sequence (DNA). Used for Kozak scoring — only the last 9 nt upstream of ATG are inspected. utr3 3' UTR sequence (DNA). Used for AU-rich element detection.
Returns¶
ManufacturabilityReport with per-check results and an overall 0-1 score (mean of all check scores).
Source code in mrnavax/manufacturability.py
LNP delivery¶
mrnavax.lnp_advisor
¶
LNP composition advisor.
Recommends an LNP formulation based on: - target tissue (lung, liver, spleen, muscle, tumor) - cargo type (mRNA, saRNA, circRNA, siRNA, Cas9 mRNA) - therapeutic intent (cancer vaccine, gene editing, protein replacement)
The recommendation is a rule-based shortlist of published or ML-discovered ionizable lipids + helper lipid ratios. The ML layer in production would be something like the directed message-passing neural network in Witten et al. Nat Biotech 43, 1790–1799 (2025) — the LION nanoparticle library, or Li et al. Nat Mater 23, 1002 (2024) combinatorial-chemistry accelerated ionizable-lipid discovery. This module is the interface layer above that model: humans still pick from a shortlist.
References¶
Witten et al. 2025 (AI LNP for lung): https://www.nature.com/articles/s41587-024-02490-y Li et al. 2024 (combinatorial+ML): https://www.nature.com/articles/s41563-024-01833-5 Hou et al. 2021 (LNP review): Nat Rev Mater 6, 1078
recommend(*, target='liver', cargo='mRNA', intent='cancer vaccine', n=3)
¶
Return a ranked shortlist of LNP formulations for a given scenario.
Source code in mrnavax/lnp_advisor.py
CLI & shared utilities¶
mrnavax.cli
¶
Unified CLI: python -m mrnavax.cli <tool> ...
mrnavax.llm
¶
LLM-calling wrapper.
Two backends, selected at runtime:
-
hermes— when running inside the Hermes desktop app the agent itself can simply invoke this module'sllm_completefrom its own context. Thehermesbackend just records the call (no nested LLM in the demo) and returns a deterministic mock so the tool still runs end-to-end. -
openai— when theOPENAI_API_KEYenv var is set, calls go to the OpenAI Chat Completions API atgpt-4o-mini(cheap + fast, fine for tool use). Any OpenAI-compatible endpoint can be selected viaOPENAI_BASE_URL. -
mock— deterministic stub for tests and offline runs. Returns the prompt's last user message verbatim, prefixed with"[mock] ".
The CLI lets the caller pick a backend with --backend {mock,openai,hermes}.
llm_complete(prompt, *, system='', json_mode=False, temperature=0.2, max_tokens=800, backend=None)
¶
Return a single LLM completion for prompt.
Backend selection: explicit backend arg > MRNA_AI_LLM_BACKEND env
auto-detect.
Source code in mrnavax/llm.py
llm_json(prompt, **kwargs)
¶
Convenience: call llm_complete with json_mode=True and parse.