LipidOracle: ambiguity-aware lipid annotation

Hierarchical, traceable, all-isomers annotation of MS1, CID, EAD, UVPD, ... spectra. Rust-based. Runs as a Docker container.

  • Truly untargeted: a built-in library spanning 49 lipid classes, including rare chain lengths and oxidised forms, for >3 Mio unique compounds
  • Multi-method structural elucidation using CID for identity, and EAD, UVPD, and OAD for positional detail
  • Hierarchical elucidation from species-level composition to positionally resolved double bonds and acyl-chain modifications
  • Never claims more than the spectrum can prove. Resolvability analysis checks whether discriminating fragments were actually observed, and honestly reports the lower idlevel when they weren't
  • Calibrated, checkable scoring, not a black box. Posterior selection turns competing structures into probabilities, keeps a credible set instead of forcing one winner, and is tested against chemically impossible decoys rather than trusted on faith
  • Self-tuning retention-time validation learns class-specific behaviour from confident annotations in each run to remove spurious matches, with optional external anchors
  • Provides CXSMILES for identifications and matched fragments, keeping structures and their evidence machine-readable
  • Adheres to lipid shorthand notation (Liebisch et al, JLR, 2020) and lipidomics data quality scoring (Hoffmann et al, JLR, 2025)
  • An interactive dashboard for quick quality control, result exploration, and spectrum-level evidence review

© Zamboni lab, ETH Zurich.

LipidOracle logo, an illustrated oracle holding a molecule
LipidOracle dashboard, Summary tab, showing run totals per identification level and charts of identifications, ID level, rarity scores, and score distribution LipidOracle dashboard, Summary tab, showing run totals per identification level and charts of identifications, ID level, rarity scores, and score distribution

Every run writes a self-contained dashboard.html next to the CSVs. No server, no upload.

Two commands to a first run

LipidOracle ships as a Docker image. All input MS1 and MS2 data are provided in a single .mgf file. All settings are defined in a lipidoracle.yaml file, which is written to the output folder on the first run if it doesn't already exist.

Pull the image from Docker Hub.

docker pull zambonilab/lipidoracle

Create a local input folder. Paste the .mgf file with MS data into it. If you have a preconfigured lipidoracle.yaml, paste it in too.

Mount your folders and run. It's a matter of seconds to get results!

docker run --rm \
  -v <INPUT-FOLDER>:/input \
  -v <OUTPUT-FOLDER>:/output \
  zambonilab/lipidoracle

If no lipidoracle.yaml is found in either folder, LipidOracle writes a default one to the output folder and stops so you can check it. Review the parameters, then run again. Or simply trust the defaults, which use the internal LipidOracle library and a permissive RT checking routine (LiRI).

WORKFLOW:
  lipidoracle: True       # internal MS1/MS2 annotation engine
  stage3: False           # No EAD/UVPD/OAD/OzID analysis of acyl chains
  rt_check: liri          # False | legacy | liri | hydra

Workflow

A run is a fixed sequence of steps. Three of them are the numbered analysis stages, and each reports the identification level its evidence supports — falling back to the level below when the spectrum cannot separate the isomers, rather than asserting a structure the data does not carry. The remaining steps prepare the input and filter or export what the stages produced. A typical run concludes in less than 10 sec for CID data, and less than 5 min for EAD data.

Load spectra

Reads MS2 and MS1 from the MGF. An m/z target list and internal standards can be pinned in.

input

Build libraries

Internal LipidOracle library, optionally LipiDex, LipidBlast, and your own CSV libraries.

setup

Match on accurate mass

Identifies features by precursor m/z against every library in play. Internal standards are matched here too. Reports idlevel 1.

stage 1

Match on MS2

Every stage-1 hit that carries MS2 goes on to fragment matching and scoring. Reports idlevel 2, or idlevel 1 where the chains do not resolve.

stage 2

Validate retention time

A class-specific model flags implausible hits. External RT anchors refine the fit.

filter

Resolve acyl chains

