[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6XF9VQ2WP34FQGA55RC68GA":3,"skill-same:01M6XF9VQ2WP34FQGA55RC68GA":99},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":57,"commitSha":58,"skillDirectory":59,"forksCount":14,"repositoryHtmlUrl":60,"repositoryHomepageUrl":6,"ownerHtmlUrl":61,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":62,"install":63,"resources":76},"01M6XF9VQ2WP34FQGA55RC68GA","molecular-cloning",null,"Molecular cloning simulation and design. PCR amplicon prediction, restriction enzyme digestion, Golden Gate and Gibson assembly simulation, primer design, CRISPR sgRNA design, and plasmid annotation. For protein-level sequence analysis use biopython or esm; for database lookups use gene-database or ensembl-database.","fadrienne\u002FMyGitHub","fadrienne","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F197874571?v=4","01M6X64V8VWCRSMFZ4EPS2BWXG","Francesca Adrienne","01M6X64VD5MW4F9PHDWQKS7ZAF",0,"MIT","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000032","设计师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"molecular cloning","cloning","molecular","crispr","Protein","prediction","sequence","gene","for","primer design","biology","primer","design","gate","use","simulation","analysis","biopython","PCR","database","2026-11-10 10:12:30",false,"---\nname: molecular-cloning\ndescription: Molecular cloning simulation and design. PCR amplicon prediction, restriction enzyme digestion, Golden Gate and Gibson assembly simulation, primer design, CRISPR sgRNA design, and plasmid annotation. For protein-level sequence analysis use biopython or esm; for database lookups use gene-database or ensembl-database.\ncategory: biology\nlicense: MIT license\nmetadata:\n    skill-author: InkVell Inc.\n---\n\n# Molecular Cloning: Sequence Engineering & Cloning Design\n\n## Overview\n\nMolecular Cloning provides computational tools for simulating and designing molecular cloning workflows. This skill covers PCR amplicon prediction with primer binding analysis, restriction enzyme digestion simulation, Golden Gate and Gibson assembly design and verification, primer design with thermodynamic calculations, CRISPR sgRNA design with off-target scoring, and plasmid feature annotation. All simulations use Biopython's Bio.Restriction and Bio.SeqUtils for accurate enzyme and sequence handling.\n\n## When to Use This Skill\n\n- Predicting PCR amplicons from primer sequences and templates\n- Simulating restriction enzyme digestions and predicting fragment sizes\n- Designing Golden Gate assembly with 4bp overhang compatibility\n- Planning Gibson assembly with overlap design\n- Designing PCR primers with Tm and specificity constraints\n- Designing CRISPR sgRNAs and scoring off-target potential\n- Annotating plasmid features (promoters, CDS, terminators, origins)\n- Generating plasmid maps in GenBank format\n\n**Related Skills:** For protein-level sequence analysis use `biopython` or `esm`. For gene\u002Ftranscript lookups use `gene-database` or `ensembl-database`. For synthetic biology circuit design use `synthetic-biology`.\n\n## Installation\n\n```bash\nuv pip install biopython primer3-py numpy\n```\n\n## Quick Start\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.Restriction import BamHI, EcoRI\nfrom Bio.SeqUtils import MeltingTemp as mt\n\n# Restriction digestion\nsequence = Seq(\"ATCGATCGGGATCCATCGATCGAATTCATCGATCG\")\nprint(f\"BamHI cuts at: {BamHI.search(sequence)}\")\nprint(f\"EcoRI cuts at: {EcoRI.search(sequence)}\")\n\n# Primer Tm calculation\nprimer = Seq(\"ATCGATCGGATCCATCGATCG\")\ntm = mt.Tm_NN(primer)\nprint(f\"Primer Tm: {tm:.1f} C\")\n```\n\n## Core Capabilities\n\n### 1. PCR Simulation\n\nPredict amplicon from primer binding on template.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.SeqUtils import MeltingTemp as mt\nimport re\n\ndef find_primer_binding(template, primer, max_mismatches=2):\n    \"\"\"Find primer binding sites on template (both strands).\n\n    Returns list of (position, strand, mismatches) tuples.\n    \"\"\"\n    template_str = str(template).upper()\n    primer_str = str(primer).upper()\n    rc_template = str(template.reverse_complement()).upper()\n\n    sites = []\n\n    # Search forward strand\n    for i in range(len(template_str) - len(primer_str) + 1):\n        region = template_str[i:i+len(primer_str)]\n        mismatches = sum(a != b for a, b in zip(primer_str, region))\n        if mismatches \u003C= max_mismatches:\n            sites.append((i, '+', mismatches))\n\n    # Search reverse strand\n    for i in range(len(rc_template) - len(primer_str) + 1):\n        region = rc_template[i:i+len(primer_str)]\n        mismatches = sum(a != b for a, b in zip(primer_str, region))\n        if mismatches \u003C= max_mismatches:\n            pos = len(template_str) - i - len(primer_str)\n            sites.append((pos, '-', mismatches))\n\n    return sites\n\ndef simulate_pcr(template, fwd_primer, rev_primer, max_mismatches=2):\n    \"\"\"Simulate PCR and predict amplicon.\n\n    Args:\n        template: Bio.Seq template sequence (can be circular)\n        fwd_primer: forward primer sequence\n        rev_primer: reverse primer sequence (as ordered, 5'->3')\n    \"\"\"\n    fwd_sites = find_primer_binding(template, fwd_primer, max_mismatches)\n    rev_rc = Seq(str(rev_primer)).reverse_complement()\n    rev_sites = find_primer_binding(template, rev_rc, max_mismatches)\n\n    amplicons = []\n    for f_pos, f_strand, f_mm in fwd_sites:\n        if f_strand != '+':\n            continue\n        for r_pos, r_strand, r_mm in rev_sites:\n            if r_strand != '-':\n                continue\n            if r_pos > f_pos:\n                amp_len = r_pos + len(str(rev_primer)) - f_pos\n                if 50 \u003C amp_len \u003C 10000:  # Reasonable amplicon size\n                    amplicon = template[f_pos:r_pos + len(str(rev_primer))]\n                    amplicons.append({\n                        'start': f_pos,\n                        'end': r_pos + len(str(rev_primer)),\n                        'length': amp_len,\n                        'fwd_mismatches': f_mm,\n                        'rev_mismatches': r_mm,\n                        'sequence': str(amplicon)\n                    })\n\n    # Calculate primer Tm\n    fwd_tm = mt.Tm_NN(fwd_primer)\n    rev_tm = mt.Tm_NN(rev_primer)\n\n    print(f\"Forward primer Tm: {fwd_tm:.1f} C\")\n    print(f\"Reverse primer Tm: {rev_tm:.1f} C\")\n    print(f\"Tm difference: {abs(fwd_tm - rev_tm):.1f} C\")\n    print(f\"Predicted amplicons: {len(amplicons)}\")\n\n    for i, amp in enumerate(amplicons):\n        print(f\"  Amplicon {i+1}: {amp['length']} bp \"\n              f\"(pos {amp['start']}-{amp['end']}, \"\n              f\"mismatches: fwd={amp['fwd_mismatches']}, rev={amp['rev_mismatches']})\")\n\n    return amplicons\n```\n\n### 2. Restriction Digestion\n\nSimulate enzyme digestion and predict fragments.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.Restriction import *\nfrom Bio.Restriction import RestrictionBatch, Analysis\n\ndef restriction_digest(sequence, enzymes, is_linear=True):\n    \"\"\"Simulate restriction enzyme digestion.\n\n    Args:\n        sequence: Bio.Seq DNA sequence\n        enzymes: list of enzyme names (e.g., ['EcoRI', 'BamHI'])\n        is_linear: True for linear DNA, False for circular\n    \"\"\"\n    # Create restriction batch\n    rb = RestrictionBatch()\n    for enz_name in enzymes:\n        rb.add(eval(enz_name))\n\n    # Run analysis\n    analysis = Analysis(rb, sequence, linear=is_linear)\n    results = analysis.full()\n\n    all_cut_sites = []\n    for enzyme, sites in results.items():\n        if sites:\n            print(f\"{enzyme}: cuts at positions {sites}\")\n            all_cut_sites.extend(sites)\n        else:\n            print(f\"{enzyme}: no cut sites\")\n\n    # Calculate fragment sizes\n    if not all_cut_sites:\n        print(f\"No cuts — single fragment: {len(sequence)} bp\")\n        return [len(sequence)]\n\n    all_cut_sites = sorted(set(all_cut_sites))\n\n    if is_linear:\n        positions = [0] + all_cut_sites + [len(sequence)]\n    else:\n        positions = all_cut_sites\n\n    fragments = []\n    if is_linear:\n        for i in range(len(positions) - 1):\n            fragments.append(positions[i+1] - positions[i])\n    else:\n        for i in range(len(positions)):\n            next_i = (i + 1) % len(positions)\n            if next_i == 0:\n                frag = len(sequence) - positions[i] + positions[0]\n            else:\n                frag = positions[next_i] - positions[i]\n            fragments.append(frag)\n\n    fragments.sort(reverse=True)\n    print(f\"\\nFragments ({len(fragments)}): {fragments}\")\n    print(f\"Total: {sum(fragments)} bp\")\n\n    return fragments\n\n# Example: double digest\nseq = Seq(\"ATCG\" * 100 + \"GGATCC\" + \"ATCG\" * 50 + \"GAATTC\" + \"ATCG\" * 75)\nfrags = restriction_digest(seq, ['BamHI', 'EcoRI'], is_linear=True)\n```\n\n### 3. Golden Gate Assembly\n\nDesign and simulate Golden Gate cloning.\n\n```python\nfrom Bio.Seq import Seq\n\ndef design_golden_gate(parts, enzyme='BsaI'):\n    \"\"\"Design Golden Gate assembly with verified overhang compatibility.\n\n    Args:\n        parts: list of dicts with 'name', 'sequence' keys\n        enzyme: Type IIS enzyme ('BsaI' or 'BpiI')\n    \"\"\"\n    # Standard overhangs for 4-part Golden Gate\n    standard_overhangs = [\n        'AATG',  # Start codon region\n        'AGGT',\n        'TTCG',\n        'GCTT',\n        'CGCT',  # After last part (return to vector)\n    ]\n\n    if len(parts) + 1 > len(standard_overhangs):\n        raise ValueError(f\"Too many parts ({len(parts)}) for standard overhang set\")\n\n    # Check overhang compatibility (no palindromes, no near-matches)\n    overhangs_used = standard_overhangs[:len(parts) + 1]\n    for i, oh in enumerate(overhangs_used):\n        rc = str(Seq(oh).reverse_complement())\n        if oh == rc:\n            print(f\"WARNING: Overhang {oh} is palindromic — may self-ligate\")\n        for j, oh2 in enumerate(overhangs_used):\n            if i != j and oh == oh2:\n                raise ValueError(f\"Duplicate overhangs: position {i} and {j}\")\n\n    # Build assembly plan\n    assembly = []\n    for i, part in enumerate(parts):\n        left_oh = overhangs_used[i]\n        right_oh = overhangs_used[i + 1]\n\n        # Part with enzyme sites added\n        if enzyme == 'BsaI':\n            recognition = 'GGTCTC'\n            spacer = 'N'\n        else:  # BpiI\n            recognition = 'GAAGAC'\n            spacer = 'NN'\n\n        assembled_part = f\"{recognition}{spacer}{left_oh}{part['sequence']}{right_oh}\"\n\n        assembly.append({\n            'name': part['name'],\n            'left_overhang': left_oh,\n            'right_overhang': right_oh,\n            'part_length': len(part['sequence']),\n            'total_length': len(assembled_part)\n        })\n\n        print(f\"Part {i+1} ({part['name']}): [{left_oh}]--{len(part['sequence'])}bp--[{right_oh}]\")\n\n    # Predict assembled product\n    total_insert = sum(len(p['sequence']) for p in parts) + \\\n                   len(overhangs_used) * 4  # Overhangs contribute 4bp each\n    print(f\"\\nAssembly: {len(parts)} parts\")\n    print(f\"Total insert: ~{total_insert} bp (excluding vector)\")\n    print(f\"Overhang set: {' -> '.join(overhangs_used)}\")\n\n    return assembly\n\n# Example\nparts = [\n    {'name': 'Promoter', 'sequence': 'TTGACAATTAATCATCGGCTCG' * 5},\n    {'name': 'RBS', 'sequence': 'AAGGAGATATACAT'},\n    {'name': 'GFP_CDS', 'sequence': 'ATGGTGAGCAAGGGCGAG' * 40},\n    {'name': 'Terminator', 'sequence': 'TTTTTTTTTTT' * 4},\n]\n\nassembly = design_golden_gate(parts)\n```\n\n### 4. Gibson Assembly\n\nDesign overlapping fragments for Gibson assembly.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.SeqUtils import MeltingTemp as mt\n\ndef design_gibson_assembly(fragments, overlap_length=30):\n    \"\"\"Design Gibson assembly with overlap primers.\n\n    Args:\n        fragments: list of dicts with 'name', 'sequence' keys (in assembly order)\n        overlap_length: overlap length in bp (20-40 recommended)\n    \"\"\"\n    assembly_plan = []\n\n    for i in range(len(fragments)):\n        current = fragments[i]\n        next_frag = fragments[(i + 1) % len(fragments)]\n\n        # Forward primer: end of previous fragment + start of current\n        if i == 0:\n            fwd_primer = current['sequence'][:20]\n        else:\n            prev = fragments[i - 1]\n            overlap_5 = prev['sequence'][-overlap_length:]\n            fwd_primer = overlap_5 + current['sequence'][:20]\n\n        # Reverse primer: RC of (end of current + start of next)\n        overlap_3 = next_frag['sequence'][:overlap_length]\n        rev_binding = str(Seq(current['sequence'][-20:]).reverse_complement())\n        rev_primer = str(Seq(overlap_3).reverse_complement()) + rev_binding\n\n        # Tm of binding region\n        fwd_tm = mt.Tm_NN(Seq(current['sequence'][:20]))\n        rev_tm = mt.Tm_NN(Seq(current['sequence'][-20:]))\n\n        assembly_plan.append({\n            'fragment': current['name'],\n            'fragment_length': len(current['sequence']),\n            'fwd_primer': fwd_primer,\n            'rev_primer': rev_primer,\n            'fwd_tm': fwd_tm,\n            'rev_tm': rev_tm,\n            'overlap_length': overlap_length\n        })\n\n        print(f\"Fragment {i+1} ({current['name']}): {len(current['sequence'])} bp\")\n        print(f\"  Fwd primer: {fwd_primer[:40]}... ({len(fwd_primer)} nt, Tm={fwd_tm:.1f} C)\")\n        print(f\"  Rev primer: {rev_primer[:40]}... ({len(rev_primer)} nt, Tm={rev_tm:.1f} C)\")\n\n    total = sum(len(f['sequence']) for f in fragments)\n    print(f\"\\nTotal assembled length: ~{total} bp\")\n\n    return assembly_plan\n```\n\n### 5. Primer Design\n\nDesign primers with thermodynamic constraints.\n\n```python\nimport primer3\n\ndef design_primers(template_seq, target_start, target_length,\n                   product_size_range=(200, 500), tm_target=60):\n    \"\"\"Design PCR primers using primer3.\n\n    Args:\n        template_seq: template DNA sequence (string)\n        target_start: start position of target region\n        target_length: length of target region\n        product_size_range: (min, max) product size\n        tm_target: target melting temperature\n    \"\"\"\n    result = primer3.bindings.design_primers(\n        seq_args={\n            'SEQUENCE_TEMPLATE': template_seq,\n            'SEQUENCE_TARGET': [target_start, target_length],\n        },\n        global_args={\n            'PRIMER_NUM_RETURN': 5,\n            'PRIMER_OPT_SIZE': 20,\n            'PRIMER_MIN_SIZE': 18,\n            'PRIMER_MAX_SIZE': 25,\n            'PRIMER_OPT_TM': tm_target,\n            'PRIMER_MIN_TM': tm_target - 5,\n            'PRIMER_MAX_TM': tm_target + 5,\n            'PRIMER_MIN_GC': 40,\n            'PRIMER_MAX_GC': 60,\n            'PRIMER_PRODUCT_SIZE_RANGE': [list(product_size_range)],\n            'PRIMER_MAX_SELF_COMPLEMENT': 6,\n            'PRIMER_MAX_SELF_END': 3,\n            'PRIMER_MAX_HAIRPIN_TH': 47,\n        }\n    )\n\n    primers = []\n    for i in range(result.get('PRIMER_PAIR_NUM_RETURNED', 0)):\n        pair = {\n            'left_seq': result[f'PRIMER_LEFT_{i}_SEQUENCE'],\n            'right_seq': result[f'PRIMER_RIGHT_{i}_SEQUENCE'],\n            'left_tm': result[f'PRIMER_LEFT_{i}_TM'],\n            'right_tm': result[f'PRIMER_RIGHT_{i}_TM'],\n            'left_gc': result[f'PRIMER_LEFT_{i}_GC_PERCENT'],\n            'right_gc': result[f'PRIMER_RIGHT_{i}_GC_PERCENT'],\n            'product_size': result[f'PRIMER_PAIR_{i}_PRODUCT_SIZE'],\n            'penalty': result[f'PRIMER_PAIR_{i}_PENALTY'],\n        }\n        primers.append(pair)\n        print(f\"Pair {i+1}: product={pair['product_size']}bp, penalty={pair['penalty']:.2f}\")\n        print(f\"  Fwd: {pair['left_seq']} (Tm={pair['left_tm']:.1f}, GC={pair['left_gc']:.0f}%)\")\n        print(f\"  Rev: {pair['right_seq']} (Tm={pair['right_tm']:.1f}, GC={pair['right_gc']:.0f}%)\")\n\n    return primers\n```\n\n### 6. CRISPR sgRNA Design\n\nDesign guide RNAs for CRISPR-Cas9 knockout.\n\n```python\nfrom Bio.Seq import Seq\nimport re\n\ndef design_crispr_guides(target_seq, pam='NGG', guide_length=20, top_n=10):\n    \"\"\"Design CRISPR sgRNAs for SpCas9.\n\n    Args:\n        target_seq: target gene\u002Fregion sequence (string)\n        pam: PAM sequence ('NGG' for SpCas9)\n        guide_length: guide RNA length (typically 20)\n        top_n: number of top guides to return\n    \"\"\"\n    seq = str(target_seq).upper()\n    rc_seq = str(Seq(seq).reverse_complement())\n\n    guides = []\n\n    # Search forward strand for PAM (NGG at 3' end of target)\n    for i in range(len(seq) - guide_length - len(pam) + 1):\n        pam_site = seq[i + guide_length:i + guide_length + 3]\n        if re.match(pam.replace('N', '.'), pam_site):\n            guide_seq = seq[i:i + guide_length]\n            score = score_guide(guide_seq)\n            guides.append({\n                'sequence': guide_seq,\n                'pam': pam_site,\n                'position': i,\n                'strand': '+',\n                'score': score,\n                'full_target': guide_seq + pam_site\n            })\n\n    # Search reverse strand\n    for i in range(len(rc_seq) - guide_length - len(pam) + 1):\n        pam_site = rc_seq[i + guide_length:i + guide_length + 3]\n        if re.match(pam.replace('N', '.'), pam_site):\n            guide_seq = rc_seq[i:i + guide_length]\n            score = score_guide(guide_seq)\n            guides.append({\n                'sequence': guide_seq,\n                'pam': pam_site,\n                'position': len(seq) - i - guide_length,\n                'strand': '-',\n                'score': score,\n                'full_target': guide_seq + pam_site\n            })\n\n    # Sort by score (higher is better)\n    guides.sort(key=lambda x: x['score'], reverse=True)\n\n    print(f\"Found {len(guides)} potential guide RNAs\")\n    print(f\"\\nTop {min(top_n, len(guides))} guides:\")\n    for i, g in enumerate(guides[:top_n]):\n        print(f\"  {i+1}. {g['sequence']} {g['pam']} \"\n              f\"(strand={g['strand']}, pos={g['position']}, score={g['score']:.2f})\")\n\n    return guides[:top_n]\n\ndef score_guide(guide_seq):\n    \"\"\"Heuristic guide scoring based on known design rules.\"\"\"\n    score = 50.0  # Base score\n\n    # GC content (40-70% preferred)\n    gc = (guide_seq.count('G') + guide_seq.count('C')) \u002F len(guide_seq)\n    if 0.4 \u003C= gc \u003C= 0.7:\n        score += 10\n    elif gc \u003C 0.3 or gc > 0.8:\n        score -= 20\n\n    # Avoid poly-T (>4 consecutive T = pol III terminator)\n    if 'TTTT' in guide_seq:\n        score -= 30\n\n    # G at position 20 (adjacent to PAM) preferred\n    if guide_seq[-1] == 'G':\n        score += 5\n\n    # Avoid GG at position 19-20 (can cause off-target)\n    if guide_seq[-2:] == 'GG':\n        score -= 5\n\n    # Self-complementarity penalty\n    rc = str(Seq(guide_seq).reverse_complement())\n    matches = sum(a == b for a, b in zip(guide_seq, rc))\n    if matches > 12:\n        score -= 15\n\n    return max(score, 0)\n```\n\n### 7. Plasmid Annotation\n\nIdentify and annotate features in plasmid sequences.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.SeqRecord import SeqRecord\nfrom Bio.SeqFeature import SeqFeature, FeatureLocation\nfrom Bio import SeqIO\nfrom Bio.Restriction import RestrictionBatch, Analysis, CommOnly\n\ndef annotate_plasmid(sequence, name='plasmid'):\n    \"\"\"Annotate plasmid features and restriction sites.\n\n    Args:\n        sequence: plasmid DNA sequence (string)\n        name: plasmid name\n    \"\"\"\n    seq = Seq(sequence)\n    record = SeqRecord(seq, id=name, name=name,\n                       description=f'{name} annotated plasmid',\n                       annotations={'molecule_type': 'DNA', 'topology': 'circular'})\n\n    # Common feature patterns\n    feature_patterns = {\n        'T7_promoter': 'TAATACGACTCACTATAG',\n        'lac_operator': 'AATTGTGAGCGGATAACAATT',\n        'RBS_consensus': 'AAGGAG',\n        'T7_terminator': 'CTAGCATAACCCCTTGGGGCCTCTAAACGGGTCTTGAGG',\n        'ColE1_origin': 'CCTGTTTTGGCGGATGAGAGAAG',\n    }\n\n    for feat_name, pattern in feature_patterns.items():\n        pos = str(seq).find(pattern)\n        if pos >= 0:\n            record.features.append(SeqFeature(\n                FeatureLocation(pos, pos + len(pattern)),\n                type='misc_feature',\n                qualifiers={'label': feat_name}\n            ))\n            print(f\"Found {feat_name} at position {pos}\")\n\n    # Find ORFs (>300bp)\n    for strand, nuc in [(1, seq), (-1, seq.reverse_complement())]:\n        for frame in range(3):\n            trans = str(nuc[frame:].translate())\n            start = 0\n            while True:\n                start = trans.find('M', start)\n                if start == -1:\n                    break\n                stop = trans.find('*', start)\n                if stop == -1:\n                    stop = len(trans)\n                orf_len = (stop - start) * 3\n\n                if orf_len >= 300:\n                    if strand == 1:\n                        dna_start = frame + start * 3\n                        dna_end = frame + stop * 3 + 3\n                    else:\n                        dna_end = len(seq) - frame - start * 3\n                        dna_start = len(seq) - frame - stop * 3 - 3\n\n                    record.features.append(SeqFeature(\n                        FeatureLocation(min(dna_start, dna_end),\n                                       max(dna_start, dna_end), strand),\n                        type='CDS',\n                        qualifiers={'label': f'ORF_{orf_len}bp'}\n                    ))\n                    print(f\"ORF: {orf_len}bp at {dna_start}-{dna_end} (strand {'+' if strand==1 else '-'})\")\n\n                start = stop + 1\n\n    # Map restriction sites\n    rb = CommOnly\n    analysis = Analysis(rb, seq, linear=False)\n    unique_sites = {str(enz): sites for enz, sites in analysis.full().items()\n                    if len(sites) == 1}\n\n    print(f\"\\nUnique restriction sites: {len(unique_sites)}\")\n    for enz, sites in sorted(unique_sites.items()):\n        print(f\"  {enz}: {sites[0]}\")\n\n    return record\n\n# Write annotated plasmid\n# record = annotate_plasmid(plasmid_seq, name='pMyPlasmid')\n# SeqIO.write(record, 'pMyPlasmid.gb', 'genbank')\n```\n\n## Typical Workflows\n\n### Workflow 1: Design PCR Primers and Predict Amplicon\n\n```python\nfrom Bio.Seq import Seq\n\ntemplate = Seq(\"ATCGATCGATCGATCGATCGATCGATCG\" * 50)  # 1400 bp template\nfwd = Seq(\"ATCGATCGATCGATCGATCG\")\nrev = Seq(\"CGATCGATCGATCGATCGAT\")\n\namplicons = simulate_pcr(template, fwd, rev)\nif amplicons:\n    print(f\"Amplicon size: {amplicons[0]['length']} bp\")\n```\n\n### Workflow 2: Plan Golden Gate Assembly with 4 Parts\n\n```python\nparts = [\n    {'name': 'J23100_promoter', 'sequence': 'TTGACGGCTAGCTCAGTCCTAGGTACAGTGCTAGC'},\n    {'name': 'B0034_RBS', 'sequence': 'AAAGAGGAGAAA'},\n    {'name': 'GFP', 'sequence': 'ATGGTGAGCAAGGGCGAGGAG' + 'NNN' * 230 + 'TAA'},\n    {'name': 'B0015_terminator', 'sequence': 'CCAGGCATCAAATAAAACGAAAGGCTCAGTCGAAAG'},\n]\nassembly = design_golden_gate(parts)\n```\n\n### Workflow 3: Design CRISPR Knockout sgRNAs\n\n```python\n# Target: exon 3 of a gene\ntarget_exon = \"ATGCGATCGATCGATCGATCGATCGAGGCGATCGATCGATCGATCGATCGATCGATCGATCG\"\nguides = design_crispr_guides(target_exon, pam='NGG', top_n=5)\n```\n\n## Best Practices\n\n1. **Primer design** — aim for Tm within 2 C between forward and reverse primers; 40-60% GC content; avoid 3' complementarity\n2. **Golden Gate** — verify 4bp overhangs are unique and non-palindromic; use standardized overhang sets from published studies\n3. **Gibson assembly** — use 20-40bp overlaps; ensure fragments have similar Tm at overlap junctions; minimum 2 fragments\n4. **CRISPR guides** — avoid poly-T (>4 T) which terminates U6\u002FH1 transcription; prefer guides in early exons; validate against off-target databases\n5. **Restriction digestion** — always check both orientations; verify compatible cohesive ends for ligation; methylation sensitivity can block cutting\n6. **Plasmid annotation** — verify ORFs are in correct reading frame; check for cryptic promoters; map all unique restriction sites for future cloning\n\n## Troubleshooting\n\n**Problem:** PCR simulation finds no amplicons\n**Solution:** Check primer orientation (forward should match sense strand 5'->3'). Increase `max_mismatches`. Verify template contains the target region.\n\n**Problem:** Restriction enzyme doesn't cut expected site\n**Solution:** Check for CpG methylation sensitivity (dam\u002Fdcm methylation). Verify site isn't in a modified context. Use `isoschizomers()` to find alternatives.\n\n**Problem:** Golden Gate assembly produces wrong product\n**Solution:** Verify all overhangs are unique. Check enzyme is BsaI (not BsmBI) — different cut distances. Ensure parts are in correct orientation.\n\n**Problem:** primer3 returns no primers\n**Solution:** Relax constraints: widen Tm range, increase max size, lower GC requirement. Ensure target region has sufficient flanking sequence.\n\n**Problem:** CRISPR guide design returns few candidates\n**Solution:** Expand search region (use full gene, not just one exon). Try alternative PAM sequences (NAG for relaxed SpCas9). Consider Cas12a (TTTV PAM) for AT-rich regions.\n\n## Resources\n\n- [Biopython Restriction Module](https:\u002F\u002Fbiopython.org\u002Fwiki\u002FRestriction)\n- [primer3-py Documentation](https:\u002F\u002Flibnano.github.io\u002Fprimer3-py\u002F)\n- [CRISPR Design Rules](https:\u002F\u002Fdoi.org\u002F10.1038\u002Fnbt.2647)\n- [Golden Gate Assembly (Engler et al.)](https:\u002F\u002Fdoi.org\u002F10.1371\u002Fjournal.pone.0003647)\n- [Gibson Assembly (Gibson et al.)](https:\u002F\u002Fdoi.org\u002F10.1038\u002Fnmeth.1318)\n","# Molecular Cloning: Sequence Engineering & Cloning Design\n\n## Overview\n\nMolecular Cloning provides computational tools for simulating and designing molecular cloning workflows. This skill covers PCR amplicon prediction with primer binding analysis, restriction enzyme digestion simulation, Golden Gate and Gibson assembly design and verification, primer design with thermodynamic calculations, CRISPR sgRNA design with off-target scoring, and plasmid feature annotation. All simulations use Biopython's Bio.Restriction and Bio.SeqUtils for accurate enzyme and sequence handling.\n\n## When to Use This Skill\n\n- Predicting PCR amplicons from primer sequences and templates\n- Simulating restriction enzyme digestions and predicting fragment sizes\n- Designing Golden Gate assembly with 4bp overhang compatibility\n- Planning Gibson assembly with overlap design\n- Designing PCR primers with Tm and specificity constraints\n- Designing CRISPR sgRNAs and scoring off-target potential\n- Annotating plasmid features (promoters, CDS, terminators, origins)\n- Generating plasmid maps in GenBank format\n\n**Related Skills:** For protein-level sequence analysis use `biopython` or `esm`. For gene\u002Ftranscript lookups use `gene-database` or `ensembl-database`. For synthetic biology circuit design use `synthetic-biology`.\n\n## Installation\n\n```bash\nuv pip install biopython primer3-py numpy\n```\n\n## Quick Start\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.Restriction import BamHI, EcoRI\nfrom Bio.SeqUtils import MeltingTemp as mt\n\n# Restriction digestion\nsequence = Seq(\"ATCGATCGGGATCCATCGATCGAATTCATCGATCG\")\nprint(f\"BamHI cuts at: {BamHI.search(sequence)}\")\nprint(f\"EcoRI cuts at: {EcoRI.search(sequence)}\")\n\n# Primer Tm calculation\nprimer = Seq(\"ATCGATCGGATCCATCGATCG\")\ntm = mt.Tm_NN(primer)\nprint(f\"Primer Tm: {tm:.1f} C\")\n```\n\n## Core Capabilities\n\n### 1. PCR Simulation\n\nPredict amplicon from primer binding on template.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.SeqUtils import MeltingTemp as mt\nimport re\n\ndef find_primer_binding(template, primer, max_mismatches=2):\n    \"\"\"Find primer binding sites on template (both strands).\n\n    Returns list of (position, strand, mismatches) tuples.\n    \"\"\"\n    template_str = str(template).upper()\n    primer_str = str(primer).upper()\n    rc_template = str(template.reverse_complement()).upper()\n\n    sites = []\n\n    # Search forward strand\n    for i in range(len(template_str) - len(primer_str) + 1):\n        region = template_str[i:i+len(primer_str)]\n        mismatches = sum(a != b for a, b in zip(primer_str, region))\n        if mismatches \u003C= max_mismatches:\n            sites.append((i, '+', mismatches))\n\n    # Search reverse strand\n    for i in range(len(rc_template) - len(primer_str) + 1):\n        region = rc_template[i:i+len(primer_str)]\n        mismatches = sum(a != b for a, b in zip(primer_str, region))\n        if mismatches \u003C= max_mismatches:\n            pos = len(template_str) - i - len(primer_str)\n            sites.append((pos, '-', mismatches))\n\n    return sites\n\ndef simulate_pcr(template, fwd_primer, rev_primer, max_mismatches=2):\n    \"\"\"Simulate PCR and predict amplicon.\n\n    Args:\n        template: Bio.Seq template sequence (can be circular)\n        fwd_primer: forward primer sequence\n        rev_primer: reverse primer sequence (as ordered, 5'->3')\n    \"\"\"\n    fwd_sites = find_primer_binding(template, fwd_primer, max_mismatches)\n    rev_rc = Seq(str(rev_primer)).reverse_complement()\n    rev_sites = find_primer_binding(template, rev_rc, max_mismatches)\n\n    amplicons = []\n    for f_pos, f_strand, f_mm in fwd_sites:\n        if f_strand != '+':\n            continue\n        for r_pos, r_strand, r_mm in rev_sites:\n            if r_strand != '-':\n                continue\n            if r_pos > f_pos:\n                amp_len = r_pos + len(str(rev_primer)) - f_pos\n                if 50 \u003C amp_len \u003C 10000:  # Reasonable amplicon size\n                    amplicon = template[f_pos:r_pos + len(str(rev_primer))]\n                    amplicons.append({\n                        'start': f_pos,\n                        'end': r_pos + len(str(rev_primer)),\n                        'length': amp_len,\n                        'fwd_mismatches': f_mm,\n                        'rev_mismatches': r_mm,\n                        'sequence': str(amplicon)\n                    })\n\n    # Calculate primer Tm\n    fwd_tm = mt.Tm_NN(fwd_primer)\n    rev_tm = mt.Tm_NN(rev_primer)\n\n    print(f\"Forward primer Tm: {fwd_tm:.1f} C\")\n    print(f\"Reverse primer Tm: {rev_tm:.1f} C\")\n    print(f\"Tm difference: {abs(fwd_tm - rev_tm):.1f} C\")\n    print(f\"Predicted amplicons: {len(amplicons)}\")\n\n    for i, amp in enumerate(amplicons):\n        print(f\"  Amplicon {i+1}: {amp['length']} bp \"\n              f\"(pos {amp['start']}-{amp['end']}, \"\n              f\"mismatches: fwd={amp['fwd_mismatches']}, rev={amp['rev_mismatches']})\")\n\n    return amplicons\n```\n\n### 2. Restriction Digestion\n\nSimulate enzyme digestion and predict fragments.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.Restriction import *\nfrom Bio.Restriction import RestrictionBatch, Analysis\n\ndef restriction_digest(sequence, enzymes, is_linear=True):\n    \"\"\"Simulate restriction enzyme digestion.\n\n    Args:\n        sequence: Bio.Seq DNA sequence\n        enzymes: list of enzyme names (e.g., ['EcoRI', 'BamHI'])\n        is_linear: True for linear DNA, False for circular\n    \"\"\"\n    # Create restriction batch\n    rb = RestrictionBatch()\n    for enz_name in enzymes:\n        rb.add(eval(enz_name))\n\n    # Run analysis\n    analysis = Analysis(rb, sequence, linear=is_linear)\n    results = analysis.full()\n\n    all_cut_sites = []\n    for enzyme, sites in results.items():\n        if sites:\n            print(f\"{enzyme}: cuts at positions {sites}\")\n            all_cut_sites.extend(sites)\n        else:\n            print(f\"{enzyme}: no cut sites\")\n\n    # Calculate fragment sizes\n    if not all_cut_sites:\n        print(f\"No cuts — single fragment: {len(sequence)} bp\")\n        return [len(sequence)]\n\n    all_cut_sites = sorted(set(all_cut_sites))\n\n    if is_linear:\n        positions = [0] + all_cut_sites + [len(sequence)]\n    else:\n        positions = all_cut_sites\n\n    fragments = []\n    if is_linear:\n        for i in range(len(positions) - 1):\n            fragments.append(positions[i+1] - positions[i])\n    else:\n        for i in range(len(positions)):\n            next_i = (i + 1) % len(positions)\n            if next_i == 0:\n                frag = len(sequence) - positions[i] + positions[0]\n            else:\n                frag = positions[next_i] - positions[i]\n            fragments.append(frag)\n\n    fragments.sort(reverse=True)\n    print(f\"\\nFragments ({len(fragments)}): {fragments}\")\n    print(f\"Total: {sum(fragments)} bp\")\n\n    return fragments\n\n# Example: double digest\nseq = Seq(\"ATCG\" * 100 + \"GGATCC\" + \"ATCG\" * 50 + \"GAATTC\" + \"ATCG\" * 75)\nfrags = restriction_digest(seq, ['BamHI', 'EcoRI'], is_linear=True)\n```\n\n### 3. Golden Gate Assembly\n\nDesign and simulate Golden Gate cloning.\n\n```python\nfrom Bio.Seq import Seq\n\ndef design_golden_gate(parts, enzyme='BsaI'):\n    \"\"\"Design Golden Gate assembly with verified overhang compatibility.\n\n    Args:\n        parts: list of dicts with 'name', 'sequence' keys\n        enzyme: Type IIS enzyme ('BsaI' or 'BpiI')\n    \"\"\"\n    # Standard overhangs for 4-part Golden Gate\n    standard_overhangs = [\n        'AATG',  # Start codon region\n        'AGGT',\n        'TTCG',\n        'GCTT',\n        'CGCT',  # After last part (return to vector)\n    ]\n\n    if len(parts) + 1 > len(standard_overhangs):\n        raise ValueError(f\"Too many parts ({len(parts)}) for standard overhang set\")\n\n    # Check overhang compatibility (no palindromes, no near-matches)\n    overhangs_used = standard_overhangs[:len(parts) + 1]\n    for i, oh in enumerate(overhangs_used):\n        rc = str(Seq(oh).reverse_complement())\n        if oh == rc:\n            print(f\"WARNING: Overhang {oh} is palindromic — may self-ligate\")\n        for j, oh2 in enumerate(overhangs_used):\n            if i != j and oh == oh2:\n                raise ValueError(f\"Duplicate overhangs: position {i} and {j}\")\n\n    # Build assembly plan\n    assembly = []\n    for i, part in enumerate(parts):\n        left_oh = overhangs_used[i]\n        right_oh = overhangs_used[i + 1]\n\n        # Part with enzyme sites added\n        if enzyme == 'BsaI':\n            recognition = 'GGTCTC'\n            spacer = 'N'\n        else:  # BpiI\n            recognition = 'GAAGAC'\n            spacer = 'NN'\n\n        assembled_part = f\"{recognition}{spacer}{left_oh}{part['sequence']}{right_oh}\"\n\n        assembly.append({\n            'name': part['name'],\n            'left_overhang': left_oh,\n            'right_overhang': right_oh,\n            'part_length': len(part['sequence']),\n            'total_length': len(assembled_part)\n        })\n\n        print(f\"Part {i+1} ({part['name']}): [{left_oh}]--{len(part['sequence'])}bp--[{right_oh}]\")\n\n    # Predict assembled product\n    total_insert = sum(len(p['sequence']) for p in parts) + \\\n                   len(overhangs_used) * 4  # Overhangs contribute 4bp each\n    print(f\"\\nAssembly: {len(parts)} parts\")\n    print(f\"Total insert: ~{total_insert} bp (excluding vector)\")\n    print(f\"Overhang set: {' -> '.join(overhangs_used)}\")\n\n    return assembly\n\n# Example\nparts = [\n    {'name': 'Promoter', 'sequence': 'TTGACAATTAATCATCGGCTCG' * 5},\n    {'name': 'RBS', 'sequence': 'AAGGAGATATACAT'},\n    {'name': 'GFP_CDS', 'sequence': 'ATGGTGAGCAAGGGCGAG' * 40},\n    {'name': 'Terminator', 'sequence': 'TTTTTTTTTTT' * 4},\n]\n\nassembly = design_golden_gate(parts)\n```\n\n### 4. Gibson Assembly\n\nDesign overlapping fragments for Gibson assembly.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.SeqUtils import MeltingTemp as mt\n\ndef design_gibson_assembly(fragments, overlap_length=30):\n    \"\"\"Design Gibson assembly with overlap primers.\n\n    Args:\n        fragments: list of dicts with 'name', 'sequence' keys (in assembly order)\n        overlap_length: overlap length in bp (20-40 recommended)\n    \"\"\"\n    assembly_plan = []\n\n    for i in range(len(fragments)):\n        current = fragments[i]\n        next_frag = fragments[(i + 1) % len(fragments)]\n\n        # Forward primer: end of previous fragment + start of current\n        if i == 0:\n            fwd_primer = current['sequence'][:20]\n        else:\n            prev = fragments[i - 1]\n            overlap_5 = prev['sequence'][-overlap_length:]\n            fwd_primer = overlap_5 + current['sequence'][:20]\n\n        # Reverse primer: RC of (end of current + start of next)\n        overlap_3 = next_frag['sequence'][:overlap_length]\n        rev_binding = str(Seq(current['sequence'][-20:]).reverse_complement())\n        rev_primer = str(Seq(overlap_3).reverse_complement()) + rev_binding\n\n        # Tm of binding region\n        fwd_tm = mt.Tm_NN(Seq(current['sequence'][:20]))\n        rev_tm = mt.Tm_NN(Seq(current['sequence'][-20:]))\n\n        assembly_plan.append({\n            'fragment': current['name'],\n            'fragment_length': len(current['sequence']),\n            'fwd_primer': fwd_primer,\n            'rev_primer': rev_primer,\n            'fwd_tm': fwd_tm,\n            'rev_tm': rev_tm,\n            'overlap_length': overlap_length\n        })\n\n        print(f\"Fragment {i+1} ({current['name']}): {len(current['sequence'])} bp\")\n        print(f\"  Fwd primer: {fwd_primer[:40]}... ({len(fwd_primer)} nt, Tm={fwd_tm:.1f} C)\")\n        print(f\"  Rev primer: {rev_primer[:40]}... ({len(rev_primer)} nt, Tm={rev_tm:.1f} C)\")\n\n    total = sum(len(f['sequence']) for f in fragments)\n    print(f\"\\nTotal assembled length: ~{total} bp\")\n\n    return assembly_plan\n```\n\n### 5. Primer Design\n\nDesign primers with thermodynamic constraints.\n\n```python\nimport primer3\n\ndef design_primers(template_seq, target_start, target_length,\n                   product_size_range=(200, 500), tm_target=60):\n    \"\"\"Design PCR primers using primer3.\n\n    Args:\n        template_seq: template DNA sequence (string)\n        target_start: start position of target region\n        target_length: length of target region\n        product_size_range: (min, max) product size\n        tm_target: target melting temperature\n    \"\"\"\n    result = primer3.bindings.design_primers(\n        seq_args={\n            'SEQUENCE_TEMPLATE': template_seq,\n            'SEQUENCE_TARGET': [target_start, target_length],\n        },\n        global_args={\n            'PRIMER_NUM_RETURN': 5,\n            'PRIMER_OPT_SIZE': 20,\n            'PRIMER_MIN_SIZE': 18,\n            'PRIMER_MAX_SIZE': 25,\n            'PRIMER_OPT_TM': tm_target,\n            'PRIMER_MIN_TM': tm_target - 5,\n            'PRIMER_MAX_TM': tm_target + 5,\n            'PRIMER_MIN_GC': 40,\n            'PRIMER_MAX_GC': 60,\n            'PRIMER_PRODUCT_SIZE_RANGE': [list(product_size_range)],\n            'PRIMER_MAX_SELF_COMPLEMENT': 6,\n            'PRIMER_MAX_SELF_END': 3,\n            'PRIMER_MAX_HAIRPIN_TH': 47,\n        }\n    )\n\n    primers = []\n    for i in range(result.get('PRIMER_PAIR_NUM_RETURNED', 0)):\n        pair = {\n            'left_seq': result[f'PRIMER_LEFT_{i}_SEQUENCE'],\n            'right_seq': result[f'PRIMER_RIGHT_{i}_SEQUENCE'],\n            'left_tm': result[f'PRIMER_LEFT_{i}_TM'],\n            'right_tm': result[f'PRIMER_RIGHT_{i}_TM'],\n            'left_gc': result[f'PRIMER_LEFT_{i}_GC_PERCENT'],\n            'right_gc': result[f'PRIMER_RIGHT_{i}_GC_PERCENT'],\n            'product_size': result[f'PRIMER_PAIR_{i}_PRODUCT_SIZE'],\n            'penalty': result[f'PRIMER_PAIR_{i}_PENALTY'],\n        }\n        primers.append(pair)\n        print(f\"Pair {i+1}: product={pair['product_size']}bp, penalty={pair['penalty']:.2f}\")\n        print(f\"  Fwd: {pair['left_seq']} (Tm={pair['left_tm']:.1f}, GC={pair['left_gc']:.0f}%)\")\n        print(f\"  Rev: {pair['right_seq']} (Tm={pair['right_tm']:.1f}, GC={pair['right_gc']:.0f}%)\")\n\n    return primers\n```\n\n### 6. CRISPR sgRNA Design\n\nDesign guide RNAs for CRISPR-Cas9 knockout.\n\n```python\nfrom Bio.Seq import Seq\nimport re\n\ndef design_crispr_guides(target_seq, pam='NGG', guide_length=20, top_n=10):\n    \"\"\"Design CRISPR sgRNAs for SpCas9.\n\n    Args:\n        target_seq: target gene\u002Fregion sequence (string)\n        pam: PAM sequence ('NGG' for SpCas9)\n        guide_length: guide RNA length (typically 20)\n        top_n: number of top guides to return\n    \"\"\"\n    seq = str(target_seq).upper()\n    rc_seq = str(Seq(seq).reverse_complement())\n\n    guides = []\n\n    # Search forward strand for PAM (NGG at 3' end of target)\n    for i in range(len(seq) - guide_length - len(pam) + 1):\n        pam_site = seq[i + guide_length:i + guide_length + 3]\n        if re.match(pam.replace('N', '.'), pam_site):\n            guide_seq = seq[i:i + guide_length]\n            score = score_guide(guide_seq)\n            guides.append({\n                'sequence': guide_seq,\n                'pam': pam_site,\n                'position': i,\n                'strand': '+',\n                'score': score,\n                'full_target': guide_seq + pam_site\n            })\n\n    # Search reverse strand\n    for i in range(len(rc_seq) - guide_length - len(pam) + 1):\n        pam_site = rc_seq[i + guide_length:i + guide_length + 3]\n        if re.match(pam.replace('N', '.'), pam_site):\n            guide_seq = rc_seq[i:i + guide_length]\n            score = score_guide(guide_seq)\n            guides.append({\n                'sequence': guide_seq,\n                'pam': pam_site,\n                'position': len(seq) - i - guide_length,\n                'strand': '-',\n                'score': score,\n                'full_target': guide_seq + pam_site\n            })\n\n    # Sort by score (higher is better)\n    guides.sort(key=lambda x: x['score'], reverse=True)\n\n    print(f\"Found {len(guides)} potential guide RNAs\")\n    print(f\"\\nTop {min(top_n, len(guides))} guides:\")\n    for i, g in enumerate(guides[:top_n]):\n        print(f\"  {i+1}. {g['sequence']} {g['pam']} \"\n              f\"(strand={g['strand']}, pos={g['position']}, score={g['score']:.2f})\")\n\n    return guides[:top_n]\n\ndef score_guide(guide_seq):\n    \"\"\"Heuristic guide scoring based on known design rules.\"\"\"\n    score = 50.0  # Base score\n\n    # GC content (40-70% preferred)\n    gc = (guide_seq.count('G') + guide_seq.count('C')) \u002F len(guide_seq)\n    if 0.4 \u003C= gc \u003C= 0.7:\n        score += 10\n    elif gc \u003C 0.3 or gc > 0.8:\n        score -= 20\n\n    # Avoid poly-T (>4 consecutive T = pol III terminator)\n    if 'TTTT' in guide_seq:\n        score -= 30\n\n    # G at position 20 (adjacent to PAM) preferred\n    if guide_seq[-1] == 'G':\n        score += 5\n\n    # Avoid GG at position 19-20 (can cause off-target)\n    if guide_seq[-2:] == 'GG':\n        score -= 5\n\n    # Self-complementarity penalty\n    rc = str(Seq(guide_seq).reverse_complement())\n    matches = sum(a == b for a, b in zip(guide_seq, rc))\n    if matches > 12:\n        score -= 15\n\n    return max(score, 0)\n```\n\n### 7. Plasmid Annotation\n\nIdentify and annotate features in plasmid sequences.\n\n```python\nfrom Bio.Seq import Seq\nfrom Bio.SeqRecord import SeqRecord\nfrom Bio.SeqFeature import SeqFeature, FeatureLocation\nfrom Bio import SeqIO\nfrom Bio.Restriction import RestrictionBatch, Analysis, CommOnly\n\ndef annotate_plasmid(sequence, name='plasmid'):\n    \"\"\"Annotate plasmid features and restriction sites.\n\n    Args:\n        sequence: plasmid DNA sequence (string)\n        name: plasmid name\n    \"\"\"\n    seq = Seq(sequence)\n    record = SeqRecord(seq, id=name, name=name,\n                       description=f'{name} annotated plasmid',\n                       annotations={'molecule_type': 'DNA', 'topology': 'circular'})\n\n    # Common feature patterns\n    feature_patterns = {\n        'T7_promoter': 'TAATACGACTCACTATAG',\n        'lac_operator': 'AATTGTGAGCGGATAACAATT',\n        'RBS_consensus': 'AAGGAG',\n        'T7_terminator': 'CTAGCATAACCCCTTGGGGCCTCTAAACGGGTCTTGAGG',\n        'ColE1_origin': 'CCTGTTTTGGCGGATGAGAGAAG',\n    }\n\n    for feat_name, pattern in feature_patterns.items():\n        pos = str(seq).find(pattern)\n        if pos >= 0:\n            record.features.append(SeqFeature(\n                FeatureLocation(pos, pos + len(pattern)),\n                type='misc_feature',\n                qualifiers={'label': feat_name}\n            ))\n            print(f\"Found {feat_name} at position {pos}\")\n\n    # Find ORFs (>300bp)\n    for strand, nuc in [(1, seq), (-1, seq.reverse_complement())]:\n        for frame in range(3):\n            trans = str(nuc[frame:].translate())\n            start = 0\n            while True:\n                start = trans.find('M', start)\n                if start == -1:\n                    break\n                stop = trans.find('*', start)\n                if stop == -1:\n                    stop = len(trans)\n                orf_len = (stop - start) * 3\n\n                if orf_len >= 300:\n                    if strand == 1:\n                        dna_start = frame + start * 3\n                        dna_end = frame + stop * 3 + 3\n                    else:\n                        dna_end = len(seq) - frame - start * 3\n                        dna_start = len(seq) - frame - stop * 3 - 3\n\n                    record.features.append(SeqFeature(\n                        FeatureLocation(min(dna_start, dna_end),\n                                       max(dna_start, dna_end), strand),\n                        type='CDS',\n                        qualifiers={'label': f'ORF_{orf_len}bp'}\n                    ))\n                    print(f\"ORF: {orf_len}bp at {dna_start}-{dna_end} (strand {'+' if strand==1 else '-'})\")\n\n                start = stop + 1\n\n    # Map restriction sites\n    rb = CommOnly\n    analysis = Analysis(rb, seq, linear=False)\n    unique_sites = {str(enz): sites for enz, sites in analysis.full().items()\n                    if len(sites) == 1}\n\n    print(f\"\\nUnique restriction sites: {len(unique_sites)}\")\n    for enz, sites in sorted(unique_sites.items()):\n        print(f\"  {enz}: {sites[0]}\")\n\n    return record\n\n# Write annotated plasmid\n# record = annotate_plasmid(plasmid_seq, name='pMyPlasmid')\n# SeqIO.write(record, 'pMyPlasmid.gb', 'genbank')\n```\n\n## Typical Workflows\n\n### Workflow 1: Design PCR Primers and Predict Amplicon\n\n```python\nfrom Bio.Seq import Seq\n\ntemplate = Seq(\"ATCGATCGATCGATCGATCGATCGATCG\" * 50)  # 1400 bp template\nfwd = Seq(\"ATCGATCGATCGATCGATCG\")\nrev = Seq(\"CGATCGATCGATCGATCGAT\")\n\namplicons = simulate_pcr(template, fwd, rev)\nif amplicons:\n    print(f\"Amplicon size: {amplicons[0]['length']} bp\")\n```\n\n### Workflow 2: Plan Golden Gate Assembly with 4 Parts\n\n```python\nparts = [\n    {'name': 'J23100_promoter', 'sequence': 'TTGACGGCTAGCTCAGTCCTAGGTACAGTGCTAGC'},\n    {'name': 'B0034_RBS', 'sequence': 'AAAGAGGAGAAA'},\n    {'name': 'GFP', 'sequence': 'ATGGTGAGCAAGGGCGAGGAG' + 'NNN' * 230 + 'TAA'},\n    {'name': 'B0015_terminator', 'sequence': 'CCAGGCATCAAATAAAACGAAAGGCTCAGTCGAAAG'},\n]\nassembly = design_golden_gate(parts)\n```\n\n### Workflow 3: Design CRISPR Knockout sgRNAs\n\n```python\n# Target: exon 3 of a gene\ntarget_exon = \"ATGCGATCGATCGATCGATCGATCGAGGCGATCGATCGATCGATCGATCGATCGATCGATCG\"\nguides = design_crispr_guides(target_exon, pam='NGG', top_n=5)\n```\n\n## Best Practices\n\n1. **Primer design** — aim for Tm within 2 C between forward and reverse primers; 40-60% GC content; avoid 3' complementarity\n2. **Golden Gate** — verify 4bp overhangs are unique and non-palindromic; use standardized overhang sets from published studies\n3. **Gibson assembly** — use 20-40bp overlaps; ensure fragments have similar Tm at overlap junctions; minimum 2 fragments\n4. **CRISPR guides** — avoid poly-T (>4 T) which terminates U6\u002FH1 transcription; prefer guides in early exons; validate against off-target databases\n5. **Restriction digestion** — always check both orientations; verify compatible cohesive ends for ligation; methylation sensitivity can block cutting\n6. **Plasmid annotation** — verify ORFs are in correct reading frame; check for cryptic promoters; map all unique restriction sites for future cloning\n\n## Troubleshooting\n\n**Problem:** PCR simulation finds no amplicons\n**Solution:** Check primer orientation (forward should match sense strand 5'->3'). Increase `max_mismatches`. Verify template contains the target region.\n\n**Problem:** Restriction enzyme doesn't cut expected site\n**Solution:** Check for CpG methylation sensitivity (dam\u002Fdcm methylation). Verify site isn't in a modified context. Use `isoschizomers()` to find alternatives.\n\n**Problem:** Golden Gate assembly produces wrong product\n**Solution:** Verify all overhangs are unique. Check enzyme is BsaI (not BsmBI) — different cut distances. Ensure parts are in correct orientation.\n\n**Problem:** primer3 returns no primers\n**Solution:** Relax constraints: widen Tm range, increase max size, lower GC requirement. Ensure target region has sufficient flanking sequence.\n\n**Problem:** CRISPR guide design returns few candidates\n**Solution:** Expand search region (use full gene, not just one exon). Try alternative PAM sequences (NAG for relaxed SpCas9). Consider Cas12a (TTTV PAM) for AT-rich regions.\n\n## Resources\n\n- [Biopython Restriction Module](https:\u002F\u002Fbiopython.org\u002Fwiki\u002FRestriction)\n- [primer3-py Documentation](https:\u002F\u002Flibnano.github.io\u002Fprimer3-py\u002F)\n- [CRISPR Design Rules](https:\u002F\u002Fdoi.org\u002F10.1038\u002Fnbt.2647)\n- [Golden Gate Assembly (Engler et al.)](https:\u002F\u002Fdoi.org\u002F10.1371\u002Fjournal.pone.0003647)\n- [Gibson Assembly (Gibson et al.)](https:\u002F\u002Fdoi.org\u002F10.1038\u002Fnmeth.1318)\n",{"name":5,"license":54,"category":39,"metadata":55,"description":7},"MIT license",{"skill-author":56},"InkVell Inc.","main","4aa39efd1cdab0b4657ecee16c92a92011a5b10f","openscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub","https:\u002F\u002Fgithub.com\u002Ffadrienne","2026-10-28 00:43:09",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add fadrienne\u002FMyGitHub --skill molecular-cloning",{"tool":69,"command":70},"bunx","bunx skills add fadrienne\u002FMyGitHub --skill molecular-cloning",{"tool":72,"command":73},"pnpm","pnpm dlx skills add fadrienne\u002FMyGitHub --skill molecular-cloning","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002FSKILL.md",true,[77,83,87,91,95],{"path":78,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":81,"sourceHtmlUrl":82},"scripts\u002Fdesign_crispr.py","SCRIPT","脚本",10295,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002Fscripts\u002Fdesign_crispr.py",{"path":84,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":85,"sourceHtmlUrl":86},"scripts\u002Fdesign_primers.py",11276,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002Fscripts\u002Fdesign_primers.py",{"path":88,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":89,"sourceHtmlUrl":90},"scripts\u002Fgolden_gate.py",12757,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002Fscripts\u002Fgolden_gate.py",{"path":92,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":93,"sourceHtmlUrl":94},"scripts\u002Frestriction_digest.py",9020,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002Fscripts\u002Frestriction_digest.py",{"path":96,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":97,"sourceHtmlUrl":98},"scripts\u002Fsimulate_pcr.py",7420,"https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fopenscience\u002Fbackend\u002Fcli\u002Fskills\u002Fbiology\u002Fmolecular-cloning\u002Fscripts\u002Fsimulate_pcr.py",[100,127,152,184,211,238],{"skillNo":101,"name":102,"nameZh":6,"description":103,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":109,"publishedAt":49},"01M7167B28PK20HP7R7ZED2DY0","statistical-power","Sample size calculation, power analysis, and effect size conversion for scientific studies. Use BEFORE data collection (a priori) to determine required N, or after (post-hoc) to compute achieved power. Covers parametric tests (t-test, ANOVA, chi-square, proportions, correlation, regression), simulation-based power for complex\u002Fclustered\u002Fnested designs, and power curves. Use this skill when someone asks 'how many samples do I need', 'what is my power', 'what effect size can I detect', or any variant. Pairs with \u002Fexperimental-design (choose design first, then compute power) and \u002Fstatistical-analysis (analyze data after collection).","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fstatistical-power\u002FSKILL.md",[106],{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[110,111,112,113,114,115,41,116,117,118,119,45,120,121,122,123,124,125,44,126],"power","statistical power","effect","scipy","regression","choose","uv","when","Bash","collection","calculation","ANOVA","conversion","analyze","t-test","chi-square","sample",{"skillNo":128,"name":129,"nameZh":6,"description":130,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":131,"categories":132,"keywords":136,"publishedAt":49},"01M71677EBCM8EPCE9BZCK8505","statistical-analysis","Guided statistical analysis with test selection and reporting. Use when you need help choosing appropriate tests for your data, assumption checking, power analysis, and APA-formatted results. Best for academic research reporting, test selection guidance. For implementing specific models programmatically use statsmodels.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fstatistical-analysis\u002FSKILL.md",[133],{"categoryNo":134,"categoryName":135,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[45,137,110,138,139,140,117,141,142,143,37,144,43,145,146,147,148,149,150,151],"statistical analysis","academic research","implementing","selection","you","reporting","data","tests","with","test","research","results","statsmodels","models","help",{"skillNo":153,"name":154,"nameZh":6,"description":155,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":156,"categories":157,"keywords":165,"publishedAt":49},"01M71673R93XAHFH81DBNVNG7H","scientific-writing","Core skill for the deep research and writing tool. Write scientific manuscripts in full paragraphs (never bullet points). Use two-stage process with (1) section outlines with key points using research-lookup then (2) convert to flowing prose. IMRAD structure, citations (APA\u002FAMA\u002FVancouver), figures\u002Ftables, reporting guidelines (CONSORT\u002FSTROBE\u002FPRISMA), for research papers and journal submissions.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fscientific-writing\u002FSKILL.md",[158,161,162],{"categoryNo":159,"categoryName":160,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000018","写作与文案",{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":163,"categoryName":164,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000036","内容创作者",[166,167,168,169,170,171,172,173,174,175,118,176,177,178,179,180,181,182,142,183],"writing","scientific","scientific writing","Citations","deep","deep research","never","papers","journal","false","api","prisma","structure","openrouter","Outlines","core skill","read","features",{"skillNo":185,"name":186,"nameZh":6,"description":187,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":188,"categories":189,"keywords":194,"publishedAt":49},"01M7166ZPKXBF4EBPHVTJPQBB1","scientific-visualization","Meta-skill for publication-ready figures. Use when creating journal submission figures requiring multi-panel layouts, significance annotations, error bars, colorblind-safe palettes, and specific journal formatting (Nature, Science, Cell). Orchestrates matplotlib\u002Fseaborn\u002Fplotly with publication styles. For quick exploration use seaborn or plotly directly.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fscientific-visualization\u002FSKILL.md",[190,193],{"categoryNo":191,"categoryName":192,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000013","分析与可视化",{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},[195,167,196,197,198,199,200,201,202,174,117,203,204,205,206,207,208,209,37,210],"visualization","scientific visualization","error","ready","quick","exploration","meta-skill","Meta","safe","plotly","annotations","formatting","Publication","figures","panel","submission",{"skillNo":212,"name":213,"nameZh":6,"description":214,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":215,"categories":216,"keywords":223,"publishedAt":49},"01M7166VXJWQSSC3RQZP60WBGR","research-code","Debug, profile, review, and restructure Python research and analysis code. Use when analysis scripts crash, produce wrong results, run too slowly, or need a correctness review. Covers: reading tracebacks and diagnosing root causes, hypothesis-driven debugging, reviewing code for common statistical\u002Fnumerical errors, profiling data pipelines, improving reproducibility (seeds, environments, determinism), and structuring analysis scripts for sharing. Distinct from \u002Fexploratory-data-analysis (which understands data) and \u002Fstatistical-analysis (which chooses and runs tests) — this skill focuses on the code itself.","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fresearch-code\u002FSKILL.md",[217,220],{"categoryNo":218,"categoryName":219,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000021","资料检索与研究",{"categoryNo":221,"categoryName":222,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师",[224,225,147,226,227,228,229,116,230,117,118,45,231,232,233,234,235,236,182,237],"code","research code","which","memory","data-analysis","errors","debugging","common","review","data pipelines","run","scripts","line","write",{"skillNo":239,"name":240,"nameZh":6,"description":241,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":242,"licenseFileUrl":6,"sourceHtmlUrl":243,"categories":244,"keywords":251,"publishedAt":49},"01M7166CF5HSR7SVZYZFWTDX55","markdown-mermaid-writing","Comprehensive markdown and Mermaid diagram writing skill. Use when creating any scientific document, report, analysis, or visualization. Establishes text-based diagrams as the default documentation standard with full style guides (markdown + mermaid), 24 diagram type references, and 9 document templates.","Apache-2.0","https:\u002F\u002Fgithub.com\u002Ffadrienne\u002FMyGitHub\u002Fblob\u002Fmain\u002Fscientific-agent-skills\u002Fskills\u002Fmarkdown-mermaid-writing\u002FSKILL.md",[245,248,249,250],{"categoryNo":246,"categoryName":247,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000002","文档处理",{"categoryNo":159,"categoryName":160,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":107,"categoryName":108,"taxonomyType":21,"taxonomyTypeDesc":22},{"categoryNo":163,"categoryName":164,"taxonomyType":26,"taxonomyTypeDesc":27},[166,252,253,254,255,256,195,257,258,117,118,45,259,260,261,262,263,264,167,182],"markdown mermaid writing","mermaid","markdown","community","diagrams","project","default","team","guides","text","documentation","references","diagram"]