Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Analyze codon usage, calculate CAI (Codon Adaptation Index), and examine synonymous codon bias using Biopython. Use when analyzing coding sequences for expression optimization or evolutionary analysis.
.claude/skills/bio-codon-usage/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 155% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 101% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 118% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 114% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 120% | 0% |
<!--
#
#
-->
Analyze codon usage patterns and calculate codon adaptation metrics using Biopython.
pythonfrom Bio.Seq import Seq from Bio.SeqUtils import GC123 from Bio.SeqUtils.CodonUsage import CodonAdaptationIndex from Bio.Data import CodonTable from collections import Counter
pythonfrom collections import Counter def count_codons(seq): seq_str = str(seq).upper() codons = [seq_str[i:i+3] for i in range(0, len(seq_str) - 2, 3)] return Counter(codons) seq = Seq('ATGCGATCGATCGATCGTAA') codon_counts = count_codons(seq)
pythondef codon_frequencies(seq): counts = count_codons(seq) total = sum(counts.values()) return {codon: count / total for codon, count in counts.items()}
pythonfrom Bio.SeqUtils.CodonUsage import CodonAdaptationIndex # Create CAI calculator with reference set cai = CodonAdaptationIndex() # Generate index from highly expressed genes cai.generate_index('highly_expressed_genes.fasta') # Calculate CAI for a sequence seq = Seq('ATGCGATCGATCGATCGTAA') cai_value = cai.cai_for_gene(str(seq)) print(f'CAI: {cai_value:.3f}') # Range 0-1, higher = better adapted
pythonfrom Bio.SeqUtils.CodonUsage import CodonAdaptationIndex cai = CodonAdaptationIndex() # Set custom index (relative adaptiveness for each codon) custom_index = { 'TTT': 0.5, 'TTC': 1.0, # Phe 'TTA': 0.1, 'TTG': 0.5, 'CTT': 0.3, 'CTC': 1.0, 'CTA': 0.1, 'CTG': 1.0, # Leu # ... define all 64 codons } cai.set_cai_index(custom_index)
RSCU = (observed codon frequency) / (expected frequency if all synonymous codons were used equally)
pythonfrom Bio.Data import CodonTable def calculate_rscu(seq, table_id=1): codon_table = CodonTable.unambiguous_dna_by_id[table_id] counts = count_codons(seq) # Group codons by amino acid aa_to_codons = {} for codon in counts: if codon in codon_table.stop_codons: continue try: aa = codon_table.forward_table[codon] aa_to_codons.setdefault(aa, []).append(codon) except KeyError: continue # Calculate RSCU for each codon rscu = {} for aa, codons in aa_to_codons.items(): total = sum(counts.get(c, 0) for c in codons) n_synonymous = len(codons) expected = total / n_synonymous if n_synonymous > 0 else 0 for codon in codons: observed = counts.get(codon, 0) rscu[codon] = observed / expected if expected > 0 else 0 return rscu
pythondef find_rare_codons(seq, threshold=0.1): freq = codon_frequencies(seq) return {codon: f for codon, f in freq.items() if f < threshold}
pythonfrom Bio.SeqUtils import GC123 seq = Seq('ATGCGATCGATCGATCGATCGATCGATCGTAA') gc_total, gc_pos1, gc_pos2, gc_pos3 = GC123(seq) print(f'Total GC: {gc_total:.1f}%') print(f'1st position GC: {gc_pos1:.1f}%') print(f'2nd position GC: {gc_pos2:.1f}%') print(f'3rd position GC: {gc_pos3:.1f}% (wobble position)')
pythonfrom Bio.Data import CodonTable # Get standard table std_table = CodonTable.unambiguous_dna_by_id[1] # List all available tables for id, table in CodonTable.unambiguous_dna_by_id.items(): print(f'{id}: {table.names[0]}')
| ID | Name | Organism | |----|------|----------| | 1 | Standard | Most organisms | | 2 | Vertebrate Mitochondrial | Human, mouse mito | | 4 | Mold Mitochondrial | Fungi, protozoa mito | | 5 | Invertebrate Mitochondrial | Insects, worms mito | | 11 | Bacterial/Plastid | E. coli, chloroplasts |
pythontable = CodonTable.unambiguous_dna_by_id[1] print(f'Start codons: {table.start_codons}') print(f'Stop codons: {table.stop_codons}') # Forward table: codon -> amino acid print(table.forward_table['ATG']) # 'M' # Back table: amino acid -> list of codons back_table = {} for codon, aa in table.forward_table.items(): back_table.setdefault(aa, []).append(codon) print(f'Leucine codons: {back_table["L"]}')
pythondef codon_usage_report(seq, table_id=1): from Bio.Data import CodonTable table = CodonTable.unambiguous_dna_by_id[table_id] counts = count_codons(seq) total = sum(counts.values()) # Group by amino acid aa_groups = {} for codon, aa in table.forward_table.items(): aa_groups.setdefault(aa, []).append(codon) report = {} for aa, codons in sorted(aa_groups.items()): aa_total = sum(counts.get(c, 0) for c in codons) report[aa] = { 'total': aa_total, 'codons': {c: {'count': counts.get(c, 0), 'freq': counts.get(c, 0) / aa_total if aa_total > 0 else 0} for c in codons} } return report
pythondef compare_codon_usage(seq1, seq2): freq1 = codon_frequencies(seq1) freq2 = codon_frequencies(seq2) all_codons = set(freq1.keys()) | set(freq2.keys()) comparison = {} for codon in sorted(all_codons): f1, f2 = freq1.get(codon, 0), freq2.get(codon, 0) comparison[codon] = {'seq1': f1, 'seq2': f2, 'diff': f1 - f2} return comparison
pythondef optimize_codons(protein_seq, preferred_codons): '''Replace codons with preferred synonymous codons''' optimized = [] for aa in str(protein_seq): if aa in preferred_codons: optimized.append(preferred_codons[aa]) else: optimized.append('NNN') # Unknown return Seq(''.join(optimized)) # E. coli preferred codons ecoli_preferred = { 'A': 'GCG', 'R': 'CGT', 'N': 'AAC', 'D': 'GAT', 'C': 'TGC', 'Q': 'CAG', 'E': 'GAA', 'G': 'GGT', 'H': 'CAC', 'I': 'ATT', 'L': 'CTG', 'K': 'AAA', 'M': 'ATG', 'F': 'TTC', 'P': 'CCG', 'S': 'TCT', 'T': 'ACC', 'W': 'TGG', 'Y': 'TAC', 'V': 'GTT', }
pythonfrom Bio import SeqIO def analyze_fasta_codon_usage(filename): all_counts = Counter() for record in SeqIO.parse(filename, 'fasta'): all_counts.update(count_codons(record.seq)) total = sum(all_counts.values()) return {codon: count / total for codon, count in all_counts.items()}
A measure of codon bias (lower = more biased, range 20-61):
pythonimport math def effective_nc(seq, table_id=1): from Bio.Data import CodonTable table = CodonTable.unambiguous_dna_by_id[table_id] counts = count_codons(seq) # Group by degeneracy class aa_groups = {} for codon, aa in table.forward_table.items(): aa_groups.setdefault(aa, []).append(codon) # Calculate F for each amino acid nc_sum = 0 for aa, codons in aa_groups.items(): n = sum(counts.get(c, 0) for c in codons) if n <= 1: continue pi_sq_sum = sum((counts.get(c, 0) / n) ** 2 for c in codons) F = (n * pi_sq_sum - 1) / (n - 1) nc_sum += 1 / F if F > 0 else len(codons) return nc_sum if nc_sum > 0 else 61
| Metric | Range | Interpretation | |--------|-------|----------------| | CAI | 0-1 | Higher = better adapted to host | | RSCU | 0-N | 1.0 = no bias, >1 = overused, <1 = underused | | Nc | 20-61 | Lower = more biased | | GC3 | 0-100% | GC at wobble position |
| Error | Cause | Solution | |-------|-------|----------| | KeyError | Non-standard codon | Handle N-containing codons | | Wrong counts | Sequence not in frame | Ensure length is multiple of 3 | | No index set | Called CAI without training | Call generate_index() first |
Need to analyze codon usage?
├── Count codon frequencies?
│ └── Use Counter on 3-mers
├── Calculate adaptation to host?
│ └── Use CodonAdaptationIndex (CAI)
├── Identify synonymous bias?
│ └── Calculate RSCU
├── Check wobble position bias?
│ └── Use GC123()
├── Measure overall bias?
│ └── Calculate Nc (effective number of codons)
└── Optimize for expression?
└── Replace with preferred synonymous codons<!-- 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-01 | fail→pass | 7,852 | 5,713 | -27% | 1 | 1 | 0% | 1,691 | 4,305 | +155% | 0 | 0 | — |
case-02 | fail→pass | 11,893 | 10,344 | -13% | 1 | 1 | 0% | 2,541 | 5,119 | +101% | 0 | 0 | — |
case-03 | fail→pass | 11,810 | 6,779 | -43% | 1 | 1 | 0% | 2,030 | 4,427 | +118% | 0 | 0 | — |
case-04 | fail→pass | 9,062 | 5,206 | -43% | 1 | 1 | 0% | 1,897 | 4,053 | +114% | 0 | 0 | — |
case-05 | fail→pass | 11,848 | 11,372 | -4% | 1 | 1 | 0% | 2,508 | 5,528 | +120% | 0 | 0 | — |
case-10 | pass→pass | 15,865 | 7,556 | -52% | 1 | 1 | 0% | 3,227 | 4,717 | +46% | 0 | 0 | — |
case-15 | pass→pass | 10,678 | 5,980 | -44% | 1 | 1 | 0% | 2,278 | 4,264 | +87% | 0 | 0 | — |
case-21 | pass→pass | 9,551 | 6,650 | -30% | 1 | 1 | 0% | 1,972 | 4,443 | +125% | 0 | 0 | — |
case-22 | pass→pass | 17,852 | 7,791 | -56% | 1 | 1 | 0% | 984 | 4,602 | +368% | 0 | 0 | — |
case-06 | fail→pass | 6,563 | 4,866 | -26% | 1 | 1 | 0% | 1,323 | 4,018 | +204% | 0 | 0 | — |
case-07 | pass→pass | 11,061 | 7,287 | -34% | 1 | 1 | 0% | 2,246 | 4,456 | +98% | 0 | 0 | — |
case-08 | pass→pass | 15,040 | 6,631 | -56% | 1 | 1 | 0% | 2,955 | 4,268 | +44% | 0 | 0 | — |
case-09 | fail→fail | 21,170 | 14,727 | -30% | 1 | 1 | 0% | 4,975 | 6,094 | +22% | 0 | 0 | — |
case-11 | pass→pass | 10,106 | 6,269 | -38% | 1 | 1 | 0% | 2,165 | 4,312 | +99% | 0 | 0 | — |
case-12 | pass→pass | 9,984 | 7,134 | -29% | 1 | 1 | 0% | 2,005 | 4,463 | +123% | 0 | 0 | — |
case-13 | pass→pass | 6,200 | 2,681 | -57% | 1 | 1 | 0% | 1,288 | 3,468 | +169% | 0 | 0 | — |
case-14 | pass→pass | 5,957 | 3,007 | -50% | 1 | 1 | 0% | 1,182 | 3,626 | +207% | 0 | 0 | — |
case-16 | pass→pass | 6,643 | 5,555 | -16% | 1 | 1 | 0% | 1,405 | 4,091 | +191% | 0 | 0 | — |
case-17 | pass→pass | 6,671 | 3,785 | -43% | 1 | 1 | 0% | 1,364 | 3,696 | +171% | 0 | 0 | — |
case-18 | pass→pass | 5,571 | 2,963 | -47% | 1 | 1 | 0% | 1,084 | 3,547 | +227% | 0 | 0 | — |
case-19 | fail→pass | 11,249 | 7,968 | -29% | 1 | 1 | 0% | 2,056 | 4,618 | +125% | 0 | 0 | — |
case-20 | pass→pass | 9,369 | 9,158 | -2% | 1 | 1 | 0% | 1,813 | 4,722 | +160% | 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 +32 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/26/2026 | +26% |
Other measured skills in the registry, with their headline benchmark lift.