Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Query Reactome pathways via REST: pathway queries, entity lookup, keyword search, gene list enrichment, hierarchy, cross-refs. Content + Analysis services. Python wrapper: reactome2py. For KEGG use kegg-database; for PPIs use string-database-ppi.
.claude/skills/jaechang-hits-reactome-database/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 84% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 314% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 361% | 0% |
| case-19 | ✗→✓ | ▲ Improved | 277% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 327% | 0% |
Reactome is an open-source, curated database of biological pathways and reactions for 16+ species. It provides two REST APIs: the Content Service for querying pathway data, entities, and hierarchy, and the Analysis Service for gene/protein list enrichment and expression data overlay. All endpoints return JSON (default) or other formats and require no authentication.
kegg-database insteadstring-database-ppi insteadreactome2py (pip install reactome2py)bashpip install requests
API constraints:
time.sleep(0.5) between batch requests to be respectfulhttps://reactome.org/ContentServicehttps://reactome.org/AnalysisServicepythonimport requests import time CONTENT = "https://reactome.org/ContentService" ANALYSIS = "https://reactome.org/AnalysisService" def reactome_get(base, path, params=None): """Generic Reactome REST API caller. Returns JSON or raises.""" resp = requests.get(f"{base}{path}", params=params) resp.raise_for_status() try: return resp.json() except ValueError: return resp.text # Check database version version = reactome_get(CONTENT, "/data/database/version") print(f"Reactome version: {version}") # Query a pathway pathway = reactome_get(CONTENT, "/data/query/R-HSA-69620") print(f"Pathway: {pathway['displayName']}") print(f"Species: {pathway['speciesName']}") time.sleep(0.5) # Search for pathways results = reactome_get(CONTENT, "/search/query", params={"query": "apoptosis", "types": "Pathway"}) print(f"Found {results['found']} results for 'apoptosis'")
Retrieve detailed information about pathways, reactions, and biological entities by stable ID. Uses reactome_get helper from Quick Start.
python# Query pathway by stable ID pathway = reactome_get(CONTENT, "/data/query/R-HSA-69620") print(f"Name: {pathway['displayName']}") print(f"Stable ID: {pathway['stId']}, Species: {pathway['speciesName']}") print(f"Schema class: {pathway['schemaClass']}") # Pathway, TopLevelPathway, etc. time.sleep(0.5) # Get participating physical entities in a pathway entities = reactome_get(CONTENT, f"/data/participants/{pathway['stId']}") print(f"\nParticipating entities: {len(entities)}") for e in entities[:3]: print(f" {e['displayName']} ({e['schemaClass']})") time.sleep(0.5) # Get participating molecules with reference entities (UniProt, ChEBI, etc.) refs = reactome_get(CONTENT, f"/data/participants/{pathway['stId']}/referenceEntities") print(f"\nReference entities: {len(refs)}") for r in refs[:3]: print(f" {r['displayName']} — {r.get('databaseName', 'N/A')}:{r.get('identifier', 'N/A')}")
Search across Reactome by keyword with faceted filtering.
python# Keyword search filtered to Pathways results = reactome_get(CONTENT, "/search/query", params={ "query": "cell cycle", "types": "Pathway", "species": "Homo sapiens", "cluster": "true" }) print(f"Total found: {results['found']}") for entry in results.get("results", [])[:1]: for e in entry.get("entries", [])[:5]: print(f" {e['stId']}: {e['name']}") time.sleep(0.5) # Search for proteins/complexes proteins = reactome_get(CONTENT, "/search/query", params={ "query": "TP53", "types": "Protein", "species": "Homo sapiens" }) print(f"\nTP53 protein entries: {proteins['found']}") time.sleep(0.5) # Suggest (autocomplete) suggestions = reactome_get(CONTENT, "/search/suggest", params={"query": "apopt"}) print(f"Suggestions: {suggestions}")
Searchable types: Pathway, Reaction, Protein, Complex, SmallMolecule, Gene, DNA, RNA, Drug, ReferenceEntity
Submit a gene/protein list for over-representation analysis against Reactome pathways.
pythonimport requests import time ANALYSIS = "https://reactome.org/AnalysisService" # Gene list (newline-separated identifiers — UniProt, HGNC symbols, Ensembl, etc.) gene_list = "TP53\nBRCA1\nBRCA2\nATM\nCHEK2\nCDK2\nRB1\nMDM2\nCDKN1A\nBAX" # Submit for enrichment (POST with text body) resp = requests.post( f"{ANALYSIS}/identifiers/", headers={"Content-Type": "text/plain"}, data=gene_list, params={"pageSize": 10, "page": 1, "sortBy": "ENTITIES_FDR", "order": "ASC"} ) resp.raise_for_status() result = resp.json() print(f"Analysis token: {result['summary']['token']}") print(f"Pathways found: {result['pathwaysFound']}") print(f"Identifiers found: {result['identifiersNotFound']}") print(f"\nTop enriched pathways:") for p in result["pathways"][:5]: print(f" {p['stId']}: {p['name']}") print(f" FDR: {p['entities']['fdr']:.2e}, " f"Found: {p['entities']['found']}/{p['entities']['total']}") time.sleep(0.5)
Analysis accepts: newline-separated identifiers, or tab-separated with expression values (for expression overlay). Supported IDs include UniProt, HGNC symbols, Ensembl, NCBI Gene, ChEBI, miRBase, KEGG, and more.
Retrieve previously computed analysis results by token and apply filters.
pythonimport requests import time ANALYSIS = "https://reactome.org/AnalysisService" # Re-fetch results by token (from a previous analysis) token = "MjAyNTA2MTcxMDA3MzRfMQ%3D%3D" # example — use token from Module 3 # Get results with filtering results = requests.get(f"{ANALYSIS}/token/{token}", params={ "pageSize": 20, "page": 1, "sortBy": "ENTITIES_FDR", "species": "Homo sapiens", "resource": "TOTAL" # TOTAL, UNIPROT, ENSEMBL, CHEBI, etc. }) results.raise_for_status() data = results.json() print(f"Token: {data['summary']['token']}") print(f"Pathways: {data['pathwaysFound']}") time.sleep(0.5) # Get identifiers found in a specific pathway pathway_detail = requests.get( f"{ANALYSIS}/token/{token}/found/all/{data['pathways'][0]['stId']}" ) pathway_detail.raise_for_status() found = pathway_detail.json() print(f"\nIdentifiers found in {data['pathways'][0]['name']}:") for entity in found.get("entities", [])[:5]: mapsTo = [m["identifier"] for m in entity.get("mapsTo", [])] print(f" {entity['id']} -> {mapsTo}")
Token persistence: analysis tokens are valid for several hours. Share tokens to let collaborators view the same results without re-running. Filter by resource (TOTAL, UNIPROT, ENSEMBL, CHEBI, etc.) and species.
Navigate the Reactome pathway hierarchy from top-level pathways down to reactions.
python# Top-level pathways for human (9606 = NCBI taxonomy ID) top = reactome_get(CONTENT, "/data/pathways/top/9606") print(f"Top-level human pathways: {len(top)}") for p in top[:5]: print(f" {p['stId']}: {p['displayName']}") time.sleep(0.5) # Get contained events (sub-pathways and reactions) events = reactome_get(CONTENT, "/data/pathway/R-HSA-69620/containedEvents") print(f"\nContained events in Cell Cycle: {len(events)}") for e in events[:5]: print(f" {e['stId']}: {e['displayName']} ({e['schemaClass']})") time.sleep(0.5) # Get the full ancestor chain for a pathway ancestors = reactome_get(CONTENT, "/data/event/R-HSA-69620/ancestors") print(f"\nAncestors of Cell Cycle:") for chain in ancestors: names = [a["displayName"] for a in chain] print(f" {' > '.join(names)}")
Species identifiers: use NCBI taxonomy IDs (9606=human, 10090=mouse, 10116=rat) or species names.
Map identifiers across databases and query species-specific data.
python# List all species in Reactome species = reactome_get(CONTENT, "/data/species/all") print(f"Species in Reactome: {len(species)}") for s in species[:5]: print(f" {s['displayName']} (taxId: {s['taxId']})") time.sleep(0.5) # Map a Reactome entity to external references xrefs = reactome_get(CONTENT, "/data/query/R-HSA-69620/xrefs") if isinstance(xrefs, list): print(f"\nCross-references for R-HSA-69620: {len(xrefs)}") for x in xrefs[:5]: print(f" {x}") time.sleep(0.5) # Get orthologous pathway in another species (human → mouse) mouse_ortho = reactome_get(CONTENT, "/data/orthology/R-HSA-69620/species/10090") if mouse_ortho: for o in mouse_ortho[:3]: print(f"Mouse ortholog: {o['stId']}: {o['displayName']}")
Reactome organizes knowledge in a hierarchical structure:
| Level | Schema Class | Example | |-------|-------------|---------| | Top-Level Pathway | TopLevelPathway | Cell Cycle, Immune System, Metabolism | | Pathway | Pathway | Cell Cycle Checkpoints, Mitotic G1-G1/S phases | | Reaction | Reaction | TP53 binds RB1 | | Physical Entity | EntityWithAccessionedSequence | TP53 cytosol] |
Pathways contain sub-pathways and reactions. Reactions connect input/output physical entities. Each entity maps to reference databases (UniProt, ChEBI, Ensembl).
The Analysis Service accepts a wide range of identifiers:
| Database | Example ID | Type | |----------|-----------|------| | UniProt | P04637 | Protein | | HGNC Symbol | TP53 | Gene symbol | | Ensembl Gene | ENSG00000141510 | Gene | | NCBI Gene | 7157 | Gene | | ChEBI | CHEBI:15377 | Small molecule | | miRBase | hsa-miR-21-5p | microRNA | | KEGG Gene | hsa:7157 | Gene (KEGG format) | | Ensembl Protein | ENSP00000269305 | Protein |
When you submit an analysis, Reactome returns a token — a URL-safe string that identifies your result set. Tokens enable:
GET /token/{token})https://reactome.org/PathwayBrowser/#/DTAB=AN&ANALYSIS={token}Goal: Submit a gene list, get enriched pathways, and explore top hits.
pythonimport requests import time CONTENT = "https://reactome.org/ContentService" ANALYSIS = "https://reactome.org/AnalysisService" # Step 1: Submit gene list genes = "TP53\nBRCA1\nBRCA2\nATM\nCHEK2\nCDK2\nRB1\nMDM2\nCDKN1A\nBAX" resp = requests.post( f"{ANALYSIS}/identifiers/", headers={"Content-Type": "text/plain"}, data=genes, params={"pageSize": 5, "sortBy": "ENTITIES_FDR", "order": "ASC"} ) resp.raise_for_status() result = resp.json() token = result["summary"]["token"] print(f"Token: {token} | Pathways found: {result['pathwaysFound']}") # Step 2: Show top pathways with FDR for p in result["pathways"][:5]: fdr = p["entities"]["fdr"] ratio = f"{p['entities']['found']}/{p['entities']['total']}" print(f" {p['stId']}: {p['name']} (FDR={fdr:.2e}, {ratio})") time.sleep(0.5) # Step 3: Get details on top pathway top_id = result["pathways"][0]["stId"] detail = requests.get(f"{CONTENT}/data/query/{top_id}").json() print(f"\nTop pathway: {detail['displayName']}") print(f"Compartments: {[c['displayName'] for c in detail.get('compartment', [])]}")
Goal: Navigate from a top-level pathway down to specific reactions and entities.
python# Uses reactome_get helper and CONTENT base URL from Quick Start # Step 1: Find pathway by search results = reactome_get(CONTENT, "/search/query", params={"query": "DNA repair", "types": "Pathway", "species": "Homo sapiens"}) top_hit = results["results"][0]["entries"][0] pid = top_hit["stId"] print(f"Found: {pid} — {top_hit['name']}") time.sleep(0.5) # Step 2: Get sub-events events = reactome_get(CONTENT, f"/data/pathway/{pid}/containedEvents") reactions = [e for e in events if e["schemaClass"] == "Reaction"] subpaths = [e for e in events if "Pathway" in e["schemaClass"]] print(f"Sub-pathways: {len(subpaths)}, Reactions: {len(reactions)}") time.sleep(0.5) # Step 3: Get participating molecules for a reaction if reactions: rxn = reactions[0] refs = reactome_get(CONTENT, f"/data/participants/{rxn['stId']}/referenceEntities") print(f"\n{rxn['displayName']} participants:") for r in refs[:5]: print(f" {r.get('databaseName', '?')}:{r.get('identifier', '?')} — {r['displayName']}")
Goal: Submit expression values alongside identifiers for pathway-level expression overlay.
pythonimport requests ANALYSIS = "https://reactome.org/AnalysisService" # Tab-separated: identifier \t expression_value1 \t expression_value2 ... # First line can be a header (auto-detected) expression_data = """#id\tcontrol\ttreated TP53\t1.2\t3.5 BRCA1\t2.1\t1.8 CDK2\t0.9\t4.2 RB1\t1.5\t0.6 MDM2\t1.0\t2.8 CDKN1A\t0.8\t5.1 BAX\t1.1\t3.9""" resp = requests.post( f"{ANALYSIS}/identifiers/", headers={"Content-Type": "text/plain"}, data=expression_data, params={"pageSize": 10, "sortBy": "ENTITIES_FDR"} ) resp.raise_for_status() result = resp.json() print(f"Expression columns: {result['summary'].get('sampleName', 'N/A')}") print(f"Token: {result['summary']['token']}") for p in result["pathways"][:3]: exp = p["entities"].get("exp", []) print(f" {p['name']}: FDR={p['entities']['fdr']:.2e}, expr={exp}")
| Parameter | Function/Endpoint | Default | Options | Effect | |-----------|-------------------|---------|---------|--------| | query | /search/query | — | Any string | Keyword search term | | types | /search/query | All | Pathway, Reaction, Protein, etc. | Filter search by schema class | | species | /search/query, analysis | All | Species name or taxon ID | Restrict to organism | | pageSize | Analysis, search | 20 | 1-250 | Results per page | | sortBy | Analysis | ENTITIES_PVALUE | ENTITIES_FDR, ENTITIES_PVALUE, ENTITIES_FOUND, NAME | Sort enrichment results | | resource | Analysis filtering | TOTAL | TOTAL, UNIPROT, ENSEMBL, CHEBI, etc. | Filter by identifier source | | cluster | /search/query | true | true, false | Group search results by type |
time.sleep(0.5) between sequential requests: Reactome has no documented hard rate limit, but rapid-fire requests may be throttled. Be courteous to the shared resource.sortBy=ENTITIES_FDR for enrichment results: FDR-corrected p-values are more reliable than raw p-values for pathway-level significance.identifiersNotFound in analysis results: a high unmapped count may indicate wrong identifier type or outdated IDs.pythonimport requests CONTENT = "https://reactome.org/ContentService" pathway_id = "R-HSA-69620" # Cell Cycle refs = requests.get(f"{CONTENT}/data/participants/{pathway_id}/referenceEntities").json() genes = set() for r in refs: if r.get("databaseName") == "UniProt": genes.add(r.get("displayName", r.get("identifier"))) print(f"UniProt proteins in {pathway_id}: {len(genes)}") for g in sorted(genes)[:10]: print(f" {g}")
python# Generate a direct link to the Reactome pathway diagram pathway_id = "R-HSA-69620" diagram_url = f"https://reactome.org/PathwayBrowser/#/{pathway_id}" print(f"View diagram: {diagram_url}") # With analysis overlay token = "YOUR_TOKEN" overlay_url = f"https://reactome.org/PathwayBrowser/#/{pathway_id}&DTAB=AN&ANALYSIS={token}" print(f"View with analysis: {overlay_url}")
pythonimport requests import time CONTENT = "https://reactome.org/ContentService" pathway_ids = ["R-HSA-69620", "R-HSA-109581", "R-HSA-1640170"] summaries = [] for pid in pathway_ids: resp = requests.get(f"{CONTENT}/data/query/{pid}") resp.raise_for_status() data = resp.json() summaries.append({ "stId": data["stId"], "name": data["displayName"], "species": data["speciesName"], "hasDiagram": data.get("hasDiagram", False) }) time.sleep(0.5) for s in summaries: print(f"{s['stId']}: {s['name']} (diagram: {s['hasDiagram']})")
| Problem | Cause | Solution | |---------|-------|----------| | 404 Not Found | Invalid stable ID or wrong species prefix | Verify ID format: R-HSA-{number} for human; use /search/query to find valid IDs | | 400 Bad Request | Malformed POST body or wrong Content-Type | Use Content-Type: text/plain for analysis; newline-separated identifiers | | Empty analysis results | Identifiers not recognized | Check identifiersNotFound; try different ID types (UniProt vs HGNC symbol) | | 500 Internal Server Error | Server-side issue or very large input | Retry after delay; split large gene lists (>2000 IDs) into batches | | Token expired | Analysis results no longer available | Re-submit the gene list; tokens last several hours | | Wrong species results | No species filter applied | Add species=Homo sapiens parameter to search/analysis | | Slow response | Large pathway with many entities | Use pageSize to paginate; cache results locally | | Cross-reference returns empty | Entity has no external DB mapping | Not all Reactome entities have UniProt/Ensembl mappings; check entity schema class |
This skill consolidates content from:
bioservices.Reactome| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 14,642 | 15,322 | +5% | 1 | 1 | 0% | 2,788 | 8,500 | +205% | 0 | 0 | — |
case-02 | pass→pass | 13,668 | 8,026 | -41% | 1 | 1 | 0% | 2,545 | 7,521 | +196% | 0 | 0 | — |
case-03 | pass→pass | 8,559 | 10,456 | +22% | 1 | 1 | 0% | 1,526 | 7,793 | +411% | 0 | 0 | — |
case-04 | fail→fail | 16,169 | 8,185 | -49% | 1 | 1 | 0% | 3,029 | 7,751 | +156% | 0 | 0 | — |
case-05 | fail→pass | 23,012 | 11,213 | -51% | 1 | 1 | 0% | 4,539 | 8,363 | +84% | 0 | 0 | — |
case-06 | pass→pass | 16,807 | 8,507 | -49% | 1 | 1 | 0% | 2,615 | 7,665 | +193% | 0 | 0 | — |
case-07 | pass→pass | 7,473 | 4,375 | -41% | 1 | 1 | 0% | 1,404 | 6,845 | +388% | 0 | 0 | — |
case-08 | pass→pass | 11,697 | 6,385 | -45% | 1 | 1 | 0% | 2,386 | 7,307 | +206% | 0 | 0 | — |
case-09 | pass→pass | 11,628 | 4,691 | -60% | 1 | 1 | 0% | 1,785 | 6,936 | +289% | 0 | 0 | — |
case-10 | pass→pass | 10,981 | 5,308 | -52% | 1 | 1 | 0% | 2,071 | 7,057 | +241% | 0 | 0 | — |
case-11 | pass→pass | 5,833 | 3,685 | -37% | 1 | 1 | 0% | 1,103 | 6,758 | +513% | 0 | 0 | — |
case-12 | pass→pass | 9,691 | 4,929 | -49% | 1 | 1 | 0% | 1,695 | 7,009 | +314% | 0 | 0 | — |
case-13 | pass→pass | 13,061 | 16,634 | +27% | 1 | 1 | 0% | 2,861 | 8,693 | +204% | 0 | 0 | — |
case-14 | fail→pass | 9,322 | 4,833 | -48% | 1 | 1 | 0% | 1,694 | 7,017 | +314% | 0 | 0 | — |
case-15 | fail→pass | 9,758 | 3,943 | -60% | 1 | 1 | 0% | 1,468 | 6,773 | +361% | 0 | 0 | — |
case-16 | pass→pass | 9,453 | 4,571 | -52% | 1 | 1 | 0% | 1,766 | 6,952 | +294% | 0 | 0 | — |
case-17 | pass→pass | 8,763 | 5,836 | -33% | 1 | 1 | 0% | 1,687 | 6,867 | +307% | 0 | 0 | — |
case-18 | pass→pass | 7,779 | 3,269 | -58% | 1 | 1 | 0% | 1,486 | 6,641 | +347% | 0 | 0 | — |
case-19 | fail→pass | 9,429 | 3,007 | -68% | 1 | 1 | 0% | 1,766 | 6,653 | +277% | 0 | 0 | — |
case-20 | fail→pass | 8,075 | 4,092 | -49% | 1 | 1 | 0% | 1,595 | 6,803 | +327% | 0 | 0 | — |
case-21 | fail→pass | 13,267 | 5,463 | -59% | 1 | 1 | 0% | 2,014 | 7,032 | +249% | 0 | 0 | — |
case-22 | pass→pass | 10,978 | 2,579 | -77% | 1 | 1 | 0% | 985 | 6,559 | +566% | 0 | 0 | — |
case-23 | fail→pass | 10,331 | 6,618 | -36% | 1 | 1 | 0% | 2,065 | 7,380 | +257% | 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. 23 cases were attempted. The headline lift of +30 percentage points is the difference between those two pass rates over the 23 comparable cases.
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.
Other measured skills in the registry, with their headline benchmark lift.