Mageck
K-DenseCommunityCreated by K-Dense Inc.
- Skill
- Tool integration
- Science and research
- MIT
- Low risk
- Has scripts
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured workflow for processing pooled CRISPR screen data, including knockout, CRISPRi, and CRISPRa experiments. It leverages the MAGeCK 0.5.9.5 toolset to perform read counting, replicate and library quality control, and statistical testing to identify enriched or depleted genes. The workflow includes a Python helper to manage input validation, normalization, and result reporting, ensuring that guide-level counts are correctly processed into gene-level rankings with FDR and effect sizes.
What it does
- Counts sequencing reads from FASTQ files against a guide library.
- Performs quality control on libraries and replicates, including Gini coefficient and correlation analysis.
- Normalizes count data using median or control-guide methods.
- Executes statistical tests to identify significantly enriched or depleted genes.
- Generates comprehensive reports including FDR, log2 fold change, and gene rankings.
- Supports advanced multi-factor analysis via MAGeCK MLE design matrices.
When to use it
- When you need to process raw FASTQ reads from a pooled CRISPR screen.
- When comparing treatment and control conditions to identify gene hits.
- When performing quality assessment on CRISPR screen libraries and replicates.
- When you require a reproducible workflow for RRA-based gene ranking.
Advantages
- Automates complex MAGeCK command sequences and input validation.
- Provides clear provenance for normalization methods and statistical results.
- Enforces strict input formatting to prevent common analysis errors.
- Includes built-in QC reporting to identify potential experimental artifacts.
Usage examples
- “Count reads for my CRISPR screen samples c1, c2, t1, and t2 using library.tsv.”
- The skill runs the MAGeCK count command, processes the FASTQ files, and generates a count matrix.
- “Perform quality control on my count matrix counts.count.txt.”
- The skill evaluates library representation, zero fractions, and replicate correlations, outputting a qc.json report.
- “Run a statistical test to find enriched genes between control c1, c2 and treatment t1, t2.”
- The skill executes the MAGeCK test workflow, calculates gene rankings with FDR, and saves the results to the specified output directory.
Install
Download the skill as a ZIP:
https://mp-staging.autogineer.com/agent-skills/k-dense-ai/mageck/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip mageck.zip -d .agents/skills
Documentation by K-Dense Inc.
MAGeCK pooled-screen analysis
When to use
Use this skill to count existing sequencing reads against a supplied guide library or compare already-counted pooled screens. Deliver the count matrix, QC, guide and gene results, contrast provenance, and a short interpretation of enrichment/depletion. This workflow analyzes screens; it does not design guides or infer gene function from a hit alone.
Runtime
The tested source installation and external-runtime caveat are in
references/runtime.md. Verify both mageck --version and
mageck test --help before an analysis. The bundled Python helper is standard-library only.
MAGeCK itself also needs NumPy, SciPy, and the RRA binary. PDF/R reporting is optional and not
needed by the helper.
The official release directory still lists 0.5.9.5 as its latest MAGeCK release. Upstream now links the separate MAGeCK2 project; these commands and the helper target MAGeCK 0.5.9.5, not an interchangeable MAGeCK2 installation. This is a local CLI workflow with no service API or authentication.
Workflow
Establish the library version, perturbation modality, sample names, selection direction, biological replicates, baseline material, time point, and batch. Separate sequencing lanes from independent biological replicates. A plasmid baseline and a cell day-zero baseline answer different questions. Require an explicit treatment/control contrast; the helper never silently assigns all unused samples to the control group.
Validate a headerless TSV library containing guide ID, DNA sequence, gene. IDs and sequences must be unique. The helper requires a count-table header beginning
sgRNA,Gene, followed by unique nonnumeric sample names such asc1. MAGeCK can interpret numeric names as column indices or count values; rename them before analysis. Guide/gene IDs must have no whitespace. The helper rejects ambiguous sequences and any count/library ID or gene mismatch; resolve intentional multi-target guides explicitly upstream. These are deliberate helper restrictions; native MAGeCK also accepts other input variants.For FASTQ, inspect read structure and known guide sequences to establish trimming and orientation. Use MAGeCK
count, with one space-separated argument per biological sample; comma-join lanes only when they are technical replicates of that same sample. Preserve unmapped-read and count-summary evidence when mapping is poor. A zero-count guide remains in the library; do not drop it to improve QC.Run QC before statistical testing. Review library representation, median reads per guide, zero fractions, Gini coefficients, and within-condition replicate correlations. The helper's 10% zero and 0.8 correlation flags are review prompts, not universal acceptance thresholds. High correlation can coexist with systematic artifacts. Read depth is not experimental cell coverage. The helper uses a raw-count population Gini; MAGeCK's native count-summary Gini uses log(count + 1) with a finite-sample correction. Do not compare their values or thresholds as the same statistic.
Choose normalization based on the screen. Median normalization assumes most guides are stable. For a strong global shift, supplied validated negative-control guides may support
--normalization control. These must be guide IDs, one per line; a gene list is not interchangeable. Biological control samples and negative-control guides serve different roles. At least two controls must be present, and every guide assigned to a control gene must be designated a control. Supplying--control-guidesalso changes the RRA null distribution, even with median normalization. Record their origin and check their count distribution. MAGeCK 0.5.9.5 switches median normalization to total-count scaling for a zero median or more than 45% zero guides in any selected sample; for control normalization it evaluates the control-guide subset. Check the report's applied method, size factors, and warnings.Use
testfor a two-group comparison.--pairedrequires both lists in corresponding biological order and equal length; matching lengths alone do not establish pairing. The helper reports genes at the requested FDR in both directions and retains full rankings. For a multi-factor design, see references/design.md; do not collapse batches or time courses into an unjustified two-group test.Inspect guide concordance for leading genes, essential-gene recovery where appropriate, negative controls, replicate consistency, and copy-number artifacts in nuclease knockout screens. Report effect sizes alongside FDR. An enriched guide can indicate resistance, growth advantage, or a sampling artifact depending on the selection; depletion need not imply universal essentiality. Lack of replication or low-count guides weakens inference.
Commands
Run paths relative to the installed skill directory. Input and output paths refer to the user's analysis directory. The helper refuses to reuse an existing results directory.
# Single-end guide reads; trim and orientation must match the user's library preparation.
mageck count -l library.tsv --fastq c1.fastq.gz c2.fastq.gz t1.fastq.gz t2.fastq.gz \
--sample-label c1,c2,t1,t2 --trim-5 0 --norm-method none -n counts
python scripts/screen_analysis.py qc --counts counts.count.txt --library library.tsv \
--control c1 c2 --treatment t1 t2 --output qc.json
python scripts/screen_analysis.py test --counts counts.count.txt --library library.tsv \
--control c1 c2 --treatment t1 t2 --normalization median --fdr 0.05 --output resultThe FASTQ command structure was exercised with a synthetic two-guide library: counts of 30 and 12 were recovered exactly. A separate trimmed, reverse-complemented, two-lane fixture recovered 15, 7, and 0 reads. The two-group helper was exercised with 500 guides and two replicates per condition in unpaired and paired modes; known depleted and enriched genes ranked first in their respective directions and passed FDR 0.05. Sparse fixtures verified the total-normalization fallback. These tests establish execution and signal direction, not real-screen statistical calibration. Real-file paths above are illustrative.
result/report.json records count/library/control-guide SHA-256, control-guide IDs, MAGeCK version,
actual arguments, QC, applied normalization, warnings, hit direction, FDR, log2 fold change and rank.
The helper explicitly selects median guide LFC aggregation and --remove-zero both: all-zero
guides remain in the input/QC but are excluded from ranking. Native MAGeCK also skips NA/na
gene labels by default. The helper's --fdr filters completed gene results; it does not set MAGeCK's
--gene-test-fdr-threshold, which controls the RRA guide-selection cutoff. Negative and positive
FDRs are separate families; their union does not establish joint FDR control across directions or
across multiple contrasts. screen.gene_summary.txt, screen.sgrna_summary.txt, normalized
counts and the execution log retain the complete evidence. Include the original library, sample
sheet and negative-control list in the analysis handoff; the count checksum cannot reconstruct them.
Primary references
Files
- ATTRIBUTION.mdAdded by AutoGineer904 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md8.4 KiB
- references/design.md2.9 KiB
- references/runtime.md3.4 KiB
- scripts/screen_analysis.pyScript13.7 KiB
scripts/screen_analysis.py
"""Validate pooled-screen inputs, quantify QC, and execute MAGeCK RRA testing."""
from __future__ import annotations
import argparse
import csv
from collections import Counter
import hashlib
import itertools
import json
import math
from pathlib import Path
import re
import shutil
import statistics
import subprocess
import tempfile
def numeric_label(value):
"""Upstream guesses numeric headers as counts and integer labels as indices."""
try:
float(value)
return True
except ValueError:
return False
def validate_identifier(value):
if not value or any(c.isspace() for c in value):
raise ValueError("Guide and gene IDs must be nonempty and free of whitespace")
def read_counts(path):
with Path(path).open(newline="") as handle:
rows = list(csv.reader(handle, delimiter="\t"))
if len(rows) < 2 or len(rows[0]) < 4:
raise ValueError("Expected sgRNA, Gene, and at least two sample columns")
if [x.lower() for x in rows[0][:2]] != ["sgrna", "gene"]:
raise ValueError("Count table requires a header beginning sgRNA and Gene")
samples = rows[0][2:]
if len(set(samples)) != len(samples) or any(not x or ',' in x or any(c.isspace() for c in x) for x in samples):
raise ValueError("Sample labels must be unique, nonempty, and free of commas/whitespace")
if any(numeric_label(x) for x in samples):
raise ValueError("Numeric sample labels are ambiguous in MAGeCK; rename with a prefix such as sample_1")
guides, genes, counts = [], [], []
for line, row in enumerate(rows[1:], 2):
if len(row) != len(rows[0]) or not row[0] or not row[1]:
raise ValueError(f"Invalid row {line}: missing fields")
validate_identifier(row[0]); validate_identifier(row[1])
try:
values = [int(v) for v in row[2:]]
except ValueError as error:
raise ValueError(f"Row {line}: counts must be integers") from error
if min(values) < 0:
raise ValueError(f"Row {line}: negative count")
guides.append(row[0]); genes.append(row[1]); counts.append(values)
if len(set(guides)) != len(guides):
raise ValueError("Duplicate guide IDs")
if any(sum(col) == 0 for col in zip(*counts)):
raise ValueError("A sample has zero total reads")
return samples, guides, genes, counts
def read_library(path):
"""MAGeCK headerless tab-separated guide, sequence, gene library."""
library, sequences = {}, set()
with Path(path).open(newline="") as handle:
for line, row in enumerate(csv.reader(handle, delimiter="\t"), 1):
if len(row) != 3 or not all(row):
raise ValueError(f"Library row {line}: expected guide, sequence, gene (no header)")
guide, seq, gene = row
validate_identifier(guide); validate_identifier(gene)
seq = seq.upper()
if set(seq) - set("ACGT") or guide in library or seq in sequences:
raise ValueError(f"Library row {line}: invalid DNA, duplicate ID, or ambiguous sequence")
library[guide] = (seq, gene); sequences.add(seq)
if not library:
raise ValueError("Empty library")
return library
def gini(values):
ordered = sorted(values)
return 2 * sum(i * x for i, x in enumerate(ordered, 1)) / (len(ordered) * sum(ordered)) - (len(ordered) + 1) / len(ordered)
def correlation(a, b):
a = [math.log2(x + 1) for x in a]; b = [math.log2(x + 1) for x in b]
mean_a, mean_b = statistics.mean(a), statistics.mean(b)
ac = [x - mean_a for x in a]; bc = [x - mean_b for x in b]
denominator = math.sqrt(sum(x*x for x in ac) * sum(x*x for x in bc))
return sum(x*y for x, y in zip(ac, bc)) / denominator if denominator else None
def inspect_screen(count_path, control, treatment, library_path=None, controls_path=None, paired=False):
samples, guides, genes, counts = read_counts(count_path)
if not control or not treatment or len(set(control + treatment)) != len(control + treatment):
raise ValueError("Control and treatment must be nonempty, disjoint lists without duplicates")
if not set(control + treatment) <= set(samples):
raise ValueError("Unknown sample label in contrast")
if paired and len(control) != len(treatment):
raise ValueError("Paired contrasts need equal counts in matching biological order")
if library_path:
library = read_library(library_path)
if set(library) != set(guides):
raise ValueError("Count/library guide sets differ; retain zero-count library guides")
if any(library[g][1] != gene for g, gene in zip(guides, genes)):
raise ValueError("Count/library gene annotations differ")
control_guides = []
if controls_path:
control_guides = Path(controls_path).read_text().splitlines()
if not control_guides or len(set(control_guides)) != len(control_guides) or not set(control_guides) <= set(guides):
raise ValueError("Control-guide file must contain unique known IDs, one per line")
if len(control_guides) < 2:
raise ValueError("MAGeCK requires at least two control-guide IDs")
control_set = set(control_guides)
control_genes = {gene for guide, gene in zip(guides, genes) if guide in control_set}
if any(gene in control_genes and guide not in control_set for guide, gene in zip(guides, genes)):
raise ValueError("A gene cannot mix control and non-control guides in MAGeCK")
control_rows = [row for guide, row in zip(guides, counts) if guide in control_set]
if any(sum(col) == 0 for col in zip(*control_rows)):
raise ValueError("Control-guide counts are zero in a sample")
columns = dict(zip(samples, zip(*counts)))
qc = {s: {"reads": sum(v), "zero_fraction": v.count(0)/len(v),
"median_reads_per_guide": statistics.median(v), "gini": gini(v)} for s, v in columns.items()}
replicate_correlations = {f"{a} vs {b}": correlation(columns[a], columns[b])
for group in (control, treatment) for a, b in itertools.combinations(group, 2)}
guide_multiplicity = dict(Counter(genes))
warnings = []
if min(len(control), len(treatment)) < 2:
warnings.append("A condition lacks biological replication; dispersion and reproducibility are limited")
if any(v["zero_fraction"] > .1 for v in qc.values()):
warnings.append("More than 10% zero-count guides in a sample: review bottlenecks and mapping")
if any(v is not None and v < .8 for v in replicate_correlations.values()):
warnings.append("Low within-condition log-count correlation (<0.8): inspect replicate effects")
if any(v is None for v in replicate_correlations.values()):
warnings.append("Some replicate correlations are undefined because a sample has constant counts")
if min(guide_multiplicity.values()) < 3:
warnings.append("Some genes have fewer than three guides; inspect guide concordance")
return {"samples": qc, "guides": len(guides), "genes": len(guide_multiplicity),
"guides_per_gene": guide_multiplicity, "within_condition_log2_count_correlations": replicate_correlations,
"control": control, "treatment": treatment, "paired": paired,
"control_guides": len(control_guides), "warnings": warnings}
def normalization_evidence(log, requested, samples):
"""Extract applied scaling from the 0.5.9.5 log, including sparse-count fallback."""
matches = re.findall(r"Final size factor: ([^\r\n]+)", log)
factors = [float(x) for x in matches[-1].split()] if matches else []
if len(factors) != len(samples) or any(not math.isfinite(x) or x <= 0 for x in factors):
raise RuntimeError("Missing or invalid MAGeCK normalization factors; inspect execution.log")
fallback = "Switch to total read count normalization." in log
return {"requested_method": requested,
"effective_method": "total" if fallback else "median" if requested == "control" else requested,
"reference_guides": "control_guides" if requested == "control" else "all_guides",
"fallback_to_total": fallback,
"sample_size_factors": dict(zip(samples, factors)),
"warnings": [line for line in log.splitlines() if "WARNING" in line]}
def read_gene_hits(path, fdr):
hits = {"neg": [], "pos": []}
seen = set()
with Path(path).open() as handle:
rows = csv.DictReader(handle, delimiter="\t")
for row in rows:
gene = row["id"]
if not gene or gene in seen:
raise ValueError("Missing or duplicate gene in MAGeCK summary")
seen.add(gene)
for direction in hits:
qvalue = float(row[f"{direction}|fdr"])
lfc = float(row[f"{direction}|lfc"])
rank = int(row[f"{direction}|rank"])
if not math.isfinite(qvalue) or not 0 <= qvalue <= 1 or not math.isfinite(lfc) or rank < 1:
raise ValueError("Invalid FDR, effect size, or rank in MAGeCK summary")
if qvalue <= fdr:
hits[direction].append({"gene": gene, "fdr": qvalue, "lfc": lfc, "rank": rank})
if not seen:
raise ValueError("Empty MAGeCK gene summary")
return hits
def run_test(count_path, output, control, treatment, library_path=None, controls_path=None,
paired=False, normalization="median", executable="mageck", fdr=.05):
if not 0 < fdr < 1:
raise ValueError("FDR must lie between zero and one")
if normalization not in {"median", "total", "control", "none"}:
raise ValueError("Unsupported normalization")
if normalization == "control" and not controls_path:
raise ValueError("Control normalization requires control-guide IDs")
qc = inspect_screen(count_path, control, treatment, library_path, controls_path, paired)
binary = shutil.which(executable)
if binary is None:
raise RuntimeError("MAGeCK executable not found; install MAGeCK 0.5.9.5 and its RRA binary")
output = Path(output)
output.mkdir(parents=True, exist_ok=False)
version = subprocess.run([binary, "--version"], text=True, capture_output=True, check=True).stdout.strip()
# Upstream uses shell commands internally. Fixed staging names avoid its path quoting problems.
with tempfile.TemporaryDirectory(prefix="mageck-analysis-") as temporary:
work = Path(temporary)
shutil.copyfile(count_path, work / "counts.tsv")
command = [binary, "test", "-k", "counts.tsv", "-c", ",".join(control), "-t", ",".join(treatment),
"--norm-method", normalization, "--normcounts-to-file", "--gene-lfc-method", "median",
"--remove-zero", "both", "-n", "screen"]
if paired:
command.append("--paired")
if controls_path:
shutil.copyfile(controls_path, work / "controls.txt")
command += ["--control-sgrna", "controls.txt"]
process = subprocess.run(command, cwd=work, capture_output=True, text=True, check=False)
log = process.stdout + process.stderr
(output / "execution.log").write_text(log)
for artifact in work.glob("screen.*"):
if artifact.is_file():
shutil.copyfile(artifact, output / artifact.name)
if process.returncode or not (output / "screen.gene_summary.txt").is_file():
raise RuntimeError(f"MAGeCK did not complete; inspect {output / 'execution.log'}")
# 0.5.9.5 normalizes cttab_sel in selected_samples_id = controlgroup + treatgroup
# order before any paired-guide expansion, rather than in original count-column order.
normalization_info = normalization_evidence(log, normalization, control + treatment)
hits = read_gene_hits(output / "screen.gene_summary.txt", fdr)
report = {"mageck_version": version, "command": command, "count_sha256": hashlib.sha256(Path(count_path).read_bytes()).hexdigest(),
"library_sha256": hashlib.sha256(Path(library_path).read_bytes()).hexdigest() if library_path else None,
"control_guides_sha256": hashlib.sha256(Path(controls_path).read_bytes()).hexdigest() if controls_path else None,
"control_guide_ids": Path(controls_path).read_text().splitlines() if controls_path else [],
"normalization": normalization_info, "fdr_threshold": fdr, "qc": qc, "hits": hits}
(output / "report.json").write_text(json.dumps(report, indent=2) + "\n")
return report
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("mode", choices=["qc", "test"])
parser.add_argument("--counts", required=True, type=Path)
parser.add_argument("--control", nargs="+", required=True)
parser.add_argument("--treatment", nargs="+", required=True)
parser.add_argument("--library", type=Path)
parser.add_argument("--control-guides", type=Path)
parser.add_argument("--paired", action="store_true")
parser.add_argument("--normalization", choices=["median", "total", "control", "none"], default="median")
parser.add_argument("--output", type=Path, help="New directory for test output; JSON path for QC")
parser.add_argument("--mageck", default="mageck")
parser.add_argument("--fdr", type=float, default=.05)
args = parser.parse_args()
if args.mode == "test":
if args.output is None:
parser.error("test requires --output")
report = run_test(args.counts, args.output, args.control, args.treatment, args.library,
args.control_guides, args.paired, args.normalization, args.mageck, args.fdr)
else:
report = inspect_screen(args.counts, args.control, args.treatment, args.library, args.control_guides, args.paired)
if args.output:
args.output.write_text(json.dumps(report, indent=2) + "\n")
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Python
The author says: Requires Python 3.10+ for the helper and MAGeCK 0.5.9.5 with its compiled RRA executable for analysis. Tested runtime uses Python 3.11, NumPy 1.26.4 and SciPy 1.13.1. Source installation needs a C++ compiler; network is needed only for installation. No credentials.
Security
What our scanner noticed· Low risk
- Instructions that use the network
- Scripts that your agent may run
This skill includes scripts that your agent may run. Read them before you use it.
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- K-Dense Inc.
- Publisher
- K-Dense (Community)
- Source
- K-Dense-AI/scientific-agent-skills · skills/mageck · commit a25cf9e
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE.md)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by K-Dense Inc. or K-Dense.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download mageck.zip