Skip to content

IGVF export

cau igvf-export writes a guide design in the IGVF per-guide metadata format. It is the fourth step: alignment finds each guide's site, annotation says what gene it falls in, element mapping says which element it tests, and this assembles the result into the table IGVF asks for.

In Claude Code the cau-igvf-export skill teaches Claude to run it and read the output (Agents and skills).

Quick start

cau igvf-export run \
    --alignment results/alignments/guide_genome_annotation.tsv \
    --mapping results/elements/guide_element_mapping.tsv \
    --elements elements.bed \
    --store gencode.v43.protein_coding.parquet \
    --promoters gencode.v43.protein_coding.TSS1bp.bed6 \
    --genes measured_element_gene_pairs.tsv \
    --outdir results/

--genes is optional and takes a table of measured element-to-gene pairs: the first column names the element, and the first column of ENSEMBL ids names the gene. Without it, a promoter's gene is inferred from the nearest TSS.

The format

The table follows Format_for_Per-Guide_Metadata.pdf, the IGVF document that files with content_type "guide RNA sequences" must abide by. Its conventions are the ones the rest of this package already uses — 0-based, half-open, ACTG — and it pins ENSEMBL ids to GENCODE release 43, so build the annotation store from v43.

What a guide targets is decided from the genome

A design's category for an element is a hypothesis; the annotation is evidence. In order:

  1. a validated enhancer stays enhancer;
  2. within 2 kb of a protein-coding TSS, promoter;
  3. overlapping an exon, exon;
  4. inside a gene, intron;
  5. otherwise, distal element.

The 2 kb is the format's own definition of a distal element ("outside of a gene body, >2 kb from any annotated TSS").

The exception is a validated enhancer: that an element was shown to regulate a particular gene is experimental knowledge no annotation can supply, so that label is trusted and its gene comes from the measured pairs.

This matters in practice. In a real 43,778-guide screen the design labelled 344 elements promoter; 300 of those have a measured gene and the genome agreed with every one, but of the other 44, 39 contained no transcription start site of any biotype — checked against all 62,757 genes of v43 — and one sat 109 kb from the nearest. Derived rather than believed, those 44 came out as 25 exon, 18 promoter and 1 intron.

type has to agree

positive control means a guide expected to produce a known measurable effect. A row claiming that while its genomic_element is exon contradicts itself, so a guide is a positive control only when its element is a validated enhancer, or the design calls it a promoter and the genome agrees.

One row per guide

The format requires guide_id to be unique, so a guide inside two overlapping elements still gets one row: the element sharing the most bases with the protospacer, ties broken by element id. Nothing is lost, because putative_target_genes keeps every gene of every element the guide hit — which is also how a bidirectional promoter keeps both of its genes.

Outputs

--outdir gets three folders and nothing loose:

igvf/            guide_metadata.tsv  guide_metadata_columns.yaml
run_metadata/    igvf_export_<UTC timestamp>.json
logs/            igvf_export.log

guide_metadata.tsv

One row per guide, which the format requires: a guide_id must name one guide and one spacer.

Column Holds
guide_id The guide's name, from the input table's own name for it.
spacer The targeting sequence, 5' to 3', in DNA bases.
oligo The sequence ordered, without the PAM.
n_oligos Entries sharing this spacer; above one the counts are a sum.
targeting TRUE only when the guide targets a relevant locus.
type targeting, safe-targeting, non-targeting or positive control.
guide_chr, guide_start, guide_end The protospacer, 0-based and half-open, without the PAM.
strand The strand targeted.
pam The PAM as the genome holds it, 5' to 3' on that strand.
element_location genic or intergenic: whether the element overlaps a protein-coding gene. Independent of genomic_element, which tests promoter and enhancer first.
genomic_element promoter, enhancer, distal element, exon or intron.
intended_target_name Names the target; what it holds depends on the element.
intended_target_chr/start/end The element's coordinates.
putative_target_genes Every associated gene, comma-separated.
reporter, imperfect Unused here; the format allows them.

What intended_target_name holds

genomic_element holds
promoter the regulated gene's ENSEMBL id
exon the ENSEMBL exon id
intron the intron's coordinates
enhancer, distal element the element's coordinates

A guide in two elements

Elements overlap, so a guide can sit in several, and the format still allows one row. The element sharing the most bases with the protospacer wins, ties broken by element id so a rerun gives the same answer. Nothing is lost: putative_target_genes carries every gene of every element the guide hit.

run_metadata/igvf_export_<timestamp>.json

The parameters, the input checksums, the store's provenance and the counts: guides by type, elements by genomic_element, and how many guides are missing a PAM, which should be zero for anything that maps.

Feeding the CRISPR pipeline

The IGVF CRISPR Perturb-seq pipeline takes a guide_metadata.tsv with a subset of these columns — everything except genomic_element, putative_target_genes, reporter and imperfect — so this table can be passed to it as it is.

intended_target_name is what joins the guide table to the pipeline's pairs-to-test file, so the two have to name elements the same way.

genomic_element does not say genic

genomic_element is decided by precedence -- promoter, then exon, then intron, then distal element -- so promoter and enhancer win before the gene body is tested and the class cannot say whether the element sits in a gene. element_location does, computed from the same overlap. On the hiPSC-to-EC library 499 promoter and 110 enhancer guides are intergenic, while every exon and intron guide is genic.