alterlab-zinc-db — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited alterlab-zinc-db (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
ZINC is a freely accessible repository of 230M+ purchasable compounds maintained by UCSF. Search by ZINC ID or SMILES, perform similarity searches, download 3D-ready structures for docking, discover analogs for virtual screening and drug discovery.
scripts/query_zinc.py — query the ZINC22 CartBlanche API via form-encoded POST (stdlib only, JSON to stdout):
python scripts/query_zinc.py id ZINC000019632618 # ZINC-ID lookup
python scripts/query_zinc.py smiles "c1ccccc1" --dist 3 # SMILES similarity search
python scripts/query_zinc.py random --count 100 --subset lead-like # random sampleEvery CartBlanche search is asynchronous. Each call returns a JSON task handle ({"task": "<uuid>"}); the result rows are assembled server-side and rendered in the web UI at https://cartblanche22.docking.org. There is no plain-text polling endpoint — the task route serves the single-page app. Use the script to submit searches and obtain the task id, then open the UI to retrieve/export rows, or use the bulk file repository (below) for programmatic large-scale retrieval.
This skill should be used when:
ZINC has evolved through multiple versions:
This skill primarily focuses on ZINC22, the most current and comprehensive version.
Primary access point: https://zinc.docking.org/ Interactive searching: https://cartblanche22.docking.org/
All ZINC22 searches can be performed programmatically via the CartBlanche22 API:
Base URL: https://cartblanche22.docking.org/
Searches are submitted as form-encoded POST requests (the scripts/query_zinc.py helper does this) or as curl -F form-field uploads. Endpoints accept either an inline value or an @file upload, and every search returns a JSON task handle ({"task": "<uuid>"}) — results are then rendered in the web UI. Pass the desired columns via the output_fields form field.
The older "colon URL" form (/substances.txt:zinc_id=...) does not work against the current CartBlanche22 service; use form fields as shown below.Retrieve specific compounds using their ZINC identifiers.
Web interface: https://cartblanche22.docking.org/search/zincid
API endpoint (form field is zinc_ids, plural — the singular zinc_id returns HTTP 400):
# Inline list of IDs
curl -X GET "https://cartblanche22.docking.org/substances.txt" \
-F zinc_ids="ZINC000019632618,ZINC000000000001" \
-F output_fields="zinc_id,smiles,catalogs"
# Or upload a file of IDs (one per line)
curl -X GET "https://cartblanche22.docking.org/substances.txt" \
-F zinc_ids=@zinc_ids.txt \
-F output_fields="zinc_id,smiles,tranche"Both return a task handle; open the printed UI task URL to view rows.
Response fields: zinc_id, smiles, sub_id, supplier_code, catalogs, tranche (includes H-count, LogP, MW, phase)
Find compounds by chemical structure using SMILES notation, with optional distance parameters for analog searching.
Web interface: https://cartblanche22.docking.org/search/smiles
API endpoint:
curl -X GET "https://cartblanche22.docking.org/smiles.txt" \
-F smiles="c1ccccc1" -F dist=3 -F adist=3 \
-F output_fields="zinc_id,smiles,tranche"Parameters (each passed as a -F form field):
smiles: Query SMILES string (inline, or @file for a batch of queries)dist: Tanimoto distance threshold (default: 0 for exact match)adist: Anonymous (graph-topology) distance for broader searches (default: 0)output_fields: Comma-separated list of desired output fieldsExample - Exact match (dist/adist default to 0):
curl -X GET "https://cartblanche22.docking.org/smiles.txt" -F smiles="c1ccccc1"Query compounds from specific chemical suppliers or retrieve all molecules from particular catalogs.
Web interface: https://cartblanche22.docking.org/search/catitems
API endpoint (form field is supplier_codes):
curl -X GET "https://cartblanche22.docking.org/catitems.txt" \
-F supplier_codes="SUPPLIER-CODE-123" \
-F output_fields="zinc_id,smiles,supplier_code,catalogs"Use cases:
Generate random compound sets for screening or benchmarking purposes.
Web interface: https://cartblanche22.docking.org/search/random
API endpoint:
curl "https://cartblanche22.docking.org/substance/random.txt" -F count=100Parameters (each passed as a -F form field):
count: Number of random compounds to retrieve (default: 100)subset: Filter by subset (e.g., 'lead-like', 'drug-like', 'fragment')output_fields: Customize returned data fieldsExample - Random lead-like molecules:
curl "https://cartblanche22.docking.org/substance/random.txt" \
-F count=1000 -F subset="lead-like" -F output_fields="zinc_id,smiles,tranche" # Example: random drug-like compounds; returns a task handle for the web UI
python scripts/query_zinc.py random --count 10000 --subset drug-like \
--fields zinc_id,smiles,tranchefrom the bulk repository) into a DataFrame and filter on tranche properties:
import pandas as pd
df = pd.read_csv('docking_library.tsv', sep='\t')
# Tranche format: H##P###M###-phase
# H = H-bond donors, P = LogP*10, M = MW hit_smiles = "CC(C)Cc1ccc(cc1)C(C)C(=O)O" # Example: Ibuprofen python scripts/query_zinc.py smiles "CC(C)Cc1ccc(cc1)C(C)C(=O)O" \
--dist 5 --fields zinc_id,smiles,catalogs import pandas as pd
analogs = pd.read_csv('analogs.tsv', sep='\t')
print(f"Found {len(analogs)} analogs")
print(analogs[['zinc_id', 'smiles', 'catalogs']].head(10)) zinc_ids = [
"ZINC000000000001",
"ZINC000000000002",
"ZINC000000000003"
]
zinc_ids_str = ",".join(zinc_ids)zinc_ids plural): curl -X GET "https://cartblanche22.docking.org/substances.txt" \
-F zinc_ids="ZINC000000000001,ZINC000000000002" \
-F output_fields="zinc_id,smiles,supplier_code,catalogs" python scripts/query_zinc.py random --count 5000 --subset lead-like \
--fields zinc_id,smiles,trancheCustomize API responses with the output_fields parameter:
Available fields:
zinc_id: ZINC identifiersmiles: SMILES string representationsub_id: Internal substance IDsupplier_code: Vendor catalog numbercatalogs: List of suppliers offering the compoundtranche: Encoded molecular properties (H-count, LogP, MW, reactivity phase)Example:
curl -X GET "https://cartblanche22.docking.org/substances.txt" \
-F zinc_ids="ZINC000000000001" \
-F output_fields="zinc_id,smiles,catalogs,tranche"ZINC organizes compounds into "tranches" based on molecular properties:
Format: H##P###M###-phase
Example tranche: H05P035M400-0
Use tranche data to filter compounds by drug-likeness criteria.
For molecular docking, 3D structures are available via file repositories:
File repository: https://files.docking.org/zinc22/
Structures are organized by tranches and available in multiple formats:
Refer to ZINC documentation at https://wiki.docking.org for downloading protocols and batch access methods.
Use the bundled scripts/query_zinc.py (stdlib only) rather than hand-rolling URLs — it sends the correct form-encoded POST and returns the JSON task handle:
import json, subprocess
def submit(*args):
"""Run query_zinc.py and return the parsed JSON (task handle or rows)."""
out = subprocess.run(
["python", "scripts/query_zinc.py", *args],
capture_output=True, text=True, check=True,
).stdout
return json.loads(out)
task = submit("id", "ZINC000019632618", "--fields", "zinc_id,smiles,catalogs")
# -> {"task": "<uuid>"}; open the UI task view to export rowsOnce you have result rows (a tranche column, exported from the UI or read from the file repository), decode each code. The LogP segment can be negative (P-005), so the regex allows a leading sign:
import re
def parse_tranche(tranche_str):
"""Parse a ZINC tranche code, e.g. 'H05P035M400-0'."""
match = re.match(r"H(\d+)P(-?\d+)M(\d+)-(\d+)", tranche_str)
if not match:
return None
return {
"h_donors": int(match.group(1)),
"logp": int(match.group(2)) / 10.0,
"mw": int(match.group(3)),
"phase": int(match.group(4)),
}
# df["tranche_props"] = df["tranche"].apply(parse_tranche)Comprehensive documentation including:
Consult this document for detailed technical information and advanced usage patterns.
ZINC explicitly states: "We do not guarantee the quality of any molecule for any purpose and take no responsibility for errors arising from the use of this database."
When using ZINC in publications, cite the appropriate version:
ZINC22: Tingle, B. I.; Tang, K. G.; Castanon, M.; Gutierrez, J. J.; Khurelbaatar, M.; Dandarchuluun, C.; Moroz, Y. S.; Irwin, J. J. "ZINC-22─A Free Multi-Billion-Scale Database of Tangible Compounds for Ligand Discovery." Journal of Chemical Information and Modeling 2023, 63(4), 1166–1176. DOI: 10.1021/acs.jcim.2c01253.
ZINC20: Irwin, J. J.; Tang, K. G.; Young, J.; et al. "ZINC20—A Free Ultralarge-Scale Chemical Database for Ligand Discovery." Journal of Chemical Information and Modeling 2020, 60(12), 6065–6073. DOI: 10.1021/acs.jcim.0c00675.
ZINC15: Sterling, T.; Irwin, J. J. "ZINC 15 – Ligand Discovery for Everyone." Journal of Chemical Information and Modeling 2015, 55, 2324–2337. DOI: 10.1021/acs.jcim.5b00559.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.