Working through several studies on different machines? Start each one with
aree start-study, which claims it on its own branch. See parallel_study_runs.md.
This walks through registering a new public (or demo) dataset in AREE. A "study" is registration-time metadata describing what was done, not what was found — see design.md for why studies, comparisons, and evidence records are kept as separate tiers.
For one study, copy the template:
cp registry/studies/_TEMPLATE.yaml registry/studies/YOUR_STUDY_ID.yamlFor registering several studies at once, start from
registry/studies/_batch_template.csv, which has one row per comparison
(the same fields as the YAML template, flattened). The batch CSV is useful
for bulk entry but every study still needs to pass the same schema validation
as a YAML record — there is no separate, looser batch schema.
The full field set is defined in schemas/study.schema.json. At minimum you
must provide:
study_id— unique, must match the filename stem, pattern^[A-Za-z0-9_-]+$citation,species,genome_assemblyassay_type— a list of one or more terms fromregistry/controlled_vocabularies/assay_types.yaml(rnaseq,methylation,proteomics,metabolomics,microarray,qpcr,genotyping)analysis_mode—raw_reanalysisorprocessed_results_harmonization(see raw_vs_processed.md)comparisons— at least one (see below)data_availability—raw_data_available,processed_data_available,status(available|restricted|embargoed|unavailable)provenance—registered_by,date_registered(ISO date)
Other useful fields: accessions (DOI/BioProject/GEO/SRA/ENA/ProteomeXchange/
other — all nullable), strain_or_population, annotation_version,
platform, qc_status, analysis_status, quality_flags, limitations.
If the study is synthetic/demo data rather than a real dataset, set
simulated: true, put the YAML in registry/demo_studies/ instead of
registry/studies/, and say so plainly in the citation and limitations
fields (see any file in registry/demo_studies/GIGAS_*.yaml for the convention
used by the demo set — they are all prefixed [SIMULATED]). Validation fails
for a study in the wrong directory. Demo studies are test fixtures for code
paths real data does not reach yet; add one only for that reason.
A single study can report more than one phenotype or stressor — for example
registry/demo_studies/GIGAS_HEAT01.yaml reports both an acute heat-shock
comparison (phenotype survival) and a chronic heat comparison (phenotype
growth_under_stress) from the same study. Rather than forcing one label per
study, phenotype/stressor/tissue/life-stage fields live at the comparison
level:
comparisons:
- comparison_id: "acute_heat_vs_control"
tissue: "gill"
life_stage: "adult"
stressor_original: "Acute heat shock, 34C for 2h, versus 20C ambient seawater"
stressor_standardized: "temperature"
exposure_intensity: "34C"
exposure_duration: "2h"
exposure_timing: "acute, single exposure"
control_condition: "20C ambient seawater, matched handling"
treatment_condition: "34C for 2h then sampled"
phenotype: "survival"
phenotype_direction: "decrease"
phenotype_unit: "percent_survival"
resilience_classification: "resilience"
contrast_type: "exposure_response"
sample_size: 24
biological_replicates: 3
results_file: "data/demo/rnaseq/GIGAS_HEAT01_acute_heat_vs_control_dge_demo.tsv"Each comparison needs its own comparison_id (unique within the study),
tissue and life_stage (from the controlled vocabularies), a
stressor_original (exact free text from the source — never discard this)
alongside a stressor_standardized ontology term, a phenotype term, a
phenotype_direction, a resilience_classification, a contrast_type, and
sample-size fields. contrast_type says whether the arms are a treatment and
its control (exposure_response) or groups that differ in resilience, and if
so whether they were sampled at baseline or under the challenge; see
contrast_types.md. If a study has both kinds, choose
meta_analysis_primary separately within each contrast type.
results_file points at the processed results table for that comparison when
analysis_mode is processed_results_harmonization (or when raw-mode output
has already been produced and staged, as in the demo).
Add as many comparisons entries as the source study actually reports. Do
not collapse two different stressors or two different phenotypes into one
comparison — see resilience_vs_exposure.md for
why this distinction matters downstream.
aree validate-study registry/studies/YOUR_STUDY_ID.yamlThis checks the file against schemas/study.schema.json and cross-checks
controlled-vocabulary fields (phenotype, stressor, tissue, life stage, assay
type, mapping/quality terms where applicable). Fix any reported errors before
proceeding; warnings are non-fatal but worth reading.
aree register-study registry/studies/YOUR_STUDY_ID.yamlThis re-validates and appends (or, with --update, overwrites) a row in
registry/study_registry.csv. That index is generated and gitignored, so it
never appears in a PR; aree build-registry rebuilds it from every YAML.
Registering a study_id that already exists
without --update fails with a duplicate-study error rather than silently
overwriting.
Confirm it landed:
aree list-studiesIf the study is processed_results_harmonization mode — the common case for
public data — its results arrive as a supplementary spreadsheet or CSV that
does not match the column contract aree harmonize expects. Do not reshape
it by hand. Write an intake config instead, so the step from publication to
evidence is a command someone else can re-run and verify.
Put the downloaded artifact under data/studies/YOUR_STUDY_ID/_source/ and
write data/studies/YOUR_STUDY_ID/intake.yaml:
study_id: YOUR_STUDY_ID
assay: rnaseq
source:
description: Supplementary Table S2 (differential expression, treated vs control)
url: https://doi.org/...
license: CC BY 4.0
citation: Author A, Author B (2025). Title. Journal 1:23. https://doi.org/...
local_copy: data/studies/YOUR_STUDY_ID/_source/supp_table_s2.xlsx
sha256: <shasum -a 256 of that file>
output_dir: data/studies/YOUR_STUDY_ID
provenance_file: data/studies/YOUR_STUDY_ID/intake_provenance.json
conversions:
- output_file: YOUR_STUDY_ID_treated_vs_control_dge.tsv
source_sheet: DEGs # spreadsheets only; omit for CSV/TSV
column_map: # AREE column: source column
gene_id: Gene
log2FoldChange: log2FC
lfcSE: lfcSE
pvalue: pvalue
padj: FDR
# Quote every note: an unquoted string containing ": " parses as a YAML mapping.
transformation_notes:
- "Anything a reader would need to know to interpret the derived table."Then:
aree intake-supplementary data/studies/YOUR_STUDY_ID/intake.yamlRules the intake step enforces, and why:
- Map only the columns the source actually reports. Unmapped AREE columns
are emitted empty. If the publication reports no standard error, leave
lfcSEunmapped — an empty column correctly prevents inverse-variance pooling, whereas a fabricated one silently corrupts every meta-analysis the study enters. Nothing is ever imputed. - Do not touch identifiers. Decoration like
gene-LOC105331241|LOC105331241is preserved verbatim; identifier_mapping.md describes how it is resolved later.feature_id_originalmust remain exactly what the authors published. - Do not filter beyond what the authors did. If the published table is
already significance-filtered, say so in
transformation_notes— it is a study limitation, not something to correct here. - The source
sha256is verified before every conversion. If the publisher reissues the file, the intake fails rather than silently re-deriving results from a different version. Resolve that deliberately.
Supported sources are .xls, .xlsx, .xlsm (needs pip install -e ".[intake]"),
.csv, .tsv, and .txt. Verify at any later time — and in CI — with:
aree intake-supplementary data/studies/YOUR_STUDY_ID/intake.yaml --checkwhich regenerates into a temporary directory and compares checksums against the committed files and provenance, without modifying anything.
If your source is genuinely not a differential-expression table (a methylation region table, a protein abundance matrix, a metabolite feature table), the intake converter does not yet cover it — see raw_vs_processed.md for the expected input shapes and prepare those tables by a documented script of your own for now.
For a raw_reanalysis study, aree fetch-samplesheet (see
first_raw_reanalysis.md) writes
fastq_manifest.tsv alongside the sample sheet, and the two always list the
same runs:
- Each run gets exactly one manifest row per mate: 1 for
SINGLE, 2 forPAIRED. Any other count is an error naming the runs. One exception: when a paired run's ENA FASTQ also includes an unpairedRUN.fastq.gzbesideRUN_1/RUN_2, that file is left out and listed underunpaired_files_droppedinena_provenance.json. - URLs come from ENA's generated FASTQ (
fastq_ftp) where it exists. Some public runs have none, and only the submitter's own files (submitted_ftp). When those are all FASTQ, they are used instead, with the submitter's MD5s and sizes. The manifest'ssourcecolumn (fastq_ftporsubmitted_ftp) andsubmitted_ftp_runsinena_provenance.jsonrecord which runs these are. PRJEB105019's ERR15996548 is one example. Submitted files keep their own names (e.g...._DNA_R1.fastq.gz), so download them byrun_accessionandmate, not by file name. - A run with neither (no ENA FASTQ, and submitted files that are BAM, CRAM or missing) is an error naming the run, not a silent omission. Resolve it with the submitter or ENA before going further. Do not hand-edit the manifest.
Before downloading a raw_reanalysis study, pre-screen its replicates on
the first ~1 M reads of each library:
python scripts/prescreen_replicates.py --source ncbi \
--samplesheet data/studies/STUDY_ID/samplesheet.tsv \
--manifest data/studies/STUDY_ID/fastq_manifest.tsv \
--salmon-index data/reference/GCF_963853765.1/salmon_index \
--level CONTROL_LEVEL --level TREATMENT_LEVELIt quantifies only those reads and applies the same dispersion statistic as
the full check below, at about 1 GB and 10 minutes per study instead of tens
of GB. --source ncbi uses fastq-dump -X (sra-tools, in
environment.yml) and is usually much faster than ENA. Use --source ena
to screen the exact files the manifest would download. It was calibrated on
two studies with known outcomes (1 M reads per library; full-depth values in
brackets):
| Study | Pre-screen | Full depth | Verdict |
|---|---|---|---|
WANG2024_HEAT_GILL |
0.0038 / 0.0029 | (0.0030 / 0.0009) | fail |
LI2022_HEAT_PLOIDY d_0 / d_f |
0.0191 / 0.0218 | (0.0139 / 0.0143) | pass |
The subsample reads a little high, so a borderline study can pass the pre-screen and still fail at full depth. A pass is permission to download, not a substitute for the full check. A fail means: do not download the study as is, and record why in candidate_studies.md.
Check after the workflow runs and before harmonizing that its replicates are independent animals:
python scripts/check_replicate_dispersion.py \
--samplesheet data/studies/STUDY_ID/samplesheet.tsv \
--salmon-dir RESULTS_DIR/COMPARISON_ID/rnaseq/salmonIt exits non-zero if any group's median gene dispersion falls below 0.005.
Real M. gigas biological replicates sit around 0.03–0.05. A group far below
that is behaving like technical replicates, and its DESeq2 standard errors
are too small to pool. IOCAS2022_OA_ENERGY and WANG2024_HEAT_GILL failed
this check even though the deposited metadata labelled every library a
biological replicate; see candidate_studies.md. If a
study fails, set qc_status: failed, record the evidence, and do not
harmonize it. For individually sequenced animals, comparing allele fractions
at expressed SNPs can show why a group failed (one RNA source vs distinct
animals). data/studies/WANG2024_HEAT_GILL/genotype_check/ is a worked
example. It cannot tell pools of larvae from one cross apart, since those
share parental genotypes.
Once a study is registered and has passed QC, harmonize its results into the shared evidence table — see raw_vs_processed.md for which mode applies and the command to run. From there it becomes eligible for meta-analysis and candidate scoring.