GhostVariant is a command-line tool for finding repeat-prone sequence contexts and annotating VCF/BCF variants that overlap them.
It is aimed at variant interpretation, benchmarking, and filtering workflows where low-complexity sequence, tandem repeats, and homopolymers are useful stratification features.
Current CLI version: 0.1.0
scan: detect low-complexity regions, tandem repeats, and homopolymers from a FASTA reference and write a BED fileannotate: add repeat-region annotations to VCF/BCF records- Supports FASTA input compressed with gzip
- Supports VCF, VCF.GZ/BGZF, BCF, and BCF.GZ/BGZF through HTSlib
- Optional
--filterto write repeat type labels into the VCF FILTER field - Optional
--padto widen variant overlap queries - Optional
--statssummary TSV forannotate
Repeat sources:
lowcomplexity: longdust-derived low-complexity regionstandem: ATR-style tandem repeatshomopolymer: perfect or one-base interrupted homopolymer runsbed: generic BED3 regions whenannotateis run with BED3 input
These examples assume the ghostvariant binary is available after building
from source or by using Docker.
Create repeat regions from a reference FASTA:
./ghostvariant scan --fasta ref.fa.gz --out repeats.bed --threads 8 --headerAnnotate variants:
./ghostvariant annotate \
--vcf input.vcf.gz \
--bed repeats.bed \
--out annotated.vcf.gz \
--threads 4 \
--output-format vcf.gz \
--stats annotated.stats.tsvAdd repeat types to FILTER as well as INFO:
./ghostvariant annotate \
--vcf input.vcf.gz \
--bed repeats.bed \
--out annotated.filter.vcf.gz \
--filterInput FASTA:
- Plain or gzip-compressed FASTA is accepted.
- Use
-to read FASTA from stdin. - Sequence names are taken from the FASTA header up to the first whitespace.
- Lowercase bases are accepted.
Input VCF/BCF:
- Plain VCF, compressed VCF, BCF, and compressed BCF are accepted.
- Use
-to read from stdin. - Chromosome/contig names must match the BED names exactly.
Input BED:
annotateaccepts either full GhostVariant BED output or simple BED3.- BED coordinates must satisfy
0 <= start <= end. - BED3 input is treated as generic
bedcontext. Metadata-derived INFO fields are emitted as missing values (.).
Output VCF/BCF:
- Output format is inferred from
--outwhen possible. - Use
--output-format vcf,vcf.gz,bcf, orbcf.gzto force a format. - Use
-to write to stdout. When writing binary output to stdout, set--output-format bcfor--output-format bcf.gz.
Coordinates:
- BED uses 0-based, half-open intervals:
[start, end). - VCF POS is 1-based.
GV_REPEAT_REGIONis reported as 1-based inclusivesource_chrom_start_end.
ghostvariant scan detects repeat-prone regions from FASTA input and writes a
BED file. FASTA input order is preserved.
Example:
./ghostvariant scan -i ref.fa.gz -o repeats.bed \
--threads 8 --chunk-size 5000000 --overlap 10000 --headerOptions:
-i, --fasta PATH: input FASTA (gzip supported;-for stdin)-o, --out PATH: output BED (-for stdout)--threads INT: number of threads (default: 1)--chunk-size INT: chunk size in bp (default: 5,000,000)--overlap INT: overlap size in bp (default: 10,000; recommended>= 2*max(ws, atr-x);<=0for auto)--header: write BED header--min-run INT: homopolymer min run (default: 7)--merge-gap INT: homopolymer merge gap (default: 1)--atr-m INT,--atr-M INT,--atr-r INT,--atr-l INT,--atr-e INT,--atr-p FLOAT,--atr-x INT: tandem repeat parameters--ld-kmer INT,--ld-ws INT,--ld-thres FLOAT,--ld-xdrop INT,--ld-min-start INT,--ld-gc FLOAT,--ld-approx: longdust parameters
BED columns:
chrom start end repeat_type gc_content unit_seq unit_len repeat_len copy_number n_count purity
Column notes:
repeat_typeislowcomplexity,tandem, orhomopolymer.gc_contentuses A/C/G/T bases as the denominator.unit_seqandunit_lendescribe the repeat unit when applicable.repeat_lenis the interval length used for the reported repeat.copy_numberisrepeat_len / unit_lenfor tandem repeats and the number of matching homopolymer bases after gap-merge for homopolymers.purityis reported fortandemandhomopolymeras the percentage of bases matching the reported repeat unit from the interval start.lowcomplexityhaspurity=unknown.
Chunk boundary policy:
lowcomplexityandhomopolymerintervals are retained when they intersect the chunk core.tandemintervals are retained when their start lies in the chunk core.- This
lowcomplexitypolicy was validated against original longdust on the CHM13 genome.
Homopolymer defaults:
- The default homopolymer threshold (
--min-run 7) is consistent with the GIAB/NIST low-complexity stratification convention for perfect homopolymers greater than 6 bp. - The
--merge-gap 1option is intended to capture one-base interrupted same-base runs, conceptually similar to GIAB imperfect homopolymer stratifications greater than 10 bp with a 1-bp interruption. GhostVariant does not attempt to exactly reproduce GIAB stratification BEDs. - See the GIAB/NIST genome stratifications for the underlying stratification convention: https://github.com/genome-in-a-bottle/genome-stratifications
ATR input normalization:
- Lowercase bases are uppercased.
- Non-ACGT bases, including IUPAC ambiguous bases and
N, are normalized toN. Nis skipped, not treated as a hard boundary.
Validated longdust-consistency setting:
- For CHM13v2 whole-genome validation against original longdust,
--chunk-size 20000000 --overlap 5000000with thelowcomplexitycore-intersection policy reproduced the original longdust BED exactly. - The CLI defaults remain smaller for general runtime.
ghostvariant annotate uses a BED file to determine whether each VCF/BCF
variant overlaps repeat regions. It adds GhostVariant-managed INFO fields and,
optionally, FILTER labels.
Example:
./ghostvariant annotate -i input.vcf.gz -b repeats.bed -o annotated.vcf.gz \
--threads 4 --buffer-size 10000 --output-format vcf.gz --stats stats.tsvOptions:
-i, --vcf PATH: input VCF/BCF (-for stdin)-b, --bed PATH: input BED (required; GhostVariant BED or BED3)-o, --out PATH: output VCF/BCF (-for stdout)--threads INT: number of threads (default: 1)--buffer-size INT: buffer size (default: 10,000; must be>= 1)--info-prefix STR: INFO prefix (default:GV)--output-format STR:vcf,vcf.gz,bcf, orbcf.gz--stats PATH: write one-row record-level summary TSV--filter: write repeat type into FILTER when overlapping.PASSis replaced; existing non-PASS labels are preserved and appended with;. BED3-derived overlaps usebed.--pad INT: symmetric padding in bp applied to the overlap query (default: 0)
INFO fields:
GV_REPEAT_REGION: overlapping regions assource_chrom_start_endGV_TYPE: repeat typeGV_GC: GC percentageGV_UNIT: repeat unitGV_UNIT_LENGTH: repeat unit lengthGV_REPEAT_LEN: repeat lengthGV_COPY_NUMBER: copy numberGV_N_COUNT: number ofNbasesGV_PURITY: repeat purity percentage
Variant footprint rules:
- SNVs and MNVs are evaluated over their reference footprint.
- Indels use
POS-1 .. POS-1+len(REF). DEL,DUP,INV, andCNV-like alleles use a reference span derived fromENDand/or allele-specificSVLEN.INSand breakend-like alleles are treated as length 1 atPOS.- Multi-allelic records are annotated at record level using the union of ALT-specific footprints.
Re-running annotation:
- Re-running
annotatewith the same INFO prefix replaces existing{prefix}_*annotations on each record. - GhostVariant-managed FILTER labels (
lowcomplexity,tandem,homopolymer,bed) are recomputed on each run. - Unrelated FILTER labels are preserved.
Stats output:
--stats writes a one-row TSV with these columns:
total_records annotated_records annotated_frac filtered_records filtered_frac total_snv total_mnv total_indel total_sv total_other annotated_snv annotated_mnv annotated_indel annotated_sv annotated_other overlap_lowcomplexity overlap_tandem overlap_homopolymer overlap_bed multi_overlap_records multi_type_records
--stats - is not supported because stdout may already be used for VCF/BCF
output.
Build requirements:
- C++17 compiler
- GNU Make
- zlib, bzip2, liblzma, and libcurl development headers
Runtime requirements:
- zlib, bzip2, liblzma, libcurl, and the C++ standard library
Development and validation:
- Python 3 for the test scripts
- Docker, optional, for containerized builds
HTSlib and longdust source snapshots are vendored under third_party/.
On Ubuntu-like systems, install the build dependencies:
sudo apt-get update
sudo apt-get install -y build-essential libbz2-dev libcurl4-openssl-dev liblzma-dev zlib1g-devBuild GhostVariant:
git clone <repository-url>
cd ghostvariant
makeCheck the CLI:
./ghostvariant --version
./ghostvariant --help
./ghostvariant scan --help
./ghostvariant annotate --helpClean local build outputs:
make cleanBuild the runtime image:
docker build -t ghostvariant:latest .Show command help:
docker run --rm ghostvariant:latest ghostvariant --version
docker run --rm ghostvariant:latest ghostvariant scan --help
docker run --rm ghostvariant:latest ghostvariant annotate --helpRun scan and annotate with the current directory mounted at /data:
docker run --rm -v "$PWD:/data" ghostvariant:latest \
ghostvariant scan --fasta /data/input.fasta --out /data/repeats.bed --header
docker run --rm -v "$PWD:/data" ghostvariant:latest \
ghostvariant annotate --vcf /data/input.vcf.gz --bed /data/repeats.bed \
--out /data/annotated.vcf.gz --stats /data/annotated.stats.tsv- GhostVariant reports sequence-context annotations. It does not classify variants as pathogenic, benign, or sequencing artifacts.
- Output depends on the reference FASTA, repeat parameters, and BED/VCF contig naming. Use the same reference naming convention throughout a workflow.
- BED3 input to
annotateis intentionally generic; usescanoutput when repeat metadata such as GC, unit, copy number, and purity are needed. - The default scan parameters are intended for general use. For exact longdust-consistency validation, use the setting documented above.
scanresults may differ slightly when--chunk-size,--overlap, or thread scheduling changes, especially for repeats near chunk boundaries. Use fixed scan parameters when comparing outputs across runs.- Whole-genome scans can be CPU intensive. Increase
--threadsand use a suitable--chunk-sizefor production references.
Build the binary before running the development test suite:
makeThe GitHub Actions workflow runs the regression and edge-case tests on Linux
and macOS. For local development, see tests/README.md for the maintained test
commands and fixture notes.
The test fixtures are intentionally small and are kept under tests/data/ and
tests/expected/.
If GhostVariant is used in a publication or benchmark, cite the GhostVariant repository or release once a DOI/release archive is available. Also cite the underlying methods and libraries as appropriate for your workflow:
- longdust for low-complexity region detection
- HTSlib for VCF/BCF I/O
- pytrf/ATR-style tandem repeat detection, for the tandem repeat algorithmic reference
- GIAB/NIST genome stratifications when comparing against those conventions
See third_party/longdust-1.4/README.md and
third_party/htslib-1.22.2/README for upstream citation details.
GhostVariant is released under the MIT License. See LICENSE.
Third-party components are documented in NOTICE and LICENSES/.
The source tree currently includes:
- longdust 1.4 source under
third_party/longdust-1.4(MIT) kseq.hbundled with longdust (MIT)- pytrf 1.4.2 algorithmic reference reimplemented in
src/tandem/atr.cpp(MIT) - htslib 1.22.2 under
third_party/htslib-1.22.2(MIT/Expat for most files; Modified 3-Clause BSD forcram/) - htscodecs bundled under htslib (
third_party/htslib-1.22.2/htscodecs) with BSD-style, public-domain, and CC0 notices as described by upstream
When redistributing source or binaries, include LICENSE, NOTICE, and the
relevant files under LICENSES/.
