Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Perform in silico gene knockout analysis and synthetic lethality screens using COBRApy single and double deletions. Predict essential genes and identify synthetic lethal pairs for drug target discovery. Use when identifying essential genes or finding synthetic lethal drug targets.
.claude/skills/bio-systems-biology-gene-essentiality/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-21 | ✗→✓ | ▲ Improved | 35% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 44% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 38% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 105% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 26% | 0% |
<!--
#
#
-->
pythonimport cobra from cobra.flux_analysis import single_gene_deletion model = cobra.io.load_model('textbook') # Perform all single gene deletions # Returns growth rate with each gene knocked out deletion_results = single_gene_deletion(model) # deletion_results is a DataFrame with: # - ids: gene IDs (frozenset) # - growth: growth rate after deletion # - status: solver status # Find essential genes (no growth when deleted) # Essential: growth < 0.01 (allowing for numerical tolerance) essential = deletion_results[deletion_results['growth'] < 0.01] print(f'Essential genes: {len(essential)}')
pythondef classify_gene_essentiality(model, growth_threshold=0.1): '''Classify genes by their impact on growth Categories: - Essential: Growth < 1% of WT (lethal) - Growth-reducing: 1-50% of WT - Non-essential: >50% of WT ''' from cobra.flux_analysis import single_gene_deletion # Get wild-type growth wt_growth = model.optimize().objective_value # Run deletions results = single_gene_deletion(model) results['relative_growth'] = results['growth'] / wt_growth # Classify results['classification'] = 'non-essential' results.loc[results['relative_growth'] < 0.5, 'classification'] = 'growth-reducing' results.loc[results['relative_growth'] < 0.01, 'classification'] = 'essential' classification_counts = results['classification'].value_counts() return results, classification_counts
pythonfrom cobra.flux_analysis import double_gene_deletion # Warning: O(n^2) complexity - can be slow for large models # For full E. coli (~1500 genes), this is ~1M combinations # Subset to genes of interest genes_of_interest = [g.id for g in model.genes[:50]] # Run double deletions double_results = double_gene_deletion( model, gene_list1=genes_of_interest, gene_list2=genes_of_interest ) # Find synthetic lethal pairs # Synthetic lethal: double KO is lethal when singles are viable # Get single deletion results first single_results = single_gene_deletion(model, gene_list=genes_of_interest) single_dict = {list(ids)[0]: growth for ids, growth in zip(single_results['ids'], single_results['growth'])}
pythondef find_synthetic_lethal_pairs(model, genes=None, growth_threshold=0.01): '''Find synthetic lethal gene pairs Synthetic lethality criteria: - Single KO of gene A: viable (growth > threshold) - Single KO of gene B: viable (growth > threshold) - Double KO of A+B: lethal (growth < threshold) Useful for: - Drug combination targets - Genetic interaction networks - Backup pathway identification ''' from cobra.flux_analysis import single_gene_deletion, double_gene_deletion if genes is None: genes = [g.id for g in model.genes] # Single deletions single = single_gene_deletion(model, gene_list=genes) viable_singles = single[single['growth'] > growth_threshold] viable_genes = [list(ids)[0] for ids in viable_singles['ids']] # Double deletions (only for viable single KOs) double = double_gene_deletion(model, gene_list1=viable_genes, gene_list2=viable_genes) # Find synthetic lethal pairs sl_pairs = [] for _, row in double.iterrows(): genes_in_pair = list(row['ids']) if len(genes_in_pair) == 2 and row['growth'] < growth_threshold: sl_pairs.append({ 'gene1': genes_in_pair[0], 'gene2': genes_in_pair[1], 'double_ko_growth': row['growth'] }) return sl_pairs
pythondef compare_essentiality_conditions(model, conditions): '''Compare gene essentiality across conditions Args: conditions: dict mapping condition name to media setup function Example: conditions = { 'aerobic': lambda m: m.reactions.EX_o2_e.lower_bound = -20, 'anaerobic': lambda m: m.reactions.EX_o2_e.lower_bound = 0 } ''' from cobra.flux_analysis import single_gene_deletion essentiality_by_condition = {} for condition_name, setup_func in conditions.items(): with model: setup_func(model) results = single_gene_deletion(model) essential = set(list(ids)[0] for ids in results[results['growth'] < 0.01]['ids']) essentiality_by_condition[condition_name] = essential # Find condition-specific essential genes all_essential = set.union(*essentiality_by_condition.values()) core_essential = set.intersection(*essentiality_by_condition.values()) condition_specific = {cond: ess - core_essential for cond, ess in essentiality_by_condition.items()} return { 'core_essential': core_essential, 'condition_specific': condition_specific, 'total_essential': len(all_essential) }
pythondef gene_robustness_analysis(model, gene_id, flux_levels=10): '''Analyze growth as function of gene expression level Instead of complete knockout, simulate reduced expression by constraining reactions associated with the gene. ''' from cobra.flux_analysis import flux_variability_analysis gene = model.genes.get_by_id(gene_id) # Get reactions associated with this gene rxns = list(gene.reactions) results = [] for level in [i/flux_levels for i in range(flux_levels + 1)]: with model: for rxn in rxns: # Get FVA bounds at wild-type fva = flux_variability_analysis(model, reaction_list=[rxn]) max_flux = fva.loc[rxn.id, 'maximum'] min_flux = fva.loc[rxn.id, 'minimum'] # Constrain to fraction of wild-type rxn.upper_bound = max_flux * level rxn.lower_bound = min_flux * level sol = model.optimize() results.append({ 'expression_level': level, 'growth': sol.objective_value }) return results
<!-- 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-20 | pass→fail | 9,052 | 5,314 | -41% | 1 | 1 | 0% | 1,499 | 2,165 | +44% | 0 | 0 | — |
case-21 | fail→pass | 9,702 | 3,127 | -68% | 1 | 1 | 0% | 1,731 | 2,343 | +35% | 0 | 0 | — |
case-10 | pass→pass | 17,860 | 4,634 | -74% | 1 | 1 | 0% | 3,150 | 2,762 | -12% | 0 | 0 | — |
case-01 | fail→pass | 13,386 | 9,949 | -26% | 1 | 1 | 0% | 2,943 | 4,239 | +44% | 0 | 0 | — |
case-02 | fail→pass | 14,546 | 10,954 | -25% | 1 | 1 | 0% | 3,091 | 4,264 | +38% | 0 | 0 | — |
case-03 | pass→pass | 12,586 | 6,657 | -47% | 1 | 1 | 0% | 2,282 | 3,117 | +37% | 0 | 0 | — |
case-04 | pass→pass | 11,346 | 11,244 | -1% | 1 | 1 | 0% | 2,259 | 4,145 | +83% | 0 | 0 | — |
case-05 | pass→pass | 4,823 | 4,011 | -17% | 1 | 1 | 0% | 867 | 2,688 | +210% | 0 | 0 | — |
case-06 | pass→pass | 24,514 | 10,102 | -59% | 1 | 1 | 0% | 1,443 | 3,767 | +161% | 0 | 0 | — |
case-07 | pass→pass | 17,135 | 11,339 | -34% | 1 | 1 | 0% | 2,966 | 4,126 | +39% | 0 | 0 | — |
case-08 | fail→pass | 18,923 | 4,167 | -78% | 1 | 1 | 0% | 1,337 | 2,735 | +105% | 0 | 0 | — |
case-09 | pass→pass | 9,712 | 7,959 | -18% | 1 | 1 | 0% | 1,954 | 2,708 | +39% | 0 | 0 | — |
case-11 | pass→fail | 15,146 | 11,324 | -25% | 1 | 1 | 0% | 3,136 | 4,136 | +32% | 0 | 0 | — |
case-12 | pass→pass | 13,061 | 13,679 | +5% | 1 | 1 | 0% | 2,601 | 4,635 | +78% | 0 | 0 | — |
case-13 | pass→pass | 7,528 | 4,764 | -37% | 1 | 1 | 0% | 1,441 | 2,735 | +90% | 0 | 0 | — |
case-14 | pass→fail | 7,848 | 5,813 | -26% | 1 | 1 | 0% | 1,356 | 2,988 | +120% | 0 | 0 | — |
case-15 | pass→pass | 7,945 | 1,910 | -76% | 1 | 1 | 0% | 1,334 | 2,240 | +68% | 0 | 0 | — |
case-16 | pass→pass | 25,894 | 4,362 | -83% | 1 | 1 | 0% | 2,635 | 2,637 | +0% | 0 | 0 | — |
case-17 | pass→pass | 8,298 | 4,332 | -48% | 1 | 1 | 0% | 1,577 | 2,670 | +69% | 0 | 0 | — |
case-18 | pass→pass | 9,214 | 4,643 | -50% | 1 | 1 | 0% | 1,715 | 2,657 | +55% | 0 | 0 | — |
case-19 | fail→pass | 12,788 | 6,256 | -51% | 1 | 1 | 0% | 2,430 | 3,067 | +26% | 0 | 0 | — |
case-22 | pass→pass | 10,570 | 2,414 | -77% | 1 | 1 | 0% | 1,994 | 2,318 | +16% | 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 20 counted toward the lift figure. The other 2 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 +9 percentage points is the difference between those two pass rates over the 20 comparable cases. 3 cases got worse with the skill loaded, and they are included in that figure.
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/26/2026 | +14% |
Other measured skills in the registry, with their headline benchmark lift.