Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Find cross-references between NCBI databases using Biopython Bio.Entrez. Use when navigating from genes to proteins, sequences to publications, finding related records, or discovering database relationships.
.claude/skills/bio-entrez-link/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-07 | ✗→✓ | ▲ Improved | 207% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 89% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 138% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 31% | 0% |
<!--
#
#
-->
Navigate between NCBI databases using Biopython's Entrez module (ELink utility).
pythonfrom Bio import Entrez Entrez.email = 'your.email@example.com' # Required by NCBI Entrez.api_key = 'your_api_key' # Optional, raises rate limit
Find related records in the same or different databases.
python# Find proteins linked to a gene handle = Entrez.elink(dbfrom='gene', db='protein', id='672') record = Entrez.read(handle) handle.close() # Extract linked IDs linkset = record[0] if linkset['LinkSetDb']: links = linkset['LinkSetDb'][0]['Link'] protein_ids = [link['Id'] for link in links] print(f"Found {len(protein_ids)} linked proteins")
Key Parameters: | Parameter | Description | Example | |-----------|-------------|---------| | dbfrom | Source database | 'gene' | | db | Target database | 'protein' | | id | Source record ID(s) | '672' or '672,675' | | linkname | Specific link type | 'gene_protein_refseq' | | cmd | Link command | 'neighbor', 'neighbor_score' |
pythonrecord[0] # First linkset record[0]['DbFrom'] # Source database record[0]['IdList'] # Input IDs record[0]['LinkSetDb'] # List of link results record[0]['LinkSetDb'][0]['DbTo'] # Target database record[0]['LinkSetDb'][0]['LinkName'] # Link name record[0]['LinkSetDb'][0]['Link'] # List of linked records record[0]['LinkSetDb'][0]['Link'][0]['Id'] # Linked ID
| From | To | Link Name | Description | |------|-----|-----------|-------------| | gene | protein | gene_protein | All proteins | | gene | protein | gene_protein_refseq | RefSeq proteins only | | gene | nucleotide | gene_nuccore | Nucleotide sequences | | gene | nucleotide | gene_nuccore_refseqrna | RefSeq mRNA | | gene | pubmed | gene_pubmed | Related publications | | gene | homologene | gene_homologene | Homologs | | gene | snp | gene_snp | SNPs in gene | | gene | clinvar | gene_clinvar | Clinical variants |
| From | To | Link Name | Description | |------|-----|-----------|-------------| | nucleotide | protein | nuccore_protein | Encoded proteins | | nucleotide | gene | nuccore_gene | Gene records | | nucleotide | pubmed | nuccore_pubmed | Publications | | nucleotide | taxonomy | nuccore_taxonomy | Organism taxonomy | | nucleotide | biosample | nuccore_biosample | Sample info | | nucleotide | sra | nuccore_sra | Related SRA data |
| From | To | Link Name | Description | |------|-----|-----------|-------------| | protein | nucleotide | protein_nuccore | Coding sequences | | protein | gene | protein_gene | Gene records | | protein | pubmed | protein_pubmed | Publications | | protein | structure | protein_structure | 3D structures | | protein | cdd | protein_cdd | Conserved domains |
| From | To | Link Name | Description | |------|-----|-----------|-------------| | pubmed | pubmed | pubmed_pubmed | Related articles | | pubmed | gene | pubmed_gene | Mentioned genes | | pubmed | protein | pubmed_protein | Mentioned proteins | | pubmed | nucleotide | pubmed_nuccore | Mentioned sequences |
pythonfrom Bio import Entrez Entrez.email = 'your.email@example.com' def get_proteins_for_gene(gene_id): handle = Entrez.elink(dbfrom='gene', db='protein', id=gene_id, linkname='gene_protein_refseq') record = Entrez.read(handle) handle.close() if not record[0]['LinkSetDb']: return [] return [link['Id'] for link in record[0]['LinkSetDb'][0]['Link']] protein_ids = get_proteins_for_gene('672') # BRCA1 print(f"RefSeq proteins: {protein_ids[:5]}")
pythondef get_gene_for_nucleotide(nuc_id): handle = Entrez.elink(dbfrom='nucleotide', db='gene', id=nuc_id) record = Entrez.read(handle) handle.close() if not record[0]['LinkSetDb']: return None return record[0]['LinkSetDb'][0]['Link'][0]['Id'] gene_id = get_gene_for_nucleotide('NM_007294') print(f"Gene ID: {gene_id}")
pythondef get_related_articles(pmid, max_results=10): handle = Entrez.elink(dbfrom='pubmed', db='pubmed', id=pmid, linkname='pubmed_pubmed') record = Entrez.read(handle) handle.close() if not record[0]['LinkSetDb']: return [] links = record[0]['LinkSetDb'][0]['Link'] return [link['Id'] for link in links[:max_results]] related = get_related_articles('35412348') print(f"Related articles: {related}")
pythondef discover_links(db, record_id): handle = Entrez.elink(dbfrom=db, id=record_id, cmd='acheck') record = Entrez.read(handle) handle.close() links = {} for linkset in record[0].get('LinkSetDb', []): links[linkset['LinkName']] = linkset['DbTo'] return links available = discover_links('gene', '672') for name, target in available.items(): print(f"{name} -> {target}")
pythondef gene_to_structures(gene_id): # Gene to protein handle = Entrez.elink(dbfrom='gene', db='protein', id=gene_id, linkname='gene_protein_refseq') record = Entrez.read(handle) handle.close() if not record[0]['LinkSetDb']: return [] protein_ids = [link['Id'] for link in record[0]['LinkSetDb'][0]['Link'][:5]] # Protein to structure handle = Entrez.elink(dbfrom='protein', db='structure', id=','.join(protein_ids)) record = Entrez.read(handle) handle.close() structure_ids = [] for linkset in record: if linkset['LinkSetDb']: structure_ids.extend([link['Id'] for link in linkset['LinkSetDb'][0]['Link']]) return structure_ids structures = gene_to_structures('672') print(f"Structure IDs: {structures[:5]}")
pythondef batch_link(dbfrom, db, ids): if isinstance(ids, list): ids = ','.join(ids) handle = Entrez.elink(dbfrom=dbfrom, db=db, id=ids) record = Entrez.read(handle) handle.close() # Returns one linkset per input ID results = {} for linkset in record: source_id = linkset['IdList'][0] linked_ids = [] if linkset['LinkSetDb']: linked_ids = [link['Id'] for link in linkset['LinkSetDb'][0]['Link']] results[source_id] = linked_ids return results results = batch_link('gene', 'protein', ['672', '675', '7157']) for gene, proteins in results.items(): print(f"Gene {gene}: {len(proteins)} proteins")
pythondef get_sequence_publications(accession): # First get the GI/UID handle = Entrez.esearch(db='nucleotide', term=f'{accession}[accn]') search = Entrez.read(handle) handle.close() if not search['IdList']: return [] uid = search['IdList'][0] # Link to PubMed handle = Entrez.elink(dbfrom='nucleotide', db='pubmed', id=uid) record = Entrez.read(handle) handle.close() if not record[0]['LinkSetDb']: return [] return [link['Id'] for link in record[0]['LinkSetDb'][0]['Link']] pmids = get_sequence_publications('NM_007294') print(f"PubMed IDs: {pmids[:5]}")
| Command | Description | |---------|-------------| | neighbor | Default - get linked records | | neighbor_score | Include relevance scores | | neighbor_history | Store results in history | | acheck | List all available links | | ncheck | Check if any links exist | | lcheck | Check specific link exists | | llinks | Get URLs to Entrez links | | prlinks | Get provider links (external) |
| Error | Cause | Solution | |-------|-------|----------| | Empty LinkSetDb | No links exist | Check if record has linked data | | HTTPError 400 | Invalid ID or database | Verify ID exists in source database | | KeyError | Missing expected field | Check if LinkSetDb is empty first | | Single linkset expected, got list | Multiple input IDs | Iterate through record list |
Need to find related records?
├── Know what link you want?
│ └── Use elink with specific linkname
├── Discover what links exist?
│ └── Use elink with cmd='acheck'
├── Navigate to target database?
│ └── Use elink(dbfrom=X, db=Y, id=Z)
├── Find related records in same database?
│ └── Use elink(dbfrom=X, db=X) with neighbor
├── Chain multiple databases?
│ └── Call elink multiple times
└── Need the actual records?
└── Use elink first, then efetch with IDs<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-07 | fail→pass | 7,488 | 8,620 | +15% | 1 | 1 | 0% | 1,536 | 4,718 | +207% | 0 | 0 | — |
case-08 | fail→pass | 12,856 | 5,877 | -54% | 1 | 1 | 0% | 2,549 | 3,966 | +56% | 0 | 0 | — |
case-09 | fail→fail | 9,541 | 6,374 | -33% | 1 | 1 | 0% | 2,048 | 4,049 | +98% | 0 | 0 | — |
case-10 | fail→pass | 10,637 | 5,529 | -48% | 1 | 1 | 0% | 2,116 | 4,002 | +89% | 0 | 0 | — |
case-11 | fail→pass | 9,430 | 6,905 | -27% | 1 | 1 | 0% | 1,819 | 4,331 | +138% | 0 | 0 | — |
case-12 | fail→pass | 15,453 | 5,795 | -62% | 1 | 1 | 0% | 3,060 | 4,023 | +31% | 0 | 0 | — |
case-01 | pass→pass | 11,383 | 10,164 | -11% | 1 | 1 | 0% | 2,446 | 4,762 | +95% | 0 | 0 | — |
case-02 | fail→pass | 11,751 | 7,643 | -35% | 1 | 1 | 0% | 2,435 | 4,434 | +82% | 0 | 0 | — |
case-03 | fail→pass | 9,404 | 8,771 | -7% | 1 | 1 | 0% | 1,997 | 4,816 | +141% | 0 | 0 | — |
case-04 | fail→pass | 7,891 | 6,024 | -24% | 1 | 1 | 0% | 1,642 | 4,117 | +151% | 0 | 0 | — |
case-05 | fail→pass | 8,034 | 6,195 | -23% | 1 | 1 | 0% | 1,687 | 4,166 | +147% | 0 | 0 | — |
case-06 | pass→pass | 10,193 | 6,295 | -38% | 1 | 1 | 0% | 2,004 | 4,064 | +103% | 0 | 0 | — |
case-13 | pass→pass | 10,506 | 5,417 | -48% | 1 | 1 | 0% | 2,150 | 3,957 | +84% | 0 | 0 | — |
case-14 | pass→pass | 11,412 | 6,990 | -39% | 1 | 1 | 0% | 2,468 | 4,230 | +71% | 0 | 0 | — |
case-15 | fail→pass | 13,330 | 11,377 | -15% | 1 | 1 | 0% | 2,388 | 5,010 | +110% | 0 | 0 | — |
case-16 | fail→pass | 14,214 | 8,822 | -38% | 1 | 1 | 0% | 3,104 | 4,927 | +59% | 0 | 0 | — |
case-17 | fail→pass | 9,359 | 7,264 | -22% | 1 | 1 | 0% | 1,896 | 4,466 | +136% | 0 | 0 | — |
case-18 | pass→pass | 12,113 | 10,098 | -17% | 1 | 1 | 0% | 2,468 | 4,963 | +101% | 0 | 0 | — |
case-19 | fail→pass | 9,921 | 5,998 | -40% | 1 | 1 | 0% | 2,119 | 4,127 | +95% | 0 | 0 | — |
case-20 | pass→pass | 6,587 | 6,018 | -9% | 1 | 1 | 0% | 1,374 | 4,034 | +194% | 0 | 0 | — |
case-21 | pass→pass | 6,518 | 5,470 | -16% | 1 | 1 | 0% | 1,351 | 4,004 | +196% | 0 | 0 | — |
case-22 | pass→pass | 10,320 | 6,501 | -37% | 1 | 1 | 0% | 1,978 | 4,138 | +109% | 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. 22 cases were attempted. The headline lift of +59 percentage points is the difference between those two pass rates over the 22 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.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/24/2026 | +27% |
Other measured skills in the registry, with their headline benchmark lift.