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 --wait # ZINC-ID lookup, rows as JSON
python scripts/query_zinc.py random --count 100 --subset lead-like # returns a task id
python scripts/query_zinc.py result <task-id> # fetch that task's rows laterEvery CartBlanche search is asynchronous. Each call returns a JSON task handle ({"task": "<uuid>"}). Poll GET https://cartblanche22.docking.org/search/result/<task>: it returns {"status": "PENDING", "progress": ...} while the job runs and {"status": "SUCCESS", "result": {...}} when done, with rows grouped by source (zinc22, zinc20) and unmatched queries under missing / zinc22_missing (--wait does the polling). ID lookups finish in seconds; random samples can stay PENDING for minutes.
Known issue (verified 2026-09-23): smiles.txt jobs finish immediately with "zinc22_missing": [""] — the server does not receive the query, whether the SMILES is sent inline, as a form upload, or as a file. Until that is fixed, run similarity searches in the CartBlanche22 web UI or in SmallWorld (https://sw.docking.org, which indexes ZINC20/ZINC22 builds) or Arthor (https://arthor.docking.org), and say so rather than reporting "no analogs found".
This skill should be used when:
| Scenario | Use Instead |
|---|---|
| Compound properties, synonyms, and bioassays for a known molecule | alterlab-pubchem |
| Measured potency (IC50/Ki) for a target | alterlab-chembl |
| Docking ligands into a protein pocket | alterlab-diffdock |
| Computing descriptors, filters, or fingerprints locally | alterlab-rdkit |
| Medicinal-chemistry filters (PAINS, rules of thumb) on a library | alterlab-medchem |
ZINC has evolved through multiple versions:
This skill primarily focuses on ZINC22, the most current and comprehensive version.
Primary access point: https://cartblanche22.docking.org/ (zinc22.docking.org redirects here) Legacy ZINC20/ZINC15 pages (zinc.docking.org, zinc20.docking.org, zinc15.docking.org) now answer scripted requests with a captcha redirect — use them interactively only.
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,tranchepython scripts/query_zinc.py result <task>, exportfrom the UI task view, or pull tranche files from 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: Ibuprofensmiles.txtAPI issue above persists, do this in the CartBlanche22 UI or SmallWorld (https://sw.docking.org) and export the hits; once fixed, the script form is:
python scripts/query_zinc.py smiles "CC(C)Cc1ccc(cc1)C(C)C(=O)O" \
--dist 5 --fields zinc_id,smiles,catalogs --wait 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)
state = submit("id", "ZINC000019632618", "--fields", "zinc_id,smiles,catalogs", "--wait")
rows = state["result"].get("zinc22") or state["result"].get("zinc20") or []Once 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.