Guide alignment¶
cau guide-alignment finds where a CRISPR guide library maps in a genome. A
guide is designed, not sequenced, so its site is an exact match of the
protospacer: the tool scans the reference once and answers three questions per
guide — where does the protospacer match, is there a PAM 3' of it, and what
sits 5' of it. There is no aligner, no index and no error budget.
A 44,000-guide library against hg38 takes about half a minute.
In Claude Code the cau-guide-alignment skill teaches Claude to run it and
read the outputs (Agents and skills).
Quick start¶
cau guide-alignment run \
--guides guides.tsv \
--reference GRCh38.fa \
--outdir results/
The guide table is two columns by default, a name and a sequence, with no header:
240911_EC_TAPseq_Enhancers_1 GAAAAGCCAACATGAATGCAG
240911_EC_TAPseq_Enhancers_2 GTTTGAGCACATAGCTCTAAG
(the separator above is a tab)
The reference must be an uncompressed FASTA. Nothing is written outside
--outdir, and nothing is written beside your inputs.
What the sequences must be¶
The guide as ordered, 5' to 3', without the PAM. The tool appends --pam
(default NGG) itself.
--spacer-length (default 20) says how long the protospacer is. Anything 5'
of it — typically the G added for the U6 promoter — is aligned too, but a
mismatch there is tolerated and reported rather than counted. That is what
makes the two sequence columns of the output worth comparing.
If your table holds bare protospacers and the construct adds a G that is not
in the file, pass --add-leading-g.
One spacer in sixteen ends in GG
So a table that silently includes the PAM will run without complaint and be wrong by three bases. Check the column before the first run.
Options¶
| Option | Default | Meaning |
|---|---|---|
--guides, --reference, --outdir |
required | |
--pam |
NGG |
IUPAC codes, 3' of the protospacer |
--spacer-length |
20 |
The protospacer is the 3'-most this many bases |
--add-leading-g |
off | Put a G in front of every sequence |
--orientation-check |
error |
error, warn or off |
--fix-orientation |
off | Align the reverse complement of flagged entries |
--contigs |
every contig | Comma-separated names |
--id-col, --spacer-col |
0, 1 |
A 0-based position, or a column name |
--sep |
tab | tab, comma, or one character |
--header |
off | The first line holds column names |
For hg38, give --contigs the primary chromosomes: without it the alt and
random scaffolds are read too, and a guide will match its own alt copy.
Coordinates¶
0-based and half-open, on the reference's forward strand, and the protospacer
alone — the PAM and any base 5' of it are outside [start, end).
target_site is the boundary the blunt SpCas9 cut falls on, three bases from the
PAM: the cut lies between target_site - 1 and target_site. On + that is
end - 3, on - it is start + 3.
Orientation¶
Both readings of every guide go into the same scan. An entry is
reverse_complement only when its reverse complement has a PAM-bearing site
and the sequence as given does not. Reading a CCN 5' of a match is not
the test — that falls there by chance one time in sixteen.
A table reversed throughout stops the run. A handful of entries only warns,
because a single guide can look reversed when its PAM simply differs between
assemblies. orientation_evidence records whether the test was distinct or
ambiguous; ambiguous means the guide has nothing 5' of its spacer, so a flip
and a chance CCN cannot be told apart.
Outputs¶
--outdir gets three folders and nothing loose, so a run's output never sits
beside its inputs:
alignments/ guide_genome_annotation.tsv guide_mapping.bed
guide_genome_annotation_columns.yaml qc.tsv
run_metadata/ guide_alignment_<UTC timestamp>.json
logs/ guide_alignment.log
guide_genome_annotation_columns.yaml is written from the same
definitions the tables are, so it is
always an accurate data dictionary of the folder it sits in. Read it first.
guide_genome_annotation.tsv¶
One row per library entry per site. A guide matching three places gets three rows; one matching nowhere gets a single row whose site columns are empty. The guide's own columns repeat on each of its rows.
| Column | Holds |
|---|---|
guide_id |
The sequence that was aligned, ending in the PAM pattern. Identifies the guide. |
alias |
The name the input table gives it. |
spacer |
The protospacer: guide_id without any base 5' of it or the PAM. |
oligo |
The sequence the library ordered, without the PAM: the spacer plus any base 5' of it. |
n_oligos |
How many entries share this spacer. Above one the counts are a sum, because one feature is all the reads can resolve. |
site_class |
unique, multi or no_site: how many places this guide can cut. |
n_matches |
How many places the protospacer occurs in the genome. |
n_target_sites |
How many of those have a PAM. |
orientation |
forward, reverse_complement, no_pam, no_match or not_checked. |
orientation_evidence |
For reverse_complement only: distinct or ambiguous. |
chr, start, end, strand |
This row's match. 0-based, half-open, the protospacer alone. |
target_site |
The boundary the cut falls on: between target_site - 1 and target_site. |
pam_matches |
TRUE when the genomic PAM fits the pattern. |
mapped_sequence |
What the genome holds here, to compare against guide_id. |
The two sequence columns¶
They line up base for base, so one diff answers three questions:
guide_id GAAAAGCCAACATGAATGCAGNGG what was looked for
mapped_sequence AAAAGCCAACATGAATGCAGTGG what the genome holds
^ ^^^
the 5' G did not pair the real PAM
mapped_sequence keeps the 5' base only where the genome has that same base,
so its length tells you whether the G is genomic or was added for the U6
promoter.
n_matches is not site_class¶
A guide can occur many times and still be cuttable once. This is the most common surprise:
n_matches 89 n_target_sites 1 site_class unique
The protospacer occurs 89 times; one of those has a PAM. Cas9 cuts there and
nowhere else. Every one of the 89 is a row in the table, 88 of them with
pam_matches FALSE.
guide_mapping.bed¶
BED6, no header, one row per cuttable site, so a guide that cuts twice
gets two rows. start/end are the protospacer, without the PAM. The name
field is the spacer, which is the same on every row of one guide, so rows
group by name. Matches with no PAM are not here; they are in the TSV.
qc.tsv¶
Three columns, section, name, value. The class and orientation
sections each sum to the number of entries. scan holds what the pass saw:
n_matches, n_off_contig_end, n_no_pam, n_sites.
run_metadata/guide_alignment_<timestamp>.json¶
One file per invocation, named for the step and when it ran: the parameters, the input checksums, the version, the counts and the timings. Nothing per-guide lives here.
What this does not do¶
Off-target search. Matching is exact, so there are no mismatch counts. Where a guide can also cut with one or two mismatches is a different question from where it comes from, and it is not answered here.
Bulges, scores and other nucleases. No DNA or RNA bulges, no CFD or MIT scores, and 3' PAMs only.
Coming from the GEM version¶
The tool used to align guides with GEM3. It now scans the reference directly: a guide is designed, not sequenced, so its site is an exact match of the protospacer, and the only other questions are what sits 3' of it (the PAM) and what sits 5' of it. There is no aligner, no index and no error budget.
What went away¶
| Gone | Why |
|---|---|
cau guide-alignment index, --index |
Nothing is indexed. Point --reference at the FASTA. |
--max-mismatches |
Matching is exact. Off-target search is separate work. |
--alt-pams |
Only --pam is searched. |
--threads |
One pass, no aligner to parallelise. |
alignments/*.bam, *.fastq |
No reads are written and nothing is aligned. |
| GEM3 itself | No external tool, so every environment is native on Apple silicon. |
A whole library now takes seconds rather than an hour, and the four GEM
defects the old version worked around — the -M 5 search cap, the N of
NGG eating the error budget, non-exhaustive search modes and garbage
coordinates at contig ends — cannot arise.
Renamed files¶
| Was | Now |
|---|---|
guides.tsv and sites.tsv |
one guide_genome_annotation.tsv |
guides.bed |
guide_mapping.bed |
target_sites.bed |
gone; target_site is a column |
orientation.tsv |
gone; its verdict and site are columns |
summary.tsv |
qc.tsv, counts only |
run.json |
run_metadata/guide_alignment_<timestamp>.json |
Everything now lives under alignments/, run_metadata/ and logs/.
Renamed columns¶
| Was | Now |
|---|---|
guide_id (the lab's name) |
alias |
| — | guide_id is now the aligned sequence |
targeting |
gone; use n_target_sites |
alignment_class |
site_class, and off_target_only no longer exists |
n_ngg_<m>mm |
n_target_sites, exact matches only |
min_ngg_mismatches |
gone |
leading_g |
gone; compare the lengths of guide_id and spacer |
pam_class |
pam_matches, TRUE/FALSE |
site_pam, guide_chr/start/end |
pam folded into mapped_sequence; chr, start, end |
no_perfect_hit (orientation) |
no_match |
input_sequence and genomic_protospacer are gone: the first is in your
input file and in guide_id, and the second is always identical to spacer
when matching is exact.
What this changes in a result¶
- Guides are keyed by sequence. Two entries differing only by a 5' G are two guides, not duplicates. The old version truncated them to the same spacer and collapsed them.
n_matchesis new and often surprising. The oldmulticounted only PAM-bearing sites and still does;n_matchescounts every occurrence of the protospacer, which is usually larger.- Orientation is decided from both readings, not from a
CCNupstream. A library reversed throughout stops the run; a handful of entries warns.