A hands-on workshop in analyzing real genomics data with an LLM coding agent | Day 0 Orientation
Welcome. This folder is your workspace. Over the workshop you'll use an LLM agent (Claude Code) to explore a real, published dataset: how gene expression changed in E. coli after tens of thousands of generations of laboratory evolution. You'll start by reproducing one published figure panel (a task with a known right answer), then plan and run an analysis of your own — and keep a journal of how you worked with the agent along the way.
You do not need to be a microbiologist, and you do not need to know ribosome
profiling. If either is new to you, that's expected — start with the primer in
orientation/00_background.md.
The E. coli Long-Term Evolution Experiment (LTEE) has propagated 12 populations of bacteria from a single ancestor since 1988 — tens of thousands of generations of evolution in a simple, constant lab environment. Favate et al. (2022) took evolved clones from 11 of those populations and measured, genome-wide, how much of each gene's mRNA is made (RNA-seq) and how much of each mRNA is being translated into protein (Ribo-seq / ribosome profiling), and compared each evolved line back to its ancestor. The central question this dataset lets you ask:
After 50,000 generations of adaptation, how have E. coli's gene-expression programs changed — and are those changes surprisingly parallel across populations that evolved independently?
The full paper is in orientation/ (Favate et al. 2022,
eLife 11:e81979). Data provenance is in data/data_dictionary.md.
There's more than one way in. Pick the track that matches what you already know — you can always climb further later. All tracks use the same data folder and the same agent.
If you know RNA-seq, start here. Work only with the mRNA-level data and ask how transcription changed during evolution: which genes go up/down, how big the changes are, and whether independent populations changed the same genes.
- Data:
table_s2_fold_changes.csv(filterseqtype == "rna"),all_data.csv(ds_*_rnacolumns),table_s1_read_counts.csv(RNA libraries). - This is the home of the warmup (below) and of reproducing Figure 1.
Optional / a step up — introduces Ribo-seq. Bring in the ribosome-profiling data and ask a question you can't answer from RNA alone: when a gene's mRNA level changes, does the amount of translation change to match, or independently? This is "translation efficiency."
- Data:
table_s7_riborex_results.csv(Riborex),all_data.csv(rr_*andds_*_ribocolumns),table_s1(both assays). - Corresponds to Figure 3 of the paper (panels A, B, D are reproducible here).
Bring your own question. For example, a pathway-level analysis — do whole metabolic
pathways shift in parallel? — using the *_pathways/*_reactions annotation columns in
all_data.csv. (This is the spirit of Figure 4; note its exact inputs aren't shipped, so
this is your own analysis, not a reproduction.) Or link expression changes to the deletions and
duplications in del_per_line.csv / dups_per_line.csv. Or something else entirely.
See orientation/02_guiding_questions.md for concrete,
ranked questions in each track.
- Get oriented (Day 0). Set up the agent (
orientation/01_getting_started.md), read the biology primer if you need it (00_background.md), and skimdata/data_dictionary.md. Write your first journal entry. - Warmup — reproduce Figure 1B. A deterministic task with a known answer:
orientation/03_quick_start.md. Journal which prompts you used, how close your version looks to the original, and what surprised you. - Plan. Choose a further analysis (narrow → open-ended → self-directed) from the guiding
questions and fill in
analysis/analysis_plan_template.md. - Execute it with the agent, journaling as you go.
- Reflect. Close with an end-of-session journal entry.
The warmup has a right answer; your own analysis does not. Both matter — one calibrates your trust in the agent, the other is where you actually learn to work with it.
workshop/
├── README.md ← you are here
├── data/
│ ├── metadata.csv ← experimental design table (start here)
│ ├── data_dictionary.md ← what every data file is + gotchas
│ ├── table_s1_read_counts.csv ← raw counts + TPM (RNA-seq AND Ribo-seq)
│ ├── table_s2_fold_changes.csv ← differential expression, DESeq2 (Track 1)
│ ├── table_s7_riborex_results.csv ← translation efficiency, Riborex (Track 2)
│ ├── all_data.csv ← pre-merged master table (all of the above + annotation)
│ ├── biocyc_df.csv ← gene names, products, pathways
│ ├── del_per_line.csv / dups_per_line.csv ← deletions / duplications per line
│ ├── araM_barcodes.tsv / araP_barcodes.tsv ← demultiplexing barcodes (reference)
│ └── schematic_figure.png ← the experiment schematic (Figure 1A)
├── orientation/
│ ├── 00_background.md ← biology primer (read first if new to microbes/Ribo-seq)
│ ├── 01_getting_started.md ← set up Claude Code + choosing effort
│ ├── 02_guiding_questions.md ← entry points + ranked questions to explore
│ ├── 03_quick_start.md ← your first task — reproduce Figure 1B, do this first
│ ├── 04_example_prompts.md ← copy-paste prompts to try with the agent
│ └── elife-81979-v2.pdf ← the paper
├── analysis/
│ └── analysis_plan_template.md ← template for your chosen analysis
└── journal/
└── my_journal.md ← your reflection log — edit throughout
Whatever you conclude, two traps sit under this dataset — name them in your analysis:
- An mRNA change is not a protein change. RNA-seq measures transcript abundance; making more mRNA does not guarantee more protein. Ribosome profiling exists precisely because the two can diverge — though in this study they mostly don't, and that's a key finding, not an assumption you get to make for free.
- "The same gene changed in many lines" has more than one explanation. It can mean parallel selection — but it can also reflect shared ancestry, or the fact that mutator lines accumulate changes far faster. A parallelism claim has to reckon with these.
Your analysis doesn't need to solve these — but it should acknowledge them.
LTEE (Long-Term Evolution Experiment) — 12 E. coli populations evolved from one ancestor
by daily transfer since 1988; a landmark study of evolution in real time.
Generation — one cell doubling; the populations grow ~6.6 generations/day, reaching ~50,000
over the study.
Serial transfer / daily passage — moving a small sample of yesterday's culture into fresh
medium each day; the mechanism of long-term propagation.
Ara+ / Ara− — a neutral genetic marker (arabinose use) that distinguishes the two ancestral
strains and their descendant lines; not itself under strong selection.
Ancestor — the starting strains, REL606 (Ara−) and REL607 (Ara+); the baseline every
evolved line is compared against.
Evolved line / clone — a single clone sampled from an evolved population (e.g. Ara-1).
Parallel (convergent) evolution — independent populations arriving at similar changes; a
central theme here.
Mutator / hypermutator — a line that lost DNA-repair fidelity and accumulates mutations
orders of magnitude faster; 5 of the 11 lines here are mutators.
RNA-seq — sequencing to measure mRNA abundance per gene (transcription).
Ribo-seq / ribosome profiling — sequencing only the mRNA fragments protected by ribosomes,
to measure how much each mRNA is being translated (translation).
Ribosome footprint — the short mRNA fragment a translating ribosome protects; the unit
Ribo-seq counts.
Translation efficiency (TE) — translation (Ribo-seq) relative to mRNA level (RNA-seq); a
change in TE means translation shifted beyond what the mRNA change explains.
TPM (transcripts per million) — a within-sample normalized abundance; good for composition
and correlation, not for cross-sample count statistics.
Read count / estimated counts — the (kallisto-estimated) number of reads for a gene; the
input to count-based differential-expression tests.
log2 fold change — log₂(evolved / ancestor); +1 = doubling, −1 = halving.
DESeq2 — the standard tool used here for differential expression from counts.
Riborex — the tool used here to detect translation-efficiency changes from paired RNA-seq +
Ribo-seq.
padj / FDR / q-value — a multiple-testing-corrected p-value; genes here are called
significant at padj ≤ 0.01.
target_id — the gene/feature identifier; a gene name (alaT) or a locus tag (ECB_00001).
ERCC spike-in — synthetic RNAs added in known amounts for calibration (gene_type == "ERCC");
usually filtered out.