Access the European Nucleotide Archive (ENA) via REST APIs and FTP/Aspera to search and retrieve sequences, raw reads (FASTQ), assemblies, and metadata when you have accession IDs or need metadata-driven discovery for genomics pipelines.
68
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Use this skill when you need to:
ERR..., SRR..., PRJ...).For detailed endpoint and parameter documentation, see
references/api_reference.md.
>=3.9requests >=2.31.0Optional (recommended for XML parsing when using the Browser API):
lxml >=4.9.0The following script is a complete, runnable example that:
#!/usr/bin/env python3
import sys
import time
import requests
PORTAL_SEARCH = "https://www.ebi.ac.uk/ena/portal/api/search"
BROWSER_XML = "https://www.ebi.ac.uk/ena/browser/api/xml"
TAXONOMY = "https://www.ebi.ac.uk/ena/taxonomy/rest"
SESSION = requests.Session()
SESSION.headers.update({"User-Agent": "ena-database-skill/1.0"})
def get_with_backoff(url, params=None, max_retries=6, timeout=30):
delay = 1.0
for attempt in range(max_retries):
r = SESSION.get(url, params=params, timeout=timeout)
if r.status_code != 429:
r.raise_for_status()
return r
time.sleep(delay)
delay *= 2
r.raise_for_status()
def search_runs_by_study(study_accession, limit=5):
params = {
"result": "read_run",
"query": f"study_accession={study_accession}",
"format": "json",
"limit": limit,
# Ask for a few useful fields; adjust as needed for your pipeline.
"fields": "run_accession,study_accession,sample_accession,experiment_accession,tax_id,scientific_name,fastq_ftp"
}
r = get_with_backoff(PORTAL_SEARCH, params=params)
return r.json()
def fetch_run_xml(run_accession):
url = f"{BROWSER_XML}/{run_accession}"
r = get_with_backoff(url)
return r.text # XML string
def fetch_taxonomy_lineage(tax_id):
url = f"{TAXONOMY}/tax-id/{tax_id}"
r = get_with_backoff(url)
return r.json()
def main():
if len(sys.argv) < 2:
print("Usage: python ena_example.py <STUDY_ACCESSION> (e.g., PRJEB1234)", file=sys.stderr)
sys.exit(2)
study = sys.argv[1]
runs = search_runs_by_study(study_accession=study, limit=5)
if not runs:
print(f"No runs found for study {study}")
return
print(f"Found {len(runs)} runs for study {study}")
first = runs[0]
run_acc = first.get("run_accession")
tax_id = first.get("tax_id")
print("\nFirst run summary (Portal API JSON):")
for k in ["run_accession", "sample_accession", "experiment_accession", "scientific_name", "tax_id", "fastq_ftp"]:
print(f" {k}: {first.get(k)}")
if run_acc:
xml = fetch_run_xml(run_acc)
print("\nBrowser API XML (first 600 chars):")
print(xml[:600])
if tax_id:
tax = fetch_taxonomy_lineage(tax_id)
print("\nTaxonomy lineage (ENA Taxonomy REST API):")
# Response is typically a list with one record
rec = tax[0] if isinstance(tax, list) and tax else tax
print(f" scientificName: {rec.get('scientificName')}")
print(f" rank: {rec.get('rank')}")
print(f" lineage: {rec.get('lineage')}")
if __name__ == "__main__":
main()Run:
python ena_example.py PRJEB1234ENA organizes records into common object types used in pipelines:
/ena/portal/api/search): use for searching and exporting metadata at scale.
json, tsv, csv.references/api_reference.md)./ena/browser/api/xml/{accession}): use for direct retrieval by accession.
/ena/taxonomy/rest/...): use for lineage/rank lookups.https://www.ebi.ac.uk/ena/xref/rest/ for related records in external databases.https://www.ebi.ac.uk/ena/cram/ for reference sequence retrieval by checksum.result: record type (e.g., sample, read_run, assembly)query: filter expression (e.g., study_accession=PRJEB1234, tax_tree(Escherichia coli))fields: comma-separated fields to return (improves performance vs returning everything)format: json/tsv/csvlimit (and pagination where applicable)fastq_ftp) from Portal results, then download via FTP/Aspera for scale.63c61d3
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.