Install any skill in seconds. Free to start, no credit card required.
Get Started Free →AI research assistant for biomedicine, RNA-seq, and drug discovery
.claude/skills/brycewang-stanford-medgeclaw-guide/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 31% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 110% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 50% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 145% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 41% | 0% |
MedgeClaw is a conceptual framework for AI-powered biomedical research assistance, integrating natural language processing for medical literature, computational biology pipelines, and drug discovery workflows. The name reflects the integration of Medical knowledge Edge (cutting-edge biomedical AI) with the Claw agent pattern for autonomous research execution.
Biomedical research is uniquely suited for AI augmentation because it generates massive, heterogeneous data -- genomic sequences, clinical records, imaging data, molecular structures, and published literature -- that exceeds the capacity of individual researchers to synthesize. AI systems that can navigate across these data types, identify patterns, and suggest hypotheses accelerate the pace of discovery.
This guide covers the key computational methods in biomedical AI research: medical NLP for literature mining, RNA-seq analysis pipelines, drug discovery computational workflows, and the integration patterns that connect these components into coherent research workflows. The focus is on methods that are reproducible, validated, and suitable for publication in biomedical journals.
python# Biomedical NER using scispaCy import scispacy import spacy from scispacy.linking import EntityLinker # Load biomedical NER model nlp = spacy.load("en_ner_bionlp13cg_md") # Add UMLS entity linker for concept normalization nlp.add_pipe("scispacy_linker", config={ "resolve_abbreviations": True, "linker_name": "umls", }) def extract_biomedical_entities(text: str) -> dict: """ Extract and normalize biomedical entities from text. Returns genes, chemicals, diseases, and their UMLS mappings. """ doc = nlp(text) entities = { "genes": [], "chemicals": [], "diseases": [], "other": [], } category_map = { "GENE_OR_GENE_PRODUCT": "genes", "SIMPLE_CHEMICAL": "chemicals", "CANCER": "diseases", "ORGAN": "other", "CELL": "other", } for ent in doc.ents: category = category_map.get(ent.label_, "other") entity_info = { "text": ent.text, "label": ent.label_, "start": ent.start_char, "end": ent.end_char, } # Add UMLS links if available if hasattr(ent, "_") and hasattr(ent._, "kb_ents"): if ent._.kb_ents: top_link = ent._.kb_ents[0] entity_info["umls_cui"] = top_link[0] entity_info["confidence"] = round(top_link[1], 3) entities[category].append(entity_info) return entities
pythonfrom Bio import Entrez import time Entrez.email = "researcher@university.edu" def systematic_pubmed_search( query: str, max_results: int = 1000, date_range: tuple = ("2020/01/01", "2025/12/31"), ) -> list: """ Conduct a systematic PubMed search with structured result extraction. Suitable for systematic reviews and meta-analyses. """ # Step 1: Search PubMed handle = Entrez.esearch( db="pubmed", term=query, retmax=max_results, datetype="pdat", mindate=date_range[0], maxdate=date_range[1], sort="relevance", ) results = Entrez.read(handle) handle.close() pmids = results["IdList"] print(f"Found {results['Count']} results, retrieving {len(pmids)}") # Step 2: Fetch article details in batches articles = [] batch_size = 100 for i in range(0, len(pmids), batch_size): batch = pmids[i:i + batch_size] handle = Entrez.efetch( db="pubmed", id=",".join(batch), rettype="xml", retmode="xml" ) records = Entrez.read(handle) handle.close() for article in records["PubmedArticle"]: medline = article["MedlineCitation"] art = medline["Article"] articles.append({ "pmid": str(medline["PMID"]), "title": art["ArticleTitle"], "abstract": art.get("Abstract", {}).get("AbstractText", [""])[0], "journal": art["Journal"]["Title"], "year": art["Journal"]["JournalIssue"]["PubDate"].get("Year", "N/A"), "mesh_terms": [ d["DescriptorName"] for d in medline.get("MeshHeadingList", []) ] if "MeshHeadingList" in medline else [], }) time.sleep(0.4) # Respect NCBI rate limits return articles
r# Complete RNA-seq differential expression analysis with DESeq2 # This is the standard workflow for biomedical RNA-seq papers library(DESeq2) library(ggplot2) library(EnhancedVolcano) library(clusterProfiler) library(org.Hs.eg.db) # --- 1. Load count matrix and metadata --- counts <- read.csv("raw_counts.csv", row.names = 1) coldata <- read.csv("sample_info.csv", row.names = 1) # Verify sample order matches stopifnot(all(colnames(counts) == rownames(coldata))) # --- 2. Create DESeq2 object --- dds <- DESeqDataSetFromMatrix( countData = counts, colData = coldata, design = ~ condition # Simple two-group comparison ) # Pre-filtering: remove low-count genes keep <- rowSums(counts(dds)) >= 10 dds <- dds[keep, ] # --- 3. Run differential expression --- dds <- DESeq(dds) res <- results(dds, contrast = c("condition", "treatment", "control"), alpha = 0.05) # Summary summary(res) # --- 4. Results with shrinkage (recommended for visualization) --- res_shrunk <- lfcShrink(dds, coef = "condition_treatment_vs_control", type = "apeglm") # --- 5. Export significant genes --- sig_genes <- subset(res, padj < 0.05 & abs(log2FoldChange) > 1) write.csv(as.data.frame(sig_genes), "significant_genes.csv")
| Metric | Expected Range | Concern If | |--------|---------------|------------| | Total reads | 20-50M per sample | < 10M | | Mapping rate | > 80% | < 70% | | rRNA contamination | < 5% | > 10% | | GC content | ~42% (human) | Bimodal distribution | | Duplication rate | < 30% (mRNA) | > 50% | | Gene body coverage | Uniform 5' to 3' | Strong 3' bias | | PCA | Samples cluster by condition | Outlier samples |
python# Molecular docking workflow using RDKit and AutoDock Vina from rdkit import Chem from rdkit.Chem import AllChem, Descriptors, Lipinski import subprocess def prepare_ligands(smiles_list: list) -> list: """ Prepare ligands for virtual screening. Apply Lipinski's Rule of Five and generate 3D conformers. """ prepared = [] for smiles in smiles_list: mol = Chem.MolFromSmiles(smiles) if mol is None: continue # Lipinski's Rule of Five filter mw = Descriptors.MolWt(mol) logp = Descriptors.MolLogP(mol) hbd = Descriptors.NumHDonors(mol) hba = Descriptors.NumHAcceptors(mol) if mw > 500 or logp > 5 or hbd > 5 or hba > 10: continue # Fails Ro5 # Generate 3D conformer mol_h = Chem.AddHs(mol) AllChem.EmbedMolecule(mol_h, AllChem.ETKDG()) AllChem.MMFFOptimizeMolecule(mol_h) prepared.append({ "smiles": smiles, "mol": mol_h, "mw": round(mw, 2), "logp": round(logp, 2), "hbd": hbd, "hba": hba, }) return prepared def compute_admet_properties(mol) -> dict: """Compute ADMET-relevant molecular descriptors.""" return { "tpsa": round(Descriptors.TPSA(mol), 2), # Topological polar surface area "rotatable_bonds": Descriptors.NumRotatableBonds(mol), "aromatic_rings": Descriptors.NumAromaticRings(mol), "fraction_csp3": round(Descriptors.FractionCSP3(mol), 3), # Drug-likeness "qed": round(Descriptors.qed(mol), 3), # Quantitative drug-likeness }
pythondef query_open_targets(target_id: str, disease_id: str) -> dict: """ Query Open Targets Platform for target-disease association evidence. """ import requests query = """ query targetDiseaseAssociation($target: String!, $disease: String!) { disease(efoId: $disease) { name associatedTargets(Bs: [$target]) { rows { target { approvedSymbol } score datatypeScores { componentId: id score } } } } } """ response = requests.post( "https://api.platform.opentargets.org/api/v4/graphql", json={"query": query, "variables": {"target": target_id, "disease": disease_id}}, ) return response.json()
Common clinical NLP tasks for research:
1. CLINICAL TEXT DE-IDENTIFICATION
- Remove PHI (Protected Health Information)
- Tools: Philter, NLM Scrubber, custom regex + NER
- Validation: Must achieve >95% recall for PHI
2. CLINICAL CODING
- Assign ICD-10, CPT, SNOMED-CT codes to clinical notes
- Approaches: Rule-based, ML classification, LLM extraction
- Evaluation: Precision/recall per code family
3. RELATION EXTRACTION
- Drug-disease, drug-adverse event, gene-disease relationships
- From clinical notes, discharge summaries, pathology reports
- Output: Knowledge graphs for downstream analysis
4. TEMPORAL INFORMATION EXTRACTION
- Disease onset, treatment timeline, outcome timing
- Critical for longitudinal studies and survival analysis
- Tools: SUTime, HeidelTime, custom models| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 16,250 | 19,570 | +20% | 1 | 1 | 0% | 3,322 | 6,096 | +84% | 0 | 0 | — |
case-02 | fail→fail | 17,745 | 10,757 | -39% | 1 | 1 | 0% | 3,305 | 5,101 | +54% | 0 | 0 | — |
case-03 | fail→pass | 24,563 | 14,487 | -41% | 1 | 1 | 0% | 4,477 | 5,882 | +31% | 0 | 0 | — |
case-04 | fail→pass | 12,923 | 10,858 | -16% | 1 | 1 | 0% | 2,396 | 5,027 | +110% | 0 | 0 | — |
case-05 | pass→pass | 8,485 | 5,736 | -32% | 1 | 1 | 0% | 1,620 | 4,063 | +151% | 0 | 0 | — |
case-06 | pass→pass | 8,492 | 5,975 | -30% | 1 | 1 | 0% | 1,616 | 4,169 | +158% | 0 | 0 | — |
case-07 | fail→pass | 14,416 | 3,359 | -77% | 1 | 1 | 0% | 2,341 | 3,519 | +50% | 0 | 0 | — |
case-08 | pass→pass | 12,287 | 3,409 | -72% | 1 | 1 | 0% | 2,161 | 3,528 | +63% | 0 | 0 | — |
case-09 | pass→pass | 7,840 | 6,094 | -22% | 1 | 1 | 0% | 1,262 | 3,999 | +217% | 0 | 0 | — |
case-10 | fail→pass | 10,671 | 10,978 | +3% | 1 | 1 | 0% | 2,209 | 5,415 | +145% | 0 | 0 | — |
case-11 | pass→pass | 7,676 | 4,635 | -40% | 1 | 1 | 0% | 1,537 | 3,861 | +151% | 0 | 0 | — |
case-12 | fail→pass | 16,911 | 3,051 | -82% | 1 | 1 | 0% | 2,478 | 3,489 | +41% | 0 | 0 | — |
case-13 | pass→pass | 13,495 | 14,236 | +5% | 1 | 1 | 0% | 2,251 | 5,301 | +135% | 0 | 0 | — |
case-14 | pass→pass | 9,503 | 3,879 | -59% | 1 | 1 | 0% | 1,674 | 3,711 | +122% | 0 | 0 | — |
case-15 | pass→pass | 9,009 | 7,564 | -16% | 1 | 1 | 0% | 1,555 | 4,210 | +171% | 0 | 0 | — |
case-16 | pass→pass | 7,551 | 2,342 | -69% | 1 | 1 | 0% | 1,217 | 3,382 | +178% | 0 | 0 | — |
case-17 | pass→pass | 6,458 | 4,423 | -32% | 1 | 1 | 0% | 1,137 | 3,834 | +237% | 0 | 0 | — |
case-18 | pass→pass | 18,223 | 20,483 | +12% | 1 | 1 | 0% | 2,988 | 6,274 | +110% | 0 | 0 | — |
case-19 | pass→pass | 16,153 | 14,137 | -12% | 1 | 1 | 0% | 2,781 | 5,534 | +99% | 0 | 0 | — |
case-20 | pass→pass | 12,736 | 12,586 | -1% | 1 | 1 | 0% | 2,414 | 5,544 | +130% | 0 | 0 | — |
case-21 | pass→pass | 17,758 | 20,033 | +13% | 1 | 1 | 0% | 3,085 | 6,709 | +117% | 0 | 0 | — |
case-22 | pass→pass | 10,576 | 8,476 | -20% | 1 | 1 | 0% | 2,042 | 4,761 | +133% | 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 +23 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.
Other measured skills in the registry, with their headline benchmark lift.