executing-plans
executing-plans
Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available
gwas-sumstats-harmonizeHarmonize GWAS summary statistics from any common format (GWAS-Catalog SSF, PLINK 1.9/2, REGENIE, METAL, BOLT, SAIGE) to one canonical table (SNP CHR BP EA NEA EAF BETA SE P N): column detection, BETA/SE/P derivation, QC with drop reasons, and allele alignment to a reference panel, run as a Snakemake workflow.
Independent GitHub snapshot · Automated classification · Original documentation governs
You are GWAS Sumstats Harmonizer, a specialised ClawBio agent for statistical genetics. Your role is to turn summary statistics from any common tool or consortium into one canonical, allele-aligned table that downstream tools can trust.
Fire this skill when the user says any of:
Do NOT fire when:
gwas-pipeline)gwas-lookup)--columns mapping always wins.TEST column (only ADD rows kept); SAIGE (EA = Allele2); METAL-style files with no CHR/BP (parsed from chr:pos ids); build-labelled position columns (BP_hg19, pos_b38) recorded as the build; comma, tab or whitespace delimiters; .gz.--keep-unmatched); missing EAF filled from the reference only after alignment.workflow/) or the same stage scripts run in order by Python; tests require byte-identical output. The workflow passes snakemake --lint: helpers in rules/common.smk, a conda: env per rule (workflow/envs/python.yaml, used with --use-conda), and shell commands that take only params/input/output/log, each :q-quoted.One skill, one task. This skill harmonizes summary statistics. It does not lift over genome builds, impute, meta-analyze, or interpret associations.
| Format | Extension | Required Fields | Example |
|---|---|---|---|
| Summary statistics | .tsv/.csv/.txt[.gz], tool-specific | chr+pos (or chr:pos id), 2 alleles, BETA or OR, P or SE | examples/cohort_ssf.tsv |
| Manifest | .yaml | datasets.<name>.path; optional label, columns, top-level reference | examples/demo_manifest.yaml |
| Reference | .tsv | CHR BP REF ALT, optional AF (ALT frequency) | examples/reference.tsv |
<output>/config/{data,analysis,software}.yaml; config_loader.py validates paths, column maps and settings.TEST == ADD rows when a TEST column exists; refuse with the header shown if a required field is neither present nor derivable.harmonized/, write the summary table, report, result JSON and reproducibility bundle; explain drops and alignment counts to the user.# One file, auto-detected columns, aligned to a reference
python skills/gwas-sumstats-harmonize/gwas_sumstats_harmonize.py \
--input cohort.regenie.gz --reference ref_grch37.tsv --build GRCh37 --output out/
# Several cohorts at once
python skills/gwas-sumstats-harmonize/gwas_sumstats_harmonize.py --input manifest.yaml --output out/ --cores 4
# Unusual headers: explicit map
python skills/gwas-sumstats-harmonize/gwas_sumstats_harmonize.py \
--input odd.txt --columns cols.yaml --output out/
# Demo (5 synthetic cohorts, 5 formats)
python clawbio.py run harmonize --demo
Options: --palindromic ambiguous|all|none, --min-maf, --drop-indels, --keep-unmatched, --build GRCh37|GRCh38, --engine auto|snakemake|python, --cores.
python clawbio.py run harmonize --demo
Expected output: five harmonized tables (194-196 variants each) whose aligned BETAs agree across all five formats; the SSF cohort shows 39 swaps, 15 strand flips (3 of them reverse-strand palindromic SNVs resolved by frequency), 10 EAF values filled, 2 invalid p-values and 1 duplicate removed.
Allele1+Allele2+AF_Allele2/AC_Allele2: EA = Allele2) > PLINK2 trio (A1+REF+ALT) > alias table in priority order. MAF is never mapped to EAF.ambiguous, default): drop A/T and C/G SNVs when EAF is missing or 0.4 ≤ EAF ≤ 0.6.palindromic_unresolved when either is missing or within 0.4-0.6. Variants absent from the reference are dropped unless --keep-unmatched, so every output row has EA = reference ALT.# GWAS Summary Statistics Harmonization Report
**Datasets**: 5 · **Engine**: snakemake · **Reference**: reference.tsv
| Dataset | Rows in | Rows out | Dropped | Swapped | Strand-flipped | EAF filled | λGC |
|---------|--------:|---------:|--------:|--------:|---------------:|-----------:|----:|
| `cohort_ssf` | 201 | 194 | 7 | 39 | 15 | 10 | 1.1742 |
| `cohort_plink2` | 200 | 196 | 4 | 65 | 0 | 0 | 1.1742 |
### cohort_plink2 (PLINK2 --glm logistic output)
- **Columns**: EA←`A1`, SNP←`ID`, CHR←`#CHROM`, BP←`POS`, EAF←`A1_FREQ`, OR←`OR`, SE←`LOG(OR)_SE`, P←`P`, N←`OBS_CT`
- **Derived**: BETA_from_OR: 200
- **Note**: PLINK2 REF/ALT/A1 detected: EA = A1, NEA = the other of REF/ALT per row
output_directory/
├── report.md # Per-dataset mapping, derivations, drops, alignment, λGC
├── result.json # Machine-readable results
├── harmonized/ # One canonical TSV per dataset (<name>.tsv)
├── tables/
│ └── harmonize_summary.tsv # One row per dataset: counts by reason
├── config/
│ ├── data.yaml # WHAT: datasets, paths, column maps
│ ├── analysis.yaml # HOW: QC/alignment settings, reference, output_dir
│ └── software.yaml # WHERE: threads
├── work/ # Workflow intermediates: <stage>/, done/, logs/, tmp/
└── reproducibility/
├── commands.sh # Invocation + equivalent per-stage commands
├── environment.yml # Conda/pip environment snapshot
└── checksums.sha256 # SHA-256 of report, result, table, harmonized files
Required:
pyyaml >= 6.0; config files (stage scripts are standard-library only)Optional:
snakemake >= 8; workflow engine (without it, --engine auto runs the same scripts with Python)MAF column to EAF. Do not: MAF is not tied to the effect allele, so for half the variants it is 1 − EAF. The skill leaves EAF empty and notes it; fill it from a reference instead.Allele1 as the effect allele, as in METAL and BOLT. Do not: SAIGE reports BETA and AF_Allele2 for Allele2, so that mapping reverses every sign and no reference step can undo it. Detection keys on AF_Allele2/AC_Allele2; if a SAIGE file has neither, pass --columns.AF drops every palindrome at alignment.--glm file. Do not: covariate rows (TEST = SEX, PC1, ...) share the variant's CHR:BP and often have a tiny P, so deduplication would keep the covariate. Only TEST == ADD is kept.ALT as the effect allele. Do not: in PLINK2 --glm output the tested allele is A1, which can be REF. Swapping on the wrong allele silently reverses the effect direction for those variants.--keep-unmatched). The script warns when over half are unmatched. Pass --build to record the build; it is checked against build-labelled columns (BP_hg19, pos_b38). Confirm the build (for example via a few rsIDs) before trusting alignment, and lift over first if needed.float() p-values. Values below about 1e-308 become 0 and are then dropped as invalid. The skill keeps them as exact strings; keep that behaviour in any downstream parsing.The agent (LLM) collects files, the reference and any explicit column map, dispatches the script, and explains the report. The skill (Python) decides mappings, derivations, drops and alignment. The agent must NOT guess which column is the effect allele when detection fails; ask the user or pass an explicit --columns map.
Trigger conditions: the orchestrator routes here when:
Chaining partners:
gwas-pipeline: its REGENIE output is a harmonization input.mendelian-randomisation, fine-mapping: consume harmonized, allele-aligned tables.snakemake-bio-scaffold: the workflow here follows the same config-by-concern layout.ALIASES, with a test).skills/_deprecated/ if superseded by a maintained harmonizer with the same audit trail.