Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Query PubChem via PUG-REST API/PubChemPy (110M+ compounds). Search by name/CID/SMILES, retrieve properties, similarity/substructure searches, bioactivity, for cheminformatics.
.claude/skills/pubchem-database/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-19 | ✗→✓ | ▲ Improved | — | — |
| case-20 | ✓→✓ | = Same ✓ | — | — |
| case-14 | ✗→✗ | = Same ✗ | — | — |
| case-18 | ✗→✗ | = Same ✗ | — | — |
| case-21 | ✗→✗ | = Same ✗ | — | — |
PubChem is the world's largest freely available chemical database with 110M+ compounds and 270M+ bioactivities. Query chemical structures by name, CID, or SMILES, retrieve molecular properties, perform similarity and substructure searches, access bioactivity data using PUG-REST API and PubChemPy.
This skill should be used when:
Search for compounds using multiple identifier types:
By Chemical Name:
pythonimport pubchempy as pcp compounds = pcp.get_compounds('aspirin', 'name') compound = compounds[0]
By CID (Compound ID):
pythoncompound = pcp.Compound.from_cid(2244) # Aspirin
By SMILES:
pythoncompound = pcp.get_compounds('CC(=O)OC1=CC=CC=C1C(=O)O', 'smiles')[0]
By InChI:
pythoncompound = pcp.get_compounds('InChI=1S/C9H8O4/...', 'inchi')[0]
By Molecular Formula:
pythoncompounds = pcp.get_compounds('C9H8O4', 'formula') # Returns all compounds matching this formula
Retrieve molecular properties for compounds using either high-level or low-level approaches:
Using PubChemPy (Recommended):
pythonimport pubchempy as pcp # Get compound object with all properties compound = pcp.get_compounds('caffeine', 'name')[0] # Access individual properties molecular_formula = compound.molecular_formula molecular_weight = compound.molecular_weight iupac_name = compound.iupac_name smiles = compound.canonical_smiles inchi = compound.inchi xlogp = compound.xlogp # Partition coefficient tpsa = compound.tpsa # Topological polar surface area
Get Specific Properties:
python# Request only specific properties properties = pcp.get_properties( ['MolecularFormula', 'MolecularWeight', 'CanonicalSMILES', 'XLogP'], 'aspirin', 'name' ) # Returns list of dictionaries
Batch Property Retrieval:
pythonimport pandas as pd compound_names = ['aspirin', 'ibuprofen', 'paracetamol'] all_properties = [] for name in compound_names: props = pcp.get_properties( ['MolecularFormula', 'MolecularWeight', 'XLogP'], name, 'name' ) all_properties.extend(props) df = pd.DataFrame(all_properties)
Available Properties: MolecularFormula, MolecularWeight, CanonicalSMILES, IsomericSMILES, InChI, InChIKey, IUPACName, XLogP, TPSA, HBondDonorCount, HBondAcceptorCount, RotatableBondCount, Complexity, Charge, and many more (see references/api_reference.md for complete list).
Find structurally similar compounds using Tanimoto similarity:
pythonimport pubchempy as pcp # Start with a query compound query_compound = pcp.get_compounds('gefitinib', 'name')[0] query_smiles = query_compound.canonical_smiles # Perform similarity search similar_compounds = pcp.get_compounds( query_smiles, 'smiles', searchtype='similarity', Threshold=85, # Similarity threshold (0-100) MaxRecords=50 ) # Process results for compound in similar_compounds[:10]: print(f"CID {compound.cid}: {compound.iupac_name}") print(f" MW: {compound.molecular_weight}")
Note: Similarity searches are asynchronous for large queries and may take 15-30 seconds to complete. PubChemPy handles the asynchronous pattern automatically.
Find compounds containing a specific structural motif:
pythonimport pubchempy as pcp # Search for compounds containing pyridine ring pyridine_smiles = 'c1ccncc1' matches = pcp.get_compounds( pyridine_smiles, 'smiles', searchtype='substructure', MaxRecords=100 ) print(f"Found {len(matches)} compounds containing pyridine")
Common Substructures:
c1ccccc1c1ccncc1c1ccc(O)cc1C(=O)OConvert between different chemical structure formats:
pythonimport pubchempy as pcp compound = pcp.get_compounds('aspirin', 'name')[0] # Convert to different formats smiles = compound.canonical_smiles inchi = compound.inchi inchikey = compound.inchikey cid = compound.cid # Download structure files pcp.download('SDF', 'aspirin', 'name', 'aspirin.sdf', overwrite=True) pcp.download('JSON', '2244', 'cid', 'aspirin.json', overwrite=True)
Generate 2D structure images:
pythonimport pubchempy as pcp # Download compound structure as PNG pcp.download('PNG', 'caffeine', 'name', 'caffeine.png', overwrite=True) # Using direct URL (via requests) import requests cid = 2244 # Aspirin url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cid}/PNG?image_size=large" response = requests.get(url) with open('structure.png', 'wb') as f: f.write(response.content)
Get all known names and synonyms for a compound:
pythonimport pubchempy as pcp synonyms_data = pcp.get_synonyms('aspirin', 'name') if synonyms_data: cid = synonyms_data[0]['CID'] synonyms = synonyms_data[0]['Synonym'] print(f"CID {cid} has {len(synonyms)} synonyms:") for syn in synonyms[:10]: # First 10 print(f" - {syn}")
Retrieve biological activity data from assays:
pythonimport requests import json # Get bioassay summary for a compound cid = 2244 # Aspirin url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cid}/assaysummary/JSON" response = requests.get(url) if response.status_code == 200: data = response.json() # Process bioassay information table = data.get('Table', {}) rows = table.get('Row', []) print(f"Found {len(rows)} bioassay records")
For more complex bioactivity queries, use the scripts/bioactivity_query.py helper script which provides:
Access detailed compound information through PUG-View:
pythonimport requests cid = 2244 url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/{cid}/JSON" response = requests.get(url) if response.status_code == 200: annotations = response.json() # Contains extensive data including: # - Chemical and Physical Properties # - Drug and Medication Information # - Pharmacology and Biochemistry # - Safety and Hazards # - Toxicity # - Literature references # - Patents
Get Specific Section:
python# Get only drug information url = f"https://pubchem.ncbi.nlm.nih.gov/rest/pug_view/data/compound/{cid}/JSON?heading=Drug and Medication Information"
Install PubChemPy for Python-based access:
bashuv pip install pubchempy
For direct API access and bioactivity queries:
bashuv pip install requests
Optional for data analysis:
bashuv pip install pandas
This skill includes Python scripts for common PubChem tasks:
Provides utility functions for searching and retrieving compound information:
Key Functions:
search_by_name(name, max_results=10): Search compounds by namesearch_by_smiles(smiles): Search by SMILES stringget_compound_by_cid(cid): Retrieve compound by CIDget_compound_properties(identifier, namespace, properties): Get specific propertiessimilarity_search(smiles, threshold, max_records): Perform similarity searchsubstructure_search(smiles, max_records): Perform substructure searchget_synonyms(identifier, namespace): Get all synonymsbatch_search(identifiers, namespace, properties): Batch search multiple compoundsdownload_structure(identifier, namespace, format, filename): Download structuresprint_compound_info(compound): Print formatted compound informationUsage:
pythonfrom scripts.compound_search import search_by_name, get_compound_properties # Search for a compound compounds = search_by_name('ibuprofen') # Get specific properties props = get_compound_properties('aspirin', 'name', ['MolecularWeight', 'XLogP'])
Provides functions for retrieving biological activity data:
Key Functions:
get_bioassay_summary(cid): Get bioassay summary for compoundget_compound_bioactivities(cid, activity_outcome): Get filtered bioactivitiesget_assay_description(aid): Get detailed assay informationget_assay_targets(aid): Get biological targets for assaysearch_assays_by_target(target_name, max_results): Find assays by targetget_active_compounds_in_assay(aid, max_results): Get active compoundsget_compound_annotations(cid, section): Get PUG-View annotationssummarize_bioactivities(cid): Generate bioactivity summary statisticsfind_compounds_by_bioactivity(target, threshold, max_compounds): Find compounds by targetUsage:
pythonfrom scripts.bioactivity_query import get_bioassay_summary, summarize_bioactivities # Get bioactivity summary summary = summarize_bioactivities(2244) # Aspirin print(f"Total assays: {summary['total_assays']}") print(f"Active: {summary['active']}, Inactive: {summary['inactive']}")
Rate Limits:
Best Practices:
Error Handling:
pythonfrom pubchempy import BadRequestError, NotFoundError, TimeoutError try: compound = pcp.get_compounds('query', 'name')[0] except NotFoundError: print("Compound not found") except BadRequestError: print("Invalid request format") except TimeoutError: print("Request timed out - try reducing scope") except IndexError: print("No results returned")
Convert between different chemical identifiers:
pythonimport pubchempy as pcp # Start with any identifier type compound = pcp.get_compounds('caffeine', 'name')[0] # Extract all identifier formats identifiers = { 'CID': compound.cid, 'Name': compound.iupac_name, 'SMILES': compound.canonical_smiles, 'InChI': compound.inchi, 'InChIKey': compound.inchikey, 'Formula': compound.molecular_formula }
Screen compounds using Lipinski's Rule of Five:
pythonimport pubchempy as pcp def check_drug_likeness(compound_name): compound = pcp.get_compounds(compound_name, 'name')[0] # Lipinski's Rule of Five rules = { 'MW <= 500': compound.molecular_weight <= 500, 'LogP <= 5': compound.xlogp <= 5 if compound.xlogp else None, 'HBD <= 5': compound.h_bond_donor_count <= 5, 'HBA <= 10': compound.h_bond_acceptor_count <= 10 } violations = sum(1 for v in rules.values() if v is False) return rules, violations rules, violations = check_drug_likeness('aspirin') print(f"Lipinski violations: {violations}")
Identify structurally similar compounds to a known drug:
pythonimport pubchempy as pcp # Start with known drug reference_drug = pcp.get_compounds('imatinib', 'name')[0] reference_smiles = reference_drug.canonical_smiles # Find similar compounds similar = pcp.get_compounds( reference_smiles, 'smiles', searchtype='similarity', Threshold=85, MaxRecords=20 ) # Filter by drug-like properties candidates = [] for comp in similar: if comp.molecular_weight and 200 <= comp.molecular_weight <= 600: if comp.xlogp and -1 <= comp.xlogp <= 5: candidates.append(comp) print(f"Found {len(candidates)} drug-like candidates")
Compare properties across multiple compounds:
pythonimport pubchempy as pcp import pandas as pd compound_list = ['aspirin', 'ibuprofen', 'naproxen', 'celecoxib'] properties_list = [] for name in compound_list: try: compound = pcp.get_compounds(name, 'name')[0] properties_list.append({ 'Name': name, 'CID': compound.cid, 'Formula': compound.molecular_formula, 'MW': compound.molecular_weight, 'LogP': compound.xlogp, 'TPSA': compound.tpsa, 'HBD': compound.h_bond_donor_count, 'HBA': compound.h_bond_acceptor_count }) except Exception as e: print(f"Error processing {name}: {e}") df = pd.DataFrame(properties_list) print(df.to_string(index=False))
Screen for compounds containing specific pharmacophores:
pythonimport pubchempy as pcp # Define pharmacophore (e.g., sulfonamide group) pharmacophore_smiles = 'S(=O)(=O)N' # Search for compounds containing this substructure hits = pcp.get_compounds( pharmacophore_smiles, 'smiles', searchtype='substructure', MaxRecords=100 ) # Further filter by properties filtered_hits = [ comp for comp in hits if comp.molecular_weight and comp.molecular_weight < 500 ] print(f"Found {len(filtered_hits)} compounds with desired substructure")
For detailed API documentation, including complete property lists, URL patterns, advanced query options, and more examples, consult references/api_reference.md. This comprehensive reference includes:
Compound Not Found:
Timeout Errors:
Empty Property Values:
if compound.xlogp:Rate Limit Exceeded:
Similarity/Substructure Search Hangs:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-14 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-18 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | pass→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 +5 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.