differential_expression
Compare an experimental condition vs control (e.g.
Skill by RCHENLAB
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/rchenlab-differential-expression
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/differential-expression
What's inside
- Skill name
differential_expression- Description
- Compare an experimental condition vs control (e.g. KO vs WT) per cell type, with pathway interpretation (v2 — pseudobulk when replicates exist, and honest about it when they don't)
- License
- MIT
- Instructions
- 294 lines in SKILL.md · view on GitHub
Agent Skills spec issues
- name: only lowercase letters, digits and single hyphens allowed
Files (2)
- PROTOCOL.md
- SKILL.md
SKILL.md (first lines)
## Read this before planning step 3
A condition contrast is a statement about the CONDITION, so the unit of replication is the
SAMPLE (donor / animal / library), never the cell. Cells from one donor are not independent
observations of that donor's condition. A Wilcoxon test over cells treats them as if they
were, and the p-values are then anti-conservative by orders of magnitude.
This is measured, not theoretical. On a synthetic 4-donor design where **exactly 1 of 400
genes** was made different between the arms:
| test | called significant (padj<0.05) |
|---|---|
| `run_de`, Wilcoxon over cells | **310 of 400 (78%)** |
| `run_pseudobulk_de`, over donors | 0 (and it ranked the true gene #1) |
So: **use `run_pseudobulk_de` for a condition contrast whenever the data has ≥2 samples per
arm.** `run_de` at its default (`reference="rest"`) is for markers — one cluster versus the rest
within a sample — which is what it is valid for. `run_de` can also run a real cell-level contrast
(`reference=<control level>`, `stratify_by=<cell-type column>`), but that inherits the
pseudoreplication above: use it only when there are no replicates, and label it as an exploratory
ranking rather than differential expression.
## Read this before planning the contrast, too: SEQUENCING DEPTH
Replication is not the only way a condition contrast goes wrong. If one arm was sequenced deeper
per cell, EVERY comparison inherits it: a gene detected in more cells because more molecules were
sampled scores as up-regulated, and whole pathways of abundant transcripts — translation,
ribosome, RNA metabolism — move together in the deeper arm. Log-normalisation does NOT remove
this; it rescales totals, while detection is a function of how many molecules were drawn.
The dataset profile gives you the median counts per cell for each arm. **Compare them before you
plan.** If they differ by more than ~1.3x, the plan MUST contain a depth-matched check, because
with one library per arm there is no replication that could separate depth from biology.
`run_depth_matched_de` is that check as a deterministic tool: within each cell type it down-samples
the deeper arm quantile by quantile until the per-cell UMI distributions match (never up-sampling),
re-runs the SAME contrast, and Spearman-correlates the original ranking against the matched one,
separately per direction. High rho = not an artefact. Rho near zero = depth decided the ranking.
NEGATIVE rho = the ranking inverts once depth is equal, which is the strongest evidence that the
finding must not be reported as biology.
Name that tool. Do NOT plan this as free-form `run_code`: it existed only as a step brief before,
and three different models wrote three different wrong versions — one plan asked the executor to
"correlate per-gene logFC against the between-arm median nCount_RNA", which is not computable (a
per-gene vector against a single scalar), and the step failed on every attempt.
Condition-comparison protocol. Use when the goal is to find the genes that change between two
experimental GROUPS of cells — disease vs control, knockout vs wild-type, treated vs untreated —
and interpret them. NOT for assigning cell-type labels (use `celltype_annotation` for that).
## Figuring out WHAT to compare from the data (do this even with a vague/empty question)
The user may not know the biology, or may just say "analyze this dataset". You do NOT need them to
spell it out — the dataset's own metadata defines the experiment. Read the DATASET PROFILE (the
obs columns + their category values are given to you at planning time) and infer:
1. **The condition/group column.** Look in obs for a low-cardinality (usually 2-level) column that
names an experimental variable: `sampleid`, `condition`, `genotype`, `treatment`, `group`,
`orig.ident`, `disease`, etc. Its two values ARE the comparison (e.g. `sampleid=[DDX41, WT]`
→ compare DDX41 vs WT). The dataset / file name often confirms intent (e.g. `*_DEG` = they
want differential expression).
2. **The reference (control) group.** Pick the level whose name looks like the baseline —
`WT`, `wild-type`, `control`, `ctrl`, `untreated`, `vehicle`, `DMSO`, `normal`, `sham`. The
OTHER level is the condition of interest. State which you chose; if it is genuinely unclear,
ask ONE clarify question in plan mode rather than guessing.
3. **The cell-type stratification.** If obs already has a cell-type / cluster label column
(`majorclass`, `celltype`, a predicted-label column), REUSE it — run the comparison
SEPARATELY WITHIN EACH cell type. Do NOT re-cluster or re-annotate from scratch. Only if no
label column exists do you `run_clustering` first and compare across clusters.
So the default study for a dataset with a 2-group condition column + existing cell-type labels is:
**"condition vs control differential expression within each major cell type, then pathway
enrichment on the changed genes"** — plan that without waiting for the user to describe it.
## Ordered plan
0. **Establish what the matrix IS, and the rules, before touching it** (`run_code`) — read-only,
and BEFORE QC. Two outputs, written as tables the later steps read back:
* *Provenance.* **Not for a 10x Cell Ranger input whose data profile already rules on it**
(its `.h5` matrices were read at upload: integer UMI counts, checked against Cell Ranger's
`metrics_summary.csv`). Cite that ruling; do NOT plan a `run_code` step to re-derive it, and
write the decision rule below into the plan's first step instead. Otherwise: inspect `X`,
`.raw`, `layers`, value ranges, sparsity and integer-ness, and check whether matrix-derived
totals reproduce any stored `nCount`/`nFeature` fields. A
published object often arrives already normalized and log1p'd: normalizing it again has NO
symptom — every tool succeeds, every figure renders, and every number after it is wrong. So
rule from the NUMBERS, and say which way you ruled:
- **Counts.** Every value non-negative and integer-valued to tolerance, the row sums
reproduce a stored total-count field (`nCount_RNA`, `total_counts`), the per-row non-zero
counts reproduce the stored detected-feature field, and no `layers`/`.raw` entry carries a
different scale. **That is sufficient — proceed.** An empty `uns` and a missing
transformation history are a LIMITATION TO REPORT, not a stop condition: a matrix that
reproduces its own stored QC fields exactly is not made unusable by the absence of a
written record, and stopping there forfeits the whole quantitative analysis over a
provenance note.
- **Not counts.** Any negative or non-integer value, row sums that do not reproduce the
stored totals, or a differently-scaled representation present. Then say so and drop the
count-dependent steps — never recover counts by exponentiating, rounding, or renaming.
Count-based tests (`run_pseudobulk_de`, `run_depth_matched_de`) need the first ruling; say
which one you applied and which representation supports which operation.
* *The decision rule.* Name the primary estimand, the unit of replication, the minimum cells
per arm per cell type, and the effect-size gate — and write them down NOW, while no DE
result is visible. A cutoff chosen after seeing which one flatters the answer is not a
cutoff. Say what happens when a gate FAILS: that stratum is reported unsupported, not
relaxed until it passes. Most of these numbers already have defaults in the Parameters
table below — this step is about COMMITTING to them (and to any change, with its reason)
before the results can influence the choice.
1. **QC** (`run_scanpy_qc` for one matrix; `run_cellqc` INSTEAD when the data profile says the input is a folder of 10x Cell Ranger outputs (raw + filtered matrices): it corrects ambient RNA, removes doublets and writes the same normalised checkpoint): per-cell metrics, filter, normalize + log1p (+ HVG). Report counts.
Honor any QC columns already in the data (e.g. `percent.mt`, doublet calls).
2. **Define the comparison** from the profile (above): name the condition column, the two groups,
the reference group, and the cell-type column you will stratify by. If labels already exist,
skip clustering.
3. **Per-cell-type differential expression — choose the test from the DESIGN, not from habit.**
First find the SAMPLE column (donor / animal / library / `orig.ident`), which is usually a
different column from the condition. Then:
- **≥2 samples per arm → `run_pseudobulk_de`** with `sample_key`, `condition_key`, and
`group_key` = the cell-type column. It aggregates counts per sample, tests across
samples, and returns `skipped_groups` for any cell type without enough samples. ReportFrom RCHENLAB/AiScientist, MIT.
More from RCHENLAB/AiScientist
- 0.563score
variant_annotation
RCHENLAB
Interpret a VCF's variants (germline/somatic, WGS/WES) — gene + functional consequence (Ensembl VEP), ClinVar pathogenicity, gnomAD frequency, deleteriousness…
SkillAFreshness: AClaude Code +9 - 0.563score
perturbation_analysis
RCHENLAB
Analyze a pooled CRISPR / Perturb-seq screen — rank which perturbations change the transcriptome, then per-perturbation DE vs the non-targeting control
SkillAFreshness: AClaude Code +9 - 0.560score
annotate_clusters_by_markers_v2
RCHENLAB
Assign a cell-type label to each cluster from a curated marker panel, using signature scoring for a first pass and RAW marker expression to make the final call.
SkillAFreshness: AClaude Code +9 - 0.560score
scgpt_annotation
RCHENLAB
scGPT foundation-model per-cell annotation for a .h5ad — transfers reference cell-type labels + calibrated confidence to every cell, AND independently…
SkillAFreshness: AClaude Code +9 - 0.557score
atlas_disease_genes
RCHENLAB
Reference template — prioritize disease-associated genes by combining condition differential expression with a precalculated cell-type atlas.
SkillAFreshness: AClaude Code +9 - 0.557score
clinical_variant_prioritization
RCHENLAB
Reference template — assign a research-triage priority tier (pathogenic → VUS → benign) per variant from ClinVar + gnomAD AF (disease-model thresholds) +…
SkillAFreshness: AClaude Code +9 - 0.557score
celltype_annotation
RCHENLAB
Single-cell cell-type annotation + report (v2 — stability-selected resolution, raw-expression label confirmation, preranked GSEA)
SkillAFreshness: AClaude Code +9 - 0.557score
normalize_vcf
RCHENLAB
Reference template — normalize a VCF (split multiallelic, atomize MNPs, left-align indels) with bcftools norm before annotation or ClinVar/gnomAD matching.
SkillAFreshness: AClaude Code +9 - 0.557score
score_signature
RCHENLAB
Reference template — score every cell for one or more gene signatures with scanpy `sc.tl.score_genes` (signature mean minus a matched random control set)…
SkillAFreshness: AClaude Code +9 - 0.554score
perturbation_edistance
RCHENLAB
Reference template — rank perturbations by E-distance to control (which guides actually did something).
SkillAFreshness: AClaude Code +9 - 0.554score
condition_by_celltype
RCHENLAB
Reference template — condition-vs-control differential expression, STRATIFIED BY CELL TYPE.
SkillAFreshness: AClaude Code +9 - 0.549score
perturbation_de_vs_control
RCHENLAB
Reference template — per-perturbation differential expression vs a shared non-targeting control.
SkillAFreshness: AClaude Code +9
Signals
- Stars
- 0
- Forks
- 3
- Open issues
- 16
- Last commit (this folder)
- Oct 13, 2026 (16 days ago)
- Last release
- Oct 19, 2026 (10 days ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- Repository
- github.com/RCHENLAB/AiScientist
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from RCHENLAB
- 0.563score
perturbation_analysis
RCHENLAB
Analyze a pooled CRISPR / Perturb-seq screen — rank which perturbations change the transcriptome, then per-perturbation DE vs the non-targeting control
SkillAFreshness: AClaude Code +9 - 0.563score
variant_annotation
RCHENLAB
Interpret a VCF's variants (germline/somatic, WGS/WES) — gene + functional consequence (Ensembl VEP), ClinVar pathogenicity, gnomAD frequency, deleteriousness…
SkillAFreshness: AClaude Code +9 - 0.560score
annotate_clusters_by_markers_v2
RCHENLAB
Assign a cell-type label to each cluster from a curated marker panel, using signature scoring for a first pass and RAW marker expression to make the final call.
SkillAFreshness: AClaude Code +9 - 0.560score
scgpt_annotation
RCHENLAB
scGPT foundation-model per-cell annotation for a .h5ad — transfers reference cell-type labels + calibrated confidence to every cell, AND independently…
SkillAFreshness: AClaude Code +9 - 0.557score
clinical_variant_prioritization
RCHENLAB
Reference template — assign a research-triage priority tier (pathogenic → VUS → benign) per variant from ClinVar + gnomAD AF (disease-model thresholds) +…
SkillAFreshness: AClaude Code +9 - 0.557score
atlas_disease_genes
RCHENLAB
Reference template — prioritize disease-associated genes by combining condition differential expression with a precalculated cell-type atlas.
SkillAFreshness: AClaude Code +9
Cite this page
differential_expression skill. Agent Mart. https://agentmart.dev/skills/rchenlab-differential-expression (last updated 2026-10-24)