Skip to content
@jennifer/ngs

@jennifer/ngs

Streaming file formats, read QC, interval arithmetic and pipeline orchestration for next-generation sequencing data, written in Jennifer.

What this deck is

NGS breaks the ordinary deck model on two axes, and the design follows from both.

Scale. FASTQ.gz files run to tens of gigabytes and BAM to hundreds. So everything here streams: every reader is a pull cursor over one line at a time, and nothing in this deck loads a sequencing file into memory. A 50 GB input costs the same memory as a 50 MB one.

Compute. Alignment, assembly and variant calling are heavily SIMD-optimised C. A tree-walking interpreter is orders of magnitude too slow to replace them, and a library that pretended otherwise would be one nobody could use.

So the deck is deliberately the glue and light-I/O layer, not the engine. It is the part of a sequencing pipeline that is all string handling, bookkeeping and process management - the part where a real language with structs, enums, error handling and a test runner beats three hundred lines of shell.

In scope

areawhat you get
Streaming format I/OFASTQ, SAM, VCF, BED, GFF3/GTF - parse, filter and convert as a stream
QCper-base quality, length and GC distributions, adapter detection, one pass
Preprocessingquality and adapter trimming, length filtering, subsampling
Interval operationsoverlap, intersect, merge, subtract, coverage, complement
Pipeline orchestrationdrive the standard tools, fan out over samples, handle errors

Out of scope

Wrap the native tool and pipe to it; do not reimplement it here.

  • Read alignment - BWA, Bowtie2, minimap2
  • De-novo assembly - SPAdes
  • Variant calling - GATK
  • BAM/CRAM handling - additionally needs BGZF (blocked gzip for random access), which the compress library does not provide, and whose standalone value is limited without the downstream compute the deck omits

Pipeline orchestration is how you drive all of them, and Recipes shows what that looks like end to end.

The modules

Every module is independent: importing fastq.j does not drag in the pipeline layer. Import what you use.

modulewhat it does
sourcestreaming line sources and sinks, gzip transparent both ways
fastqFASTQ records, streaming reader and writer, per-record accessors
bedBED features, straight onto the interval engine
gffGFF3 and GTF features, with 1-based to 0-based conversion
samSAM alignments, FLAG and CIGAR handling
vcfVCF variants, INFO and per-sample FORMAT access
intervalsoverlap, merge, intersect, subtract, coverage, complement, slop
qcone-pass FastQC-lite statistics
trimfastp-lite trimming, filtering and subsampling
pipelinerun, skip, check and fan out external tools
coreshared primitives the rest of the deck is built on
ngsthe entry module: version, and the host capability check

Every exported name in all twelve is listed in the cheatsheet.

A first look

jennifer
use io;
import "@jennifer/ngs/fastq.j" as fastq;
import "@jennifer/ngs/qc.j" as qc;

# Streams, gzip and all - memory stays flat regardless of file size.
def report as qc.Report init qc.analyze("sample.fastq.gz", qc.options());
io.printf("%s", qc.summary($report));

def r as fastq.Reader init fastq.open("sample.fastq.gz");
while (fastq.hasNext($r)) {
    def rec as fastq.Read init fastq.next($r);
    io.printf("%s\t%d\t%f|prec=1\n", $rec.id, fastq.length($rec), fastq.gcPercent($rec));
}
fastq.closeStrict($r);

Where to go next

Licence

LGPL-3.0-only, matching the Jennifer interpreter.