bio-variant-normalization — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited bio-variant-normalization (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Left-align indels and split multiallelic sites using bcftools norm.
The same variant can be represented multiple ways:
# Same deletion, different representations
chr1 100 ATCG A (right-aligned)
chr1 100 ATC A (left-aligned, normalized)
chr1 101 TCG T (different position)Normalization ensures consistent representation for:
bcftools norm -f reference.fa input.vcf.gz -Oz -o normalized.vcf.gzRequires reference FASTA to determine left-most representation.
bcftools norm -f reference.fa -c s input.vcf.gz > /dev/null
# Reports REF allele mismatchesCheck modes (-c):
w - Warn on mismatch (default)e - Error on mismatchx - Exclude mismatchess - Set correct REF from referencebcftools norm -m-any input.vcf.gz -Oz -o split.vcf.gzBefore:
chr1 100 . A G,T 30 PASS . GT 1/2After:
chr1 100 . A G 30 PASS . GT 1/0
chr1 100 . A T 30 PASS . GT 0/1bcftools norm -m-snps input.vcf.gz -Oz -o split_snps.vcf.gzbcftools norm -m-indels input.vcf.gz -Oz -o split_indels.vcf.gzbcftools norm -m+any input.vcf.gz -Oz -o merged.vcf.gz| Option | Description |
|---|---|
-m-any | Split all multiallelic sites |
-m-snps | Split multiallelic SNPs only |
-m-indels | Split multiallelic indels only |
-m-both | Split SNPs and indels separately |
-m+any | Join biallelic sites into multiallelic |
-m+snps | Join biallelic SNPs |
-m+indels | Join biallelic indels |
-m+both | Join SNPs and indels separately |
bcftools norm -f reference.fa -m-any input.vcf.gz -Oz -o normalized.vcf.gz
bcftools index normalized.vcf.gzThis:
bcftools norm -f reference.fa -m-any -d exact input.vcf.gz -Oz -o normalized.vcf.gzDuplicate removal options (-d):
exact - Remove exact duplicatessnps - Remove duplicate SNPsindels - Remove duplicate indelsboth - Remove duplicate SNPs and indelsall - Remove all duplicatesnone - Keep duplicates (default)bcftools norm -f reference.fa -c s input.vcf.gz -Oz -o fixed.vcf.gzThis sets REF alleles to match the reference genome.
bcftools norm -f reference.fa -c x input.vcf.gz -Oz -o clean.vcf.gzRemoves variants where REF doesn't match reference.
bcftools norm --atomize input.vcf.gz -Oz -o atomized.vcf.gzBefore:
chr1 100 . ATG GCA 30 PASSAfter:
chr1 100 . A G 30 PASS
chr1 101 . T C 30 PASS
chr1 102 . G A 30 PASSbcftools norm -f reference.fa --atomize input.vcf.gz -Oz -o atomized.vcf.gzbcftools norm --old-rec-tag OLD input.vcf.gz -Oz -o updated.vcf.gzTags original record for reference.
# Normalize both VCFs the same way
for vcf in caller1.vcf.gz caller2.vcf.gz; do
base=$(basename "$vcf" .vcf.gz)
bcftools norm -f reference.fa -m-any "$vcf" -Oz -o "${base}.norm.vcf.gz"
bcftools index "${base}.norm.vcf.gz"
done
# Now compare
bcftools isec -p comparison caller1.norm.vcf.gz caller2.norm.vcf.gzbcftools norm -f reference.fa -m-any variants.vcf.gz -Oz -o normalized.vcf.gz
bcftools index normalized.vcf.gz
# Now annotate against dbSNP, ClinVar, etc.bcftools norm -f reference.fa -m-any -d exact input.vcf.gz | \
bcftools view -v snps -Oz -o gwas_ready.vcf.gz
bcftools index gwas_ready.vcf.gzfrom cyvcf2 import VCF
def needs_normalization(variant):
# Check for multiallelic
if len(variant.ALT) > 1:
return True
# Check for complex variants (potential MNPs)
ref, alt = variant.REF, variant.ALT[0]
if len(ref) > 1 and len(alt) > 1 and len(ref) == len(alt):
return True
return False
count = 0
for variant in VCF('input.vcf.gz'):
if needs_normalization(variant):
count += 1
print(f'Variants needing normalization: {count}')from cyvcf2 import VCF
multiallelic = 0
total = 0
for variant in VCF('input.vcf.gz'):
total += 1
if len(variant.ALT) > 1:
multiallelic += 1
print(f'Total variants: {total}')
print(f'Multiallelic sites: {multiallelic}')
print(f'Percentage: {multiallelic/total*100:.1f}%')| Task | Command |
|---|---|
| Left-align indels | bcftools norm -f ref.fa in.vcf.gz |
| Split multiallelic | bcftools norm -m-any in.vcf.gz |
| Join to multiallelic | bcftools norm -m+any in.vcf.gz |
| Full normalization | bcftools norm -f ref.fa -m-any in.vcf.gz |
| Fix REF alleles | bcftools norm -f ref.fa -c s in.vcf.gz |
| Remove duplicates | bcftools norm -d exact in.vcf.gz |
| Atomize MNPs | bcftools norm --atomize in.vcf.gz |
| Error | Cause | Solution |
|---|---|---|
REF does not match | Wrong reference | Use same reference as caller |
not sorted | Unsorted input | Run bcftools sort first |
duplicate records | Same position twice | Use -d to remove |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.