Endometriosis is an inflammatory disease characterized by the endometrial-like tissue growth outside of the uterine cavity. This ectopic growth leads to hormonal imbalances, systemic inflammation, and debilitating pain. This condition recurs in 40–50% of patients within 5 years of surgery, and it is mostly because of minimal residual disease (resulting from incomplete excision, invisible peritoneal lesions, or impaired immune clearance of remaining endometriotic cells as a result of surgical transient immunosuppression) [2].
Although it affects 10–15% of reproductive age women, there is currently no cure and current clinical management is limited to hormonal suppression, pain control and surgical excision [3]. Consequently, there is a critical need for non-invasive, targeted therapies that can modulate the immune response and minimize recurrence rates without compromising the patient’s reproductive health.
Solution
I propose a single intraperitoneal dose of lipid nanoparticles administered at the close of laparoscopic surgery. In residual endometriotic cells overexpressing lncH19, a toehold switch activates expression of a bioPROTAC, an anti-STAT3 monobody fused to a VHL-based E3 ligase recruitment domain, driving targeted proteasomal degradation of STAT3, a key driver of endometriotic cell survival, invasion, and inflammation. Normal peritoneal tissue remains unaffected because the goal is to eliminate what the scalpel misses, before it has the chance to establish the disease again.
How does a toehold switch works?
A toehold switch is a synthetic riboregulator that controls gene expression as a programmable gatekeeper ensuring that the treatment is only “turned on” when it detects the specific marker for endometriosis.
The Guarded State (OFF): To keep healthy cells safe, the switch is designed to fold into a hairpin structure that physically hides the “start” signals (the RBS and start codon) needed to make the protein, the cell’s machinery—the ribosome—cannot see them, so the treatment (bioPROTAC) is never produced.
The Identification (The Toehold): The switch has a small, exposed “tail” called a toehold which is specially engineered to recognize and bind to lncH19, which is only overexpressed in the diseased cells I’m targeting.
The Activation (ON): When lncH19 finds the toehold, it attaches to it and initiates a process called strand displacement. Essentially, it “unzips” the hairpin, forcing the RNA to unfold
The Result: Once the structure is open, the start signals that were previously hidden are finally exposed. The ribosome can now easily latch onto the RNA and begin building the bioPROTAC protein to eliminate the residual endometriotic cells
Adapted from Choi, Lee & Kim (2022), Int. J. Mol. Sci., 23(8), 4265. CC BY 4.0.
How does a bioPROTAC works?
BioPROTAC (biological Proteolysis-Targeting Chimeras) are molecules capable of degrading target proteins by marking them for proteasomal degradation through the addition of polyubiquitin chains [4].
The mechanism functions by recruitment of an E3 ligase complex in close proximity of a target protein, which leads to target ubiquitination and subsequent proteasomal degradation [4].
The advantage of targeted protein degradation over traditional methods is that it can act on “undruggable” proteins, those lacking deep binding pockets or active sites that small-molecule inhibitors typically require.
Why STAT3?
STAT3 acts as a central regulatory axis in the endometriosis microenvironment, integrating inflammatory signals from IL-6 and IL-22 that drive ectopic cell survival, invasion, and chronic inflammation. Preclinical studies show that inhibiting STAT3 significantly reduces lesion area and modulates the signaling pathways necessary for disease persistence. By using a monobody-based bioPROTAC to degrade STAT3, we can permanently eliminate the protein in residual cells that escape surgical excision, effectively disrupting the molecular networks responsible for recurrence
RESULTS
For the toehold switch the trigger has to come from a región of lncH19 that’s accesible. So I scanned the 2315 nucleotide transcript with NUPACK, computed unpaired probabilities and ranked them by GC content, no premature stops, etc.
The winner was position 1,734
Then I built the switch following Green 2014 geometry and validated in NUPACK as well.
On the left, the switch alone:
It folds into a hairpin that hides the start codon
You’ll notice that the toehold isn’t free as it should, it’s base-pairs with part of the linker. That’s something I need to improve but it doesnt break the system
On the right, when the trigger appears: it binds the toehold and displaces the hairpin, exposing the RBS and start codon.
bioPROTAC translation begins.
The energy difference between these two states is 35 kcal/mol - this strong driving force overcomes the residual pairing.
At first, I couldn’t find a tool for building toehold switches and the gold standar (NUPACK) needed a paid subscription. I wanted to choose the best trigger that didn’t formed a secundary structure and that was unpaired, so I used RNAfold to see the dot-bracket notation and see positional entropy. Then, I realized that I could use the NUPACK python software to choose the trigger and build the toehold switch. This is my code:
rna=dna.replace('T','U')print(f"RNA length: {len(rna)} nt")print(f"First 100 nt: {rna[:100]}")# Save for the next notebookswithopen('h19_rna.txt','w')asf:f.write(rna)print("\n✓ Saved to h19_rna.txt")
02_accessibility_scan
fromnupackimportStrand,Model,pairsimportnumpyasnp# Load the sequence we saved in step 1withopen('h19_rna.txt')asf:h19=f.read().strip()print(f"H19 loaded: {len(h19)} nt")# Thermodynamic model: RNA at 37 °C (cell-free temperature)model=Model(material='rna',celsius=37)# Create the NUPACK Strand objecth19_strand=Strand(h19,name='h19')print("✓ Ready to compute pairing probabilities")
N=len(h19)# In NUPACK 4, P[i,i] = probability that base i is UNPAIREDprob_unpaired=np.diag(P_matrix)print(f"prob_unpaired statistics:")print(f" Min: {prob_unpaired.min():.3f}")print(f" Max: {prob_unpaired.max():.3f}")print(f" Mean: {prob_unpaired.mean():.3f}")# Sanity check: each row should sum to ~1row_sum=P_matrix[100,:].sum()
window=30# For each start position, average prob_unpaired over the next 30 ntwindow_score=np.array([prob_unpaired[i:i+window].mean()foriinrange(N-window+1)])print(f"Total windows evaluated: {len(window_score)}")print(f"Max score: {window_score.max():.3f}")print(f"Mean score: {window_score.mean():.3f}")# Keep the top 30 candidatestop_indices=np.argsort(window_score)[::-1][:30]print(f"\n{'Pos':>5} | {'Sequence (30 nt)':<32} | {'Score':>5}")print("-"*55)foridxintop_indices:fragment=h19[idx:idx+window]score=window_score[idx]print(f"{idx:>5} | {fragment} | {score:.3f}")
withopen('candidates.txt','w')asf:foridxintop_indices:fragment=h19[idx:idx+window]score=window_score[idx]f.write(f"{idx}\t{fragment}\t{score:.4f}\n")print("✓ Saved 30 candidates to candidates.txt")
03_filter_candidates
defgc_content(seq):"""Fraction of G+C in the sequence"""return(seq.count('G')+seq.count('C'))/len(seq)defhas_homopolymer(seq,length=5):"""True if there are 5 or more identical bases in a row"""forbasein'AUGC':ifbase*lengthinseq:returnTruereturnFalsedefhas_stop_in_critical_zone(trigger):"""
When the switch opens, the 9 nt after the AUG are trigger[9:18]
read 5'→3'. Those 9 nt are translated as 3 consecutive codons.
None of them can be a stop: UAA, UAG, UGA.
"""stops={'UAA','UAG','UGA'}region=trigger[9:18]codons=[region[0:3],region[3:6],region[6:9]]returnany(cinstopsforcincodons),codonsdefhas_internal_aug(seq):"""An internal AUG could initiate spurious translation"""return'AUG'inseq
final_list=passedifpassedelsepassed_relaxedifnotfinal_list:print("No candidate passes. We'll need to adjust further.")else:# The winner is the one with the highest scorepos,seq,score=final_list[0]print("="*60)print("CHOSEN TRIGGER")print("="*60)print(f"Position in H19: {pos}")print(f"Sequence (30 nt): {seq}")print(f"Accessibility score: {score:.3f}")print(f"GC content: {gc_content(seq):.2f}")withopen('chosen_trigger.txt','w')asf:f.write(seq)print("\nFunctional breakdown:")print(f" trigger[0:18] (pairs with stem): {seq[0:18]}")print(f" trigger[18:30] (pairs with toehold): {seq[18:30]}")print(f" trigger[9:18] (stop-free zone): {seq[9:18]}")print("\n✓ Saved to chosen_trigger.txt")
04_build_switch
defrevcomp(seq):"""Reverse complement of RNA"""comp={'A':'U','U':'A','G':'C','C':'G'}return''.join(comp[b]forbinreversed(seq))withopen('chosen_trigger.txt')asf:trigger=f.read().strip()assertlen(trigger)==30,f"Trigger must be 30 nt, got {len(trigger)}"print(f"Trigger loaded: {trigger} ({len(trigger)} nt)")
# Toehold a (12 nt): RC of the last 12 nt of the triggera_toehold=revcomp(trigger[18:30])# Ascending stem b (18 nt): RC of the first 18 nt of the triggerb_asc=revcomp(trigger[0:18])# Loop (11 nt) with strong Shine-Dalgarno RBS (AGGAG embedded)# From Green 2014 switch #2loop="AACAGAGGAGA"assertlen(loop)==11# Desc_top (6 nt before AUG): pairs with the last 6 nt of b_ascdesc_top=revcomp(b_asc[-6:])# AUG bulge (3 nt unpaired)aug="AUG"# Desc_bot (9 nt after AUG): pairs with the first 9 nt of b_ascdesc_bot=revcomp(b_asc[:9])# Check that desc_bot has NO stop codons (read 5'→3', in frame with AUG)desc_codons=[desc_bot[0:3],desc_bot[3:6],desc_bot[6:9]]stops={'UAA','UAG','UGA'}assertnotany(cinstopsforcindesc_codons), \
f"STOP in desc_bot! Codons: {desc_codons}. Need to pick another candidate."print(f"✓ desc_bot stop-free. Codons: {desc_codons}")# Green 2014: encodes N-L-A-A-A-Q-Klinker="AACCUGGCGGCAGCGCAAAAG"assertlen(linker)==21# Check that linker has no stops (in frame with AUG)linker_codons=[linker[i:i+3]foriinrange(0,21,3)]assertnotany(cinstopsforcinlinker_codons),f"STOP in linker: {linker_codons}"print(f"✓ linker stop-free. Codons: {linker_codons}")print("\n"+"="*60)print("SWITCH PARTS")print("="*60)print(f" a_toehold (12 nt): {a_toehold}")print(f" b_asc (18 nt): {b_asc}")print(f" loop+RBS (11 nt): {loop}")print(f" desc_top (6 nt): {desc_top}")print(f" AUG (3 nt): {aug}")print(f" desc_bot (9 nt): {desc_bot}")print(f" linker (21 nt): {linker}")
# Regulatory part of the switchregulatory_switch=a_toehold+b_asc+loop+desc_top+aug+desc_bot+linkerprint(f"Regulatory switch: {len(regulatory_switch)} nt")print(f"Expected: 12 + 18 + 11 + 6 + 3 + 9 + 21 = {12+18+11+6+3+9+21}")print(f"\nFull sequence (regulatory):\n{regulatory_switch}")withopen('regulatory_switch.txt','w')asf:f.write(regulatory_switch)print(f"\n✓ Saved to regulatory_switch.txt")
initial_orf=aug+desc_bot+linkerprint(f"Initial ORF (without reporter, {len(initial_orf)} nt):")print(f" {initial_orf}")print(f"\nTranslated codons:")codons=[initial_orf[i:i+3]foriinrange(0,len(initial_orf),3)]codon_table={'AUG':'M','AAA':'K','AAG':'K','AAU':'N','AAC':'N','ACA':'T','ACC':'T','ACG':'T','ACU':'T','AGA':'R','AGG':'R','AGU':'S','AGC':'S','AUA':'I','AUC':'I','AUU':'I','CAA':'Q','CAG':'Q','CAU':'H','CAC':'H','CCA':'P','CCC':'P','CCG':'P','CCU':'P','CGA':'R','CGG':'R','CGU':'R','CGC':'R','CUA':'L','CUG':'L','CUU':'L','CUC':'L','GAA':'E','GAG':'E','GAU':'D','GAC':'D','GCA':'A','GCC':'A','GCG':'A','GCU':'A','GGA':'G','GGG':'G','GGU':'G','GGC':'G','GUA':'V','GUG':'V','GUU':'V','GUC':'V','UAA':'*','UAG':'*','UGA':'*','UAU':'Y','UAC':'Y','UCA':'S','UCC':'S','UCG':'S','UCU':'S','UGG':'W','UGU':'C','UGC':'C','UUA':'L','UUG':'L','UUU':'F','UUC':'F',}aas=[]forcincodons:aa=codon_table.get(c,'?')aas.append(aa)print(f" {c} → {aa}")peptide=''.join(aas)print(f"\nN-terminal added to sfGFP: {peptide}")if'*'inpeptide:print("STOP CODON PRESENT! This will truncate translation.")else:print("No stops. The ribosome will read through to sfGFP without issue."
print("="*70)print("TEST 1: MFE structure of the switch ALONE (no trigger)")print("="*70)switch_result=mfe(strands=[switch_seq],model=model)switch_structure=str(switch_result[0].structure)switch_energy=switch_result[0].energyprint(f"\nSequence: {switch_seq}")print(f"Structure: {switch_structure}")print(f"ΔG = {switch_energy:.2f} kcal/mol")# Annotate functional regions under the structure# The switch has: G(1) + toehold(12) + asc_stem(18) + loop(11) + desc_top(6) + AUG(3) + desc_bot(9) + linker(21)G_extra=1N_a=12N_b=18N_loop=11N_desc_top=6N_AUG=3N_desc_bot=9N_linker=21regions=[]regions.append(('G',0,G_extra))regions.append(('toehold',G_extra,G_extra+N_a))regions.append(('asc_stem',G_extra+N_a,G_extra+N_a+N_b))regions.append(('loop+RBS',G_extra+N_a+N_b,G_extra+N_a+N_b+N_loop))regions.append(('desc_top',G_extra+N_a+N_b+N_loop,G_extra+N_a+N_b+N_loop+N_desc_top))regions.append(('AUG',G_extra+N_a+N_b+N_loop+N_desc_top,G_extra+N_a+N_b+N_loop+N_desc_top+N_AUG))regions.append(('desc_bot',G_extra+N_a+N_b+N_loop+N_desc_top+N_AUG,G_extra+N_a+N_b+N_loop+N_desc_top+N_AUG+N_desc_bot))regions.append(('linker',G_extra+N_a+N_b+N_loop+N_desc_top+N_AUG+N_desc_bot,len(switch_seq)))print("\nRegion breakdown:")forname,start,endinregions:region_struct=switch_structure[start:end]region_seq=switch_seq[start:end]n_paired=sum(1forcinregion_structifcin'()')n_unpaired=region_struct.count('.')print(f" {name:>10} ({start:>2}-{end-1:>2}): {region_seq}")print(f" {'':>10}{'':>2}{region_struct} → {n_paired} paired, {n_unpaired} unpaired")
print("="*70)print("TEST 2: MFE structure of the SWITCH + TRIGGER complex")print("="*70)duplex_result=mfe(strands=[switch_seq,trigger_seq],model=model)duplex_structure=str(duplex_result[0].structure)duplex_energy=duplex_result[0].energyprint(f"\nDuplex structure:")print(f" {duplex_structure}")print(f"\nΔG duplex = {duplex_energy:.2f} kcal/mol")print(f"ΔG switch alone = {switch_energy:.2f} kcal/mol")print(f"ΔΔG (duplex - switch alone) = {duplex_energy-switch_energy:.2f} kcal/mol")print(f" (the more negative, the stronger the drive to open the switch)")
All Aim 1 objectives are done: trigger identified, switch tested, a validated STAT3 binder and the constructs ready for synthesis by Twist.
The next step is to synthesize the constructs through Ginkgo, validate activation in a cell-free System, and then move into endometriotic cell lines.
Long-term vision is breaking the cycle of regrowth and repeated surgeries without affecting normal tisssue.
Bibliography
[1] M. Sahni and E. S. Day, “Nanotechnologies for the detection and treatment of endometriosis,” Front. Biomater. Sci., vol. 2, Nov. 2023, doi: 10.3389/fbiom.2023.1279358.
[2] Masferrer-Ferragutcasas, C., Delgado-Gil, R. & Colas, E. Rethinking endometriosis recurrence: from clinical challenge to biological opportunity. npj Womens Health 4, 4 (2026). https://doi.org/10.1038/s44294-026-00128-9
[4] D. Winkelvoß et al., “Molecular features defining the efficiency of bioPROTACs,” Commun. Biol., vol. 8, no. 1, p. 946, Jun. 2025, doi: 10.1038/s42003-025-08352-w.