Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Build tissue and condition-specific metabolic models using GIMME, iMAT, and INIT algorithms with expression data constraints. Create models that reflect cell-type specific metabolism. Use when building tissue-specific metabolic models or integrating transcriptomics with FBA.
.claude/skills/bio-systems-biology-context-specific-models/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-19 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 32% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 10% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 10% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 249% | 0% |
<!--
#
#
-->
pythonimport cobra import numpy as np def gimme(model, expression_data, threshold=0.25, required_growth=0.1): '''Gene Inactivity Moderated by Metabolism and Expression (GIMME) Creates context-specific model by: 1. Penalizing flux through lowly-expressed reactions 2. Requiring minimum biomass production Args: expression_data: dict mapping gene_id -> expression value threshold: Expression percentile below which genes are inactive 0.25 = bottom 25% considered inactive required_growth: Minimum growth rate to maintain Returns: Context-specific model with inactive reactions constrained ''' # Calculate expression threshold values = list(expression_data.values()) cutoff = np.percentile(values, threshold * 100) # Identify lowly-expressed genes low_expressed = {g for g, v in expression_data.items() if v < cutoff} # Create context model context_model = model.copy() # Set minimum growth constraint context_model.reactions.get_by_id('Biomass_Ecoli_core').lower_bound = required_growth # Minimize flux through reactions with low-expressed genes for rxn in context_model.reactions: genes = {g.id for g in rxn.genes} if genes and genes.issubset(low_expressed): # This reaction is likely inactive - constrain it rxn.upper_bound = min(rxn.upper_bound, 1.0) rxn.lower_bound = max(rxn.lower_bound, -1.0) return context_model
pythondef imat(model, expression_data, high_threshold=0.75, low_threshold=0.25): '''Integrative Metabolic Analysis Tool (iMAT) Maximizes agreement between flux activity and expression: - Highly expressed reactions should carry flux - Lowly expressed reactions should have zero flux More sophisticated than GIMME - uses MILP optimization. ''' from cobra import Reaction # Classify reactions by expression high_expr_rxns = [] low_expr_rxns = [] for rxn in model.reactions: if rxn.genes: # Aggregate gene expression (use max for OR, min for AND) gene_expr = [expression_data.get(g.id, 0.5) for g in rxn.genes] rxn_expr = max(gene_expr) # Simplified OR logic if rxn_expr > np.percentile(list(expression_data.values()), high_threshold * 100): high_expr_rxns.append(rxn.id) elif rxn_expr < np.percentile(list(expression_data.values()), low_threshold * 100): low_expr_rxns.append(rxn.id) # Create MILP to maximize consistent reactions # This is a simplified version - full iMAT uses binary variables context_model = model.copy() # Force flux through highly expressed reactions for rxn_id in high_expr_rxns: rxn = context_model.reactions.get_by_id(rxn_id) rxn.lower_bound = max(rxn.lower_bound, 0.01) # Constrain lowly expressed reactions for rxn_id in low_expr_rxns: rxn = context_model.reactions.get_by_id(rxn_id) rxn.upper_bound = min(rxn.upper_bound, 0.1) rxn.lower_bound = max(rxn.lower_bound, -0.1) return context_model, high_expr_rxns, low_expr_rxns
pythondef load_expression_data(filepath, gene_col='gene_id', expr_col='TPM'): '''Load and normalize expression data Accepts: - RNA-seq counts (TPM, FPKM) - Microarray intensities - Proteomics abundances Returns dict mapping gene_id -> normalized expression ''' import pandas as pd df = pd.read_csv(filepath) # Log-transform if needed (high dynamic range) expr = df[expr_col].values if expr.max() / expr.mean() > 100: expr = np.log2(expr + 1) # Normalize to 0-1 range expr_norm = (expr - expr.min()) / (expr.max() - expr.min()) return dict(zip(df[gene_col], expr_norm)) def aggregate_gene_expression(model, expression_data, method='max'): '''Map gene expression to reactions Methods: - 'max': Use maximum gene expression (OR logic) - 'min': Use minimum gene expression (AND logic) - 'mean': Average across genes For GPR: (A and B) or C - min(A, B) for the complex - max(complex, C) for the alternatives ''' rxn_expression = {} for rxn in model.reactions: if not rxn.genes: rxn_expression[rxn.id] = 0.5 # Default for non-enzymatic continue gene_expr = [expression_data.get(g.id, 0.5) for g in rxn.genes] if method == 'max': rxn_expression[rxn.id] = max(gene_expr) elif method == 'min': rxn_expression[rxn.id] = min(gene_expr) else: rxn_expression[rxn.id] = np.mean(gene_expr) return rxn_expression
pythondef create_tissue_model(generic_model, gtex_expression, tissue='liver'): '''Create tissue-specific model from GTEx expression data GTEx provides median TPM for 54 human tissues. Download from: https://gtexportal.org/home/datasets ''' import pandas as pd # Load GTEx median expression gtex = pd.read_csv(gtex_expression, sep='\t') # Extract tissue column tissue_col = [c for c in gtex.columns if tissue.lower() in c.lower()][0] expression = dict(zip(gtex['gene_id'], gtex[tissue_col])) # Apply GIMME tissue_model = gimme(generic_model, expression, threshold=0.25) return tissue_model
pythondef validate_context_model(original, context, expression_data): '''Compare original and context-specific models Checks: 1. Growth capability maintained 2. Inactive reactions reduced 3. Active reactions maintained ''' # Growth comparison orig_growth = original.optimize().objective_value context_growth = context.optimize().objective_value # Count constrained reactions constrained = 0 for rxn in context.reactions: orig_rxn = original.reactions.get_by_id(rxn.id) if rxn.upper_bound < orig_rxn.upper_bound: constrained += 1 return { 'original_growth': orig_growth, 'context_growth': context_growth, 'growth_ratio': context_growth / orig_growth, 'constrained_reactions': constrained, 'total_reactions': len(context.reactions) }
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-19 | fail→pass | 9,242 | 2,516 | -73% | 1 | 1 | 0% | 1,704 | 2,492 | +46% | 0 | 0 | — |
case-01 | fail→fail | 19,134 | 21,002 | +10% | 1 | 1 | 0% | 4,050 | 6,299 | +56% | 0 | 0 | — |
case-07 | fail→fail | 17,269 | 10,370 | -40% | 1 | 1 | 0% | 3,205 | 4,042 | +26% | 0 | 0 | — |
case-08 | fail→pass | 29,196 | 4,475 | -85% | 1 | 1 | 0% | 2,156 | 2,836 | +32% | 0 | 0 | — |
case-09 | fail→fail | 8,723 | 11,273 | +29% | 1 | 1 | 0% | 1,762 | 4,284 | +143% | 0 | 0 | — |
case-02 | fail→fail | 31,529 | 17,122 | -46% | 1 | 1 | 0% | 6,224 | 5,838 | -6% | 0 | 0 | — |
case-03 | fail→pass | 23,722 | 17,563 | -26% | 1 | 1 | 0% | 5,067 | 5,596 | +10% | 0 | 0 | — |
case-04 | pass→pass | 14,035 | 13,240 | -6% | 1 | 1 | 0% | 2,990 | 4,795 | +60% | 0 | 0 | — |
case-05 | pass→pass | 21,298 | 9,570 | -55% | 1 | 1 | 0% | 1,896 | 4,037 | +113% | 0 | 0 | — |
case-06 | pass→pass | 12,282 | 12,830 | +4% | 1 | 1 | 0% | 2,662 | 4,853 | +82% | 0 | 0 | — |
case-10 | pass→pass | 6,623 | 3,888 | -41% | 1 | 1 | 0% | 1,197 | 2,672 | +123% | 0 | 0 | — |
case-11 | pass→pass | 8,790 | 6,238 | -29% | 1 | 1 | 0% | 1,580 | 3,256 | +106% | 0 | 0 | — |
case-12 | fail→pass | 18,110 | 10,205 | -44% | 1 | 1 | 0% | 3,530 | 3,886 | +10% | 0 | 0 | — |
case-13 | pass→pass | 7,714 | 3,092 | -60% | 1 | 1 | 0% | 1,399 | 2,508 | +79% | 0 | 0 | — |
case-14 | fail→pass | 31,456 | 11,218 | -64% | 1 | 1 | 0% | 1,263 | 4,409 | +249% | 0 | 0 | — |
case-15 | fail→pass | 15,991 | 5,199 | -67% | 1 | 1 | 0% | 2,744 | 3,011 | +10% | 0 | 0 | — |
case-16 | fail→pass | 11,291 | 3,301 | -71% | 1 | 1 | 0% | 2,254 | 2,693 | +19% | 0 | 0 | — |
case-17 | fail→pass | 14,184 | 11,641 | -18% | 1 | 1 | 0% | 2,766 | 3,421 | +24% | 0 | 0 | — |
case-18 | pass→pass | 8,236 | 2,594 | -69% | 1 | 1 | 0% | 1,283 | 2,504 | +95% | 0 | 0 | — |
case-20 | pass→pass | 12,183 | 3,558 | -71% | 1 | 1 | 0% | 2,252 | 2,676 | +19% | 0 | 0 | — |
case-21 | fail→pass | 7,406 | 3,592 | -51% | 1 | 1 | 0% | 1,356 | 2,532 | +87% | 0 | 0 | — |
case-22 | pass→pass | 9,094 | 5,958 | -34% | 1 | 1 | 0% | 1,645 | 3,073 | +87% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +41 percentage points is the difference between those two pass rates over the 21 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +38% |
Other measured skills in the registry, with their headline benchmark lift.