On EAD, UVPD, OAD, or OzID spectra, locates C=C and, where supported, oxidation positions by scoring simulated isomers against method-specific diagnostic ions. Reports idlevel 3, and idlevel 4 once consolidated, or idlevel 2 where the isomers do not resolve.

stage 3

Consolidate and export

Aggregates the stage-3 candidates per spectrum into the idlevel-4 consensus form, then writes results, diagnostics, and the dashboard.

output

Evidence-based annotation

LipidOracle is built around one idea: translate MS2 data into structural information fairly. It never stops at the first good-enough match — it considers the whole set of credible candidates. And it never stops at a matching score either: it checks which fragments were actually matched, and which weren’t, and reports only trusted information. Where ambiguity between isomers remains, it refrains from producing an overly detailed structural claim.

LipidOracle distinguishes four levels of identification, with increasing detail — but only as far as the spectrum actually supports:

IDLEVEL 1 (Species)

Summed composition only, with no chain detail, for example PC 34:1.

IDLEVEL 2 (Molecular species)

Chain composition, including regiochemistry where the spectrum supports it, for example PC 16:0_18:1 or PC 16:0/18:1;OH.

IDLEVEL 3 (Positional candidates)

Positional detail within the chains, including C=C, hydroxyl, and other modification positions, for example PC 16:0/18:1(9);12OH. All plausible candidates are listed as separate rows.

IDLEVEL 4 (Aggregated positional evidence)

Stage 3 can produce hundreds of idlevel 3 matches for a unique MS2 spectrum. All of these candidates are condensed into one string, with a support score for each C=C or other modification position on every enriched chain, like PC 16:0/18:1(9Z);12OH [C=C sn2: Δ9 92%, Δ8 8%; OH sn2: 12 100%].


LipidOracle implements algorithms that adaptively select the credible candidates — the ones with practically equivalent, good scores — rather than reporting a single top hit and discarding the rest.

Matches, scores, and resolvability are reported in full in the output, letting the user reconstruct exactly what information was used to call a given structural property.

MS2 match tab showing mirror plot and fragment cleavage mapping
MS2 match. In the dashboard, each peak of the MS2 match panel is clickable and provides information about where it came from.

Adaptive retention time checking

As many features might not have - good enough - MS2 spectra, MS1-based annotation remains an important part of the workflow but suffers from spurious false hits. LipidOracle implements two retention-time engines to check for RT consistency. They employ machine learning to learn within and across lipid classes, and flag implausible hits before they reach the output.

Both models are tuned automatically based on high-quality MS2 matches. An external RT library can be provided, but is not necessary if enough MS2 spectra are available for tuning.

See Retention-time checking for more details.

LiRI – the default

Builds a structural retention index per class, mapping carbons minus a fitted penalty for double bonds and oxygens onto observed RT. Conservative: a class with too few anchors gets no prediction at all rather than a rough guess. Safe but incomplete — classes without MS2 evidence in this run pass through unfiltered.

Evidence-based Per-class model

HYDRA – zero-shot coverage

Uses one shared calibration curve and predicts missing classes through chemistry features (headgroup composition, chain inventory, family indicators). Can flag an implausible hit in a class with zero MS2 confirmation in this run. Complete but requires tuning — stricter idlevel-1 settings can increase removals.

Chemistry-informed Cross-class features

Both RT checking engines are followed by a generic RT filter that removes wrong MS1-matches. It builds on the high-quality results produced by the RT engines, and it filters out in-source fragments.

Dashboard showing scatter plot of predicted vs observed retention time, with points colored by identification level (idlevel 1-4). The plot demonstrates how the generic formula model removes outliers after the selected RT engine has run.
Generic RT filter: every hit’s predicted vs. observed retention time, coloured by identification level. Points with an excessive RT deviation from the generic model (here in green to red) are naturally removed.

Report ambiguous data faithfully

Multiple candidates often tie for the same score, or score within noise of each other. Rather than arbitrarily picking one, LipidOracle reports the ambiguity itself: CXSMILES depictions show every surviving candidate and the confidence score for each. See Scoring, thresholds, and honest reporting for what "tie" actually means here, and why a single best-scoring candidate is never enough on its own.

Names follow Shorthand 2020 (Liebisch et al.) exactly — positional modifiers as ;11OH, legacy spellings normalised on input — and structures are emitted as extended CXSMILES validated against CDK. See Nomenclature and CXSMILES.

CXSMILES

Every candidate structure is encoded as CXSMILES, a canonical SMILES string that explicitly marks uncertain double-bond, oxidation, or connectivity positions. The Sg: and m: blocks plus snN atom labels declare ambiguity precisely, in a machine-readable format. Whatever CXSMILES cannot express is stated in the trailing part, after the closing |.

PC 16:0_20:4;OH
↓
C(COP(=O)([O-])OCC[N+](C)(C)C)(OC(=O)CC=CC=CC=CC=CC.*O)COC(=O)CCCCCCCCCCCCCCC
|$;;;;;;;;;;;;;sn2;;;;;;;;;;;;;;;;sn1$,Sg:n:16:a:ht,Sg:n:18:b:ht,Sg:n:20:c:ht,Sg:n:22:d:ht,Sg:n:25:e:ht,m:26:16.17.18.19.20.21.22.23.24.25|
swappable(sn1,sn2);constrain(a+b+c+d+e=14)
  • glycerol backbone
  • acyl chain undefined C=C position
  • movable C-OH
  • ambiguity in sn-regioisomerism

Structure depiction

The ambiguity is depicted in the structures shown in the dashboard, which are calculated on the fly. The string above, drawn by CDK: one connected molecule, the sn labels marking the interchangeable ester oxygens, and the variable-length runs a–e bracketing the four double bonds whose positions were never determined.

Alternatively, LipidOracle can expand the variable parts into one representative isomer, for renderers that do not draw variable-length regions. Read that as a diagram, not a determination — an expanded double bond sits at an arbitrary valid position.

CDK depiction of PC 16:0_20:4;OH: one connected phosphatidylcholine with the palmitoyl chain abbreviated, sn1/sn2 atom labels on the interchangeable ester oxygens, five variable-length Sg runs (a-e) on the 20:4 chain, and a hydroxyl on a position-variation bond CDK depiction of PC 16:0_20:4;OH: one connected phosphatidylcholine with the palmitoyl chain abbreviated, sn1/sn2 atom labels on the interchangeable ester oxygens, five variable-length Sg runs (a-e) on the 20:4 chain, and a hydroxyl on a position-variation bond

Outputs

Three files answer most questions. The rest of the run is written to diag/ so you can trace any call back to its evidence.

In addition, both the lipidoracle.yaml and the input *.mgf files are copied to the output folder for reference.

Results

  • annotation.csv
  • summary.csv
  • dashboard.html
  • data.mgf
  • lipidoracle.yaml

Extras

  • annotation_full.csv
  • summary_by_feature.csv
  • input_spectra.csv
  • annotation_stage*.csv
  • lib_stage*.csv
  • rt_*.csv

A single dashboard.html file is generated for each run. It contains a summary of the run and links to all the other output files. The dashboard is a good place to start exploring your results.

Dashboard scatter view plotting m/z against retention time, coloured by lipid class Dashboard scatter view plotting m/z against retention time, coloured by lipid class
RT and m/z scatter. Colour by class, rarity, or score, filter by identification level, and export the figure as PNG or SVG. Kendrick mass defect and chain distribution views sit alongside it.

Reference

LipidOracle is developed by the Zamboni lab at ETH Zurich. Version 1.0 is a full rewrite in Rust. The Python version stays available as zambonilab/lipidoracle:v0.9, and is not backward compatible.

Wu et al. Optimisation of electron-induced dissociation parameters for molecular annotation of glycerides and phospholipids in fast LC-MS Analyst, 2025. 10.1039/d5an00567a