single-cell/metabolite-communication/SKILL.md
Infers metabolite-mediated cell-cell communication from scRNA-seq by scoring enzyme-to-sensor pairs (MEBOCOST), with metabolic flux (scFEA), FBA state (Compass), and neurotransmitter (NeuronChat) alternatives. Use when studying metabolic crosstalk between cell types, predicting metabolite secretion and sensing, or deciding which metabolic-communication method fits and how speculative the result is.
npx skillsauth add GPTomics/bioSkills bio-single-cell-metabolite-communicationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Reference examples tested with: mebocost 1.0+, scanpy 1.10+, anndata 0.10+
Before using code patterns, verify installed versions match. If versions differ:
pip show <package> then help(module.function) to check signaturesIf code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.
"Find which cell types exchange metabolites" -> Infer a metabolite's presence from the cells expressing its synthesizing enzymes, then score communication to cells expressing its sensor or transporter.
mebocost.create_obj() -> infer_commu() (metabolite-sensor scoring)Metabolite-mediated communication is a DOUBLE inference and the most speculative layer of cell-cell communication. scRNA-seq never measures metabolites; their levels are inferred from the expression of synthesizing enzymes, then a chain of further assumptions is stacked: enzyme mRNA -> enzyme protein -> enzyme ACTIVITY -> metabolic FLUX -> intracellular metabolite POOL -> SECRETION/export -> extracellular concentration in space -> import/SENSING by the receiver. Every arrow is an assumption and none is measured. On top of this sit all the ligand-receptor caveats (proxy, no spatial geometry in dissociated data, abundance and depth confounds, ambient RNA), so the output is hypothesis-generation ONLY. A defensible claim is never "cell A produces metabolite X" but "cell A expresses the machinery consistent with producing X". Validation is non-optional and means metabolomics (LC-MS), mass-spectrometry imaging (MALDI/DESI), isotope tracing, or perturbation of the enzyme or sensor - not another expression-based method. State the enzyme->flux->level->sensing chain explicitly whenever reporting a result.
| Method | Tests what / null | Use when | Fails when | |--------|-------------------|----------|------------| | MEBOCOST | Metabolite SENDER->RECEIVER communication; estimates an extracellular metabolite level from producing-enzyme expression, scores enzyme->sensor pairs, permutation FDR over shuffled labels | The question is metabolite crosstalk between cell types (enzyme-sensor), analogous to CellPhoneDB for L-R | Synthase mRNA present but substrate/cofactor absent; transporter "sensor" is bidirectional/promiscuous so sender/receiver direction is wrong; no spatial geometry | | scFEA | Per-cell metabolic FLUX through modules; graph neural network solver enforcing flux balance (in approximately out) | The question is relative flux per cell to FEED metabolite reasoning, not direct communication | Read as absolute mol/s (fluxes are relative); needs the matching module/stoichiometry files for the species; not a CCC tool itself | | Compass | Per-cell metabolic STATE via flux-balance analysis; reaction penalty inversely proportional to enzyme expression over Recon2, outputs a score per reaction per cell | Comparing metabolic state between conditions (e.g. pathogenic vs non-pathogenic cells) | Used to claim a SECRETED metabolite communicates (output is reaction favorability, not secretion); assumes steady state, questionable for differentiated non-proliferating cells; heavy compute, micropool first | | NeuronChat | Neurotransmitter/neuromodulator communication; vesicular release machinery and synthesis enzymes vs target receptor abundance | Neural systems specifically (glutamate, GABA, dopamine, serotonin, neuropeptides) | Applied outside neural tissue; same expression-proxy and geometry limits |
Methods and their curated databases evolve; before committing, verify current best practice, the metabolite-sensor database version, and required config/species files against the installed package docs.
| Confound | How it manufactures a fake signal | Mitigation | |----------|-----------------------------------|------------| | Compounded inference | Enzyme mRNA is a poor proxy for metabolite concentration (post-transcriptional control, substrate availability, allostery, compartmentalization), so a "secreted" metabolite may never be made | State the enzyme->flux->level->sensing chain; require metabolomics/MSI/tracing before any production claim | | Bidirectional transporters | A transporter labeled a "sensor" may export rather than import, and many move several metabolites, so sender/receiver direction can be inverted | Treat transporter-based calls as lower-confidence than dedicated-receptor calls; check transport directionality literature | | Ambient RNA | Soup of highly expressed transcripts inflates enzyme/sensor "expression" in clusters that do not transcribe them | Decontaminate (SoupX/DecontX/CellBender) before inference | | Cell-type abundance and depth | Larger clusters tighten the permutation null and deeper cells detect more genes, inflating significance independent of biology | Down-sample, run on integrated counts, do not compare raw counts across conditions | | No spatial geometry | Metabolites diffuse and degrade, but dissociated data has no coordinates, so a "communication" may be between cells never co-located | Validate proximity with spatial metabolomics/MSI; do not claim neighbor exchange from dissociated data |
Goal: Score metabolite sender->receiver communication between cell types with permutation significance.
Approach: Build a MEBOCOST object from a log-normalized AnnData with cell-type labels and a config file pointing at the metabolite-sensor database, then run permutation inference; results carry both the communication score and an FDR.
from mebocost import mebocost
import scanpy as sc
adata = sc.read_h5ad('adata_annotated.h5ad') # log-normalized, gene SYMBOLS not Ensembl IDs
# config_path points to mebocost.conf listing the metabolite-enzyme-sensor database paths
# cutoff_prop=0.15: a gene must be expressed in >=15% of a group to count (dropout floor)
# species MUST match the data: mouse data against the human enzyme/sensor DB returns almost nothing
mebo = mebocost.create_obj(adata=adata, group_col='cell_type', condition_col=None,
met_est='mebocost', config_path='./mebocost.conf', species='human',
cutoff_exp='auto', cutoff_met='auto', cutoff_prop=0.15,
sensor_type='All', thread=8)
# n_shuffle=1000: label-permutation null for FDR; min_cell_number=10 drops tiny groups
commu_res = mebo.infer_commu(n_shuffle=1000, seed=12345, Return=True,
min_cell_number=10, pval_method='permutation_test_fdr',
pval_cutoff=0.05, thread=None)
Goal: Extract the significant, defensible metabolite communications.
Approach: Filter on the permutation FDR (not the raw p-value), then summarize by metabolite and by sender->receiver pair; column names are capitalized in the result table.
sig = commu_res[commu_res['permutation_test_fdr'] < 0.05].copy()
# Result columns: Sender, Receiver, Metabolite_Name, Sensor, Annotation (Transporter/Enzyme),
# Commu_Score, Norm_Commu_Score, met_in_sender, sensor_in_receiver, permutation_test_fdr
sig['pair'] = sig['Sender'] + ' -> ' + sig['Receiver']
top_metabolites = sig['Metabolite_Name'].value_counts().head(10)
top_pairs = sig['pair'].value_counts().head(10)
# Transporter-based sensors are lower-confidence (bidirectional); separate them
transporter_calls = sig[sig['Annotation'] == 'Transporter']
Goal: Find metabolite communications that differ between conditions (e.g. tumor vs normal).
Approach: Either pass condition_col to a single object, or run MEBOCOST separately per condition subset and compare the significant sets; never compare raw interaction counts across conditions without controlling for cell number and depth.
results = {}
for cond in adata.obs['condition'].unique():
sub = adata[adata.obs['condition'] == cond].copy()
obj = mebocost.create_obj(adata=sub, group_col='cell_type', met_est='mebocost',
config_path='./mebocost.conf', species='human',
cutoff_prop=0.15, thread=8)
results[cond] = obj.infer_commu(n_shuffle=1000, seed=12345, Return=True,
min_cell_number=10, pval_cutoff=0.05)
# A "differential" metabolite call (significant in one condition only) is a HYPOTHESIS for metabolomics
| Parameter | Value | Rationale |
|-----------|-------|-----------|
| cutoff_prop | 0.15 | A chosen dropout floor (MEBOCOST tutorials use 0.15-0.25, not a fixed package default): a gene expressed in <15% of a group is mostly dropout, but real low-abundance signaling is also discarded, so tune per dataset |
| cutoff_exp / cutoff_met | 'auto' | MEBOCOST data-derived thresholds for calling a gene/metabolite present; set manually only with a documented reason |
| n_shuffle | 1000 | Stable label-permutation FDR; the FDR is about label shuffling, not actual metabolite flux |
| min_cell_number | 10 | Groups under ~10 cells give unstable mean expression and inflated scores |
| permutation_test_fdr cutoff | 0.05 | Filter on the FDR, not the raw permutation p-value; significance is statistical, not a measured concentration |
| Symptom | Cause | Fix |
|---------|-------|-----|
| KeyError: 'metabolite' / 'pval' | Result columns are capitalized (Sender, Receiver, Metabolite_Name, Commu_Score, permutation_test_fdr) | Use the exact column names from commu_res.columns |
| AttributeError: module 'mebocost' has no attribute 'create_obj' | Wrong import; create_obj lives in the submodule | from mebocost import mebocost then mebocost.create_obj(...) |
| Almost no metabolites detected | Genes are Ensembl IDs, data is not log-normalized, config_path database is missing, or species does not match the data (mouse data run against the human enzyme/sensor DB) | Convert to gene symbols, log-normalize, point config_path at a valid mebocost.conf, set species to match the organism |
| A cell type "secretes" a metabolite implausibly | Synthase mRNA present but substrate/cofactor absent, or ambient RNA inflated the enzyme | Decontaminate ambient RNA; treat as "machinery consistent with", validate with metabolomics |
| Sender/receiver direction looks reversed | Sensor is a bidirectional/promiscuous transporter | Check Annotation == 'Transporter' calls separately; confirm transport direction |
| More communications in condition B than A | Counts scale with cell number and depth | Compare score magnitudes or matched subsets, not raw counts |
tools
End-to-end CLIP-seq pipeline from FASTQ to ENCODE-compliant binding sites, single-nucleotide crosslink maps, annotation, motifs, and (optionally) differential binding. Use when running the full Yeo lab eCLIP / iCLIP / iCLIP2 / iCLIP3 / irCLIP / PAR-CLIP analysis with SMInput control, protocol-specific UMI extraction, ENCODE STAR parameters, CLIPper or Skipper peak calling with stringent log2 FC and -log10 p thresholds, IDR rescue and self-consistency QC, and downstream motif registration with mCross or PEKA.
development
Detect, date, and contextualize whole-genome duplication (WGD / paleopolyploidy) events using wgd v2 (Chen et al 2024), KsRates (Sensalari 2022 substitution-rate-corrected Ks dating), DupGen_finder (Qiao 2019), MAPS (Li 2018 phylogenomic), POInT (Conant 2008 ordered-block), SLEDGe (2024 ML-based), Whale.jl (Bayesian DL+WGD), and synteny-anchored paranome construction. Use when identifying ancient polyploidy from Ks distributions and synteny block analysis, positioning WGD events relative to speciation, distinguishing tandem from segmental from WGD duplications, dating the 2R/3R vertebrate / fish / salmonid WGDs, building paranome and Ks-age mixture models, applying KsRates substitution-rate correction across lineages, or testing alternative biased-fractionation / dosage-balance models post-WGD.
tools
Build whole-genome alignments using Progressive Cactus (Armstrong 2020 reference-free clade-level WGA), Minigraph-Cactus (Hickey 2024 pangenome-aware), LASTZ chain/net (UCSC pipeline), MUMmer4 (Marçais 2018 pairwise), minimap2 -x asm5/10/20 (Li 2018 fast pairwise), AnchorWave (Song 2022 WGD-aware), and Mauve / progressiveMauve (bacterial). Operates the HAL toolkit (Hickey 2013) for downstream extraction including halSynteny, halLiftover, halBranchMutations, and hal2maf. Use when constructing multi-species alignments for comparative-annotation projection (TOGA), synteny detection, conservation analyses (phyloP / PhastCons), or pangenome graph construction; selecting between reference-free (Cactus) and reference-anchored (LASTZ chains/nets) approaches; tuning sensitivity for closely vs distantly related genomes; or producing HAL files for genome-wide downstream tools.
development
Detect syntenic blocks and structural rearrangements between genomes using MCScanX (Wang 2012), JCVI/MCScan (Tang 2008 Python), GENESPACE (Lovell 2022) for orthology-anchored riparian visualization, SyRI for structural variation, AnchorWave for sequence-level synteny, i-ADHoRe 3.0 for highly diverged species, SynNet for synteny networks, and ntSynt for multi-genome macrosynteny. Use when identifying collinear gene blocks across species, distinguishing macrosynteny from microsynteny, detecting inversions/translocations/duplications, anchoring orthology in WGD lineages, producing publication riparian plots, computing synteny block age via Ks (cross-references whole-genome-duplication), or running synteny-aware ortholog inference in polyploids.