Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Medicinal chemistry filters. Apply drug-likeness rules (Lipinski, Veber), PAINS filters, structural alerts, complexity metrics, for compound prioritization and library filtering.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | — | — |
| case-13 | ✗→✓ | ▲ Improved | — | — |
| case-14 | ✗→✓ | ▲ Improved | — | — |
| case-17 | ✗→✓ | ▲ Improved | — | — |
| case-19 | ✗→✓ | ▲ Improved | — | — |
Medchem is a Python library for molecular filtering and prioritization in drug discovery workflows. Apply hundreds of well-established and novel molecular filters, structural alerts, and medicinal chemistry rules to efficiently triage and prioritize compound libraries at scale. Rules and filters are context-specific—use as guidelines combined with domain expertise.
This skill should be used when:
bashuv pip install medchem
Apply established drug-likeness rules to molecules using the medchem.rules module.
Available Rules:
Single Rule Application:
pythonimport medchem as mc # Apply Rule of Five to a SMILES string smiles = "CC(=O)OC1=CC=CC=C1C(=O)O" # Aspirin passes = mc.rules.basic_rules.rule_of_five(smiles) # Returns: True # Check specific rules passes_oprea = mc.rules.basic_rules.rule_of_oprea(smiles) passes_cns = mc.rules.basic_rules.rule_of_cns(smiles)
Multiple Rules with RuleFilters:
pythonimport datamol as dm import medchem as mc # Load molecules mols = [dm.to_mol(smiles) for smiles in smiles_list] # Create filter with multiple rules rfilter = mc.rules.RuleFilters( rule_list=[ "rule_of_five", "rule_of_oprea", "rule_of_cns", "rule_of_leadlike_soft" ] ) # Apply filters with parallelization results = rfilter( mols=mols, n_jobs=-1, # Use all CPU cores progress=True )
Result Format: Results are returned as dictionaries with pass/fail status and detailed information for each rule.
Detect potentially problematic structural patterns using the medchem.structural module.
Available Filters:
Common Alerts:
pythonimport medchem as mc # Create filter alert_filter = mc.structural.CommonAlertsFilters() # Check single molecule mol = dm.to_mol("c1ccccc1") has_alerts, details = alert_filter.check_mol(mol) # Batch filtering with parallelization results = alert_filter( mols=mol_list, n_jobs=-1, progress=True )
NIBR Filters:
pythonimport medchem as mc # Apply NIBR filters nibr_filter = mc.structural.NIBRFilters() results = nibr_filter(mols=mol_list, n_jobs=-1)
Lilly Demerits:
pythonimport medchem as mc # Calculate Lilly demerits lilly = mc.structural.LillyDemeritsFilters() results = lilly(mols=mol_list, n_jobs=-1) # Each result includes demerit score and whether it passes (≤100 demerits)
The medchem.functional module provides convenient functions for common workflows.
Quick Filtering:
pythonimport medchem as mc # Apply NIBR filters to a list filter_ok = mc.functional.nibr_filter( mols=mol_list, n_jobs=-1 ) # Apply common alerts alert_results = mc.functional.common_alerts_filter( mols=mol_list, n_jobs=-1 )
Identify specific chemical groups and functional groups using medchem.groups.
Available Groups:
Usage:
pythonimport medchem as mc # Create group detector group = mc.groups.ChemicalGroup(groups=["hinge_binders"]) # Check for matches has_matches = group.has_match(mol_list) # Get detailed match information matches = group.get_matches(mol)
Access curated collections of chemical structures through medchem.catalogs.
Available Catalogs:
Usage:
pythonimport medchem as mc # Access named catalogs catalogs = mc.catalogs.NamedCatalogs # Use catalog for matching catalog = catalogs.get("functional_groups") matches = catalog.get_matches(mol)
Calculate complexity metrics that approximate synthetic accessibility using medchem.complexity.
Common Metrics:
Usage:
pythonimport medchem as mc # Calculate complexity complexity_score = mc.complexity.calculate_complexity(mol) # Filter by complexity threshold complex_filter = mc.complexity.ComplexityFilter(max_complexity=500) results = complex_filter(mols=mol_list)
Apply custom property-based constraints using medchem.constraints.
Example Constraints:
Usage:
pythonimport medchem as mc # Define constraints constraints = mc.constraints.Constraints( mw_range=(200, 500), logp_range=(-2, 5), tpsa_max=140, rotatable_bonds_max=10 ) # Apply constraints results = constraints(mols=mol_list, n_jobs=-1)
Use a specialized query language for complex filtering criteria.
Query Examples:
# Molecules passing Ro5 AND not having common alerts
"rule_of_five AND NOT common_alerts"
# CNS-like molecules with low complexity
"rule_of_cns AND complexity < 400"
# Leadlike molecules without Lilly demerits
"rule_of_leadlike AND lilly_demerits == 0"Usage:
pythonimport medchem as mc # Parse and apply query query = mc.query.parse("rule_of_five AND NOT common_alerts") results = query.apply(mols=mol_list, n_jobs=-1)
Filter a large compound collection to identify drug-like candidates.
pythonimport datamol as dm import medchem as mc import pandas as pd # Load compound library df = pd.read_csv("compounds.csv") mols = [dm.to_mol(smi) for smi in df["smiles"]] # Apply primary filters rule_filter = mc.rules.RuleFilters(rule_list=["rule_of_five", "rule_of_veber"]) rule_results = rule_filter(mols=mols, n_jobs=-1, progress=True) # Apply structural alerts alert_filter = mc.structural.CommonAlertsFilters() alert_results = alert_filter(mols=mols, n_jobs=-1, progress=True) # Combine results df["passes_rules"] = rule_results["pass"] df["has_alerts"] = alert_results["has_alerts"] df["drug_like"] = df["passes_rules"] & ~df["has_alerts"] # Save filtered compounds filtered_df = df[df["drug_like"]] filtered_df.to_csv("filtered_compounds.csv", index=False)
Apply stricter criteria during lead optimization.
pythonimport medchem as mc # Create comprehensive filter filters = { "rules": mc.rules.RuleFilters(rule_list=["rule_of_leadlike_strict"]), "alerts": mc.structural.NIBRFilters(), "lilly": mc.structural.LillyDemeritsFilters(), "complexity": mc.complexity.ComplexityFilter(max_complexity=400) } # Apply all filters results = {} for name, filt in filters.items(): results[name] = filt(mols=candidate_mols, n_jobs=-1) # Identify compounds passing all filters passes_all = all(r["pass"] for r in results.values())
Find molecules containing specific functional groups or scaffolds.
pythonimport medchem as mc # Create group detector for multiple groups group_detector = mc.groups.ChemicalGroup( groups=["hinge_binders", "phosphate_binders"] ) # Screen library matches = group_detector.get_all_matches(mol_list) # Filter molecules with desired groups mol_with_groups = [mol for mol, match in zip(mol_list, matches) if match]
n_jobs=-1 for parallel processing.Comprehensive API reference covering all medchem modules with detailed function signatures, parameters, and return types.
Complete catalog of available rules, filters, and alerts with descriptions, thresholds, and literature references.
Production-ready script for batch filtering workflows. Supports multiple input formats (CSV, SDF, SMILES), configurable filter combinations, and detailed reporting.
Usage:
bashpython scripts/filter_molecules.py input.csv --rules rule_of_five,rule_of_cns --alerts nibr --output filtered.csv
Official documentation: https://medchem-docs.datamol.io/ GitHub repository: https://github.com/datamol-io/medchem
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
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. The headline lift of +73 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
Other measured skills in the registry, with their headline benchmark lift.