Featurecounts Rna Counting logo

Featurecounts Rna Counting

Community
jaechang-hits
featurecounts-rna-counting

Counts RNA-seq reads overlapping GTF gene features. Takes sorted STAR BAMs plus GTF; outputs a per-gene tab-delimited matrix across samples. Handles strandedness (0/1/2), paired-end, multi-sample batch counting in one command, and outputs assignment statistics. Use Salmon for alignment-free quantification; use featureCounts when STAR BAMs already exist.

Overview

Publisherjaechang-hits
RepositorySciAgent-Skills
Skill namefeaturecounts-rna-counting
Stars
381
Forks
45
Bundled files
Instructions only
LicenseGPL-3.0
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • Self-contained

    Everything the model needs lives in the instructions — no extra files to sync.

  • Open source

    Published by jaechang-hits on GitHub. Read the source before you install it.

Installation

Install the Featurecounts Rna Counting AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
    https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/genomics-bioinformatics/rnaseq/featurecounts-rna-counting
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/jaechang-hits/SciAgent-Skills.git /tmp/SciAgent-Skills
mkdir -p .claude/skills
cp -r /tmp/SciAgent-Skills/skills/genomics-bioinformatics/rnaseq/featurecounts-rna-counting .claude/skills/featurecounts-rna-counting
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Featurecounts Rna Counting in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Featurecounts Rna Counting on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Featurecounts Rna Counting is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

featureCounts — RNA-seq Read Counting

Overview

featureCounts (part of the Subread package) assigns sequencing reads in BAM files to genomic features defined in a GTF/GFF annotation. It counts how many reads overlap each gene (or exon, intron, or custom feature), producing a gene × sample count matrix suitable for differential expression analysis with DESeq2 or edgeR. featureCounts processes multiple BAM files in a single command, reporting read assignment statistics (assigned, unassigned by category) alongside the count matrix. It is the standard counting step after STAR alignment in RNA-seq pipelines.

When to Use

  • Generating gene-level count matrices from STAR-aligned BAM files for DESeq2 or edgeR
  • Counting reads from multiple samples simultaneously in a single featureCounts command
  • Handling stranded RNA-seq libraries where sense/antisense assignment matters
  • Producing exon-level or custom-feature counts (e.g., for splicing analysis with DEXSeq)
  • Verifying strandedness of an RNA-seq library when protocol documentation is unavailable
  • Use Salmon instead when no BAM file exists and fast pseudoalignment is preferred
  • Use HTSeq-count as an alternative with slower but more flexible counting modes

Prerequisites

  • Software: Subread package (contains featureCounts)
  • Input: Sorted BAM files from STAR or HISAT2, plus a matching GTF annotation file

Check before installing: The tool may already be available in the current environment (e.g., inside a pixi / conda env). Run command -v featureCounts first and skip the install commands below if it returns a path. When running inside a pixi project, invoke the tool via pixi run featureCounts rather than bare featureCounts.

bash
# Install with conda (recommended)
conda install -c bioconda subread

# Verify
featureCounts -v
# featureCounts v2.0.6

# Alternative: install via apt (Ubuntu/Debian)
sudo apt-get install subread

Pre-flight Interview

Settle these with the user before writing any analysis code.

yaml
decisions:
  - id: D1
    param: annotation
    kind: required
    source: upstream
    ask: "Which GTF/GFF annotation file should be used, and does its assembly exactly match the BAM alignment reference?"
    default: null

  - id: D2
    param: strandSpecific
    kind: required
    source: data
    ask: "Which strandedness did the representative-alignment check infer, and does it agree with the library preparation?"
    default: null

  - id: D3
    param: -t, -g
    kind: optional
    source: user
    ask: "Should expression be summarized from exons to genes, or from another feature type for a specific downstream question?"
    default: "-t exon -g gene_id"

  - id: D4
    param: -M, -O
    kind: optional
    source: user
    ask: "Should reads with multiple genomic mappings or overlapping gene assignments be included in the count matrix?"
    default: "exclude both multi-mappers and multi-overlap reads"

  - id: D5
    param: --minOverlap, --fracOverlap
    kind: optional_conditional
    source: user
    ask: "Does the assay or feature definition require a minimum overlap stricter than one aligned base?"
    default: "--minOverlap 1 --fracOverlap 0"

Incorrect library strandedness can substantially reduce or misassign counts; the magnitude varies by gene and annotation, so infer it from the data and treat an ambiguous result as a QC failure. Enabling multi-mapper counting can inflate counts for paralogs and repeat-associated genes. Neither setting necessarily produces a software error.

Quick Start

bash
# Count reads for multiple samples (unstranded paired-end RNA-seq)
featureCounts \
    -a gencode.v47.annotation.gtf \
    -o counts/gene_counts.txt \
    -T 8 \
    -p --countReadPairs \
    results/sample1/Aligned.sortedByCoord.out.bam \
    results/sample2/Aligned.sortedByCoord.out.bam

echo "Count matrix: counts/gene_counts.txt"
head -3 counts/gene_counts.txt

Workflow

Step 1: Prepare BAM Files and GTF

Ensure BAM files are sorted and indexed, and the GTF matches the genome assembly.

bash
# Verify BAM files are sorted
samtools view -H results/sample1/Aligned.sortedByCoord.out.bam | grep "SO:"
# Expected: SO:coordinate

# List BAMs to count
ls results/*/Aligned.sortedByCoord.out.bam | head -5

# Download GENCODE GTF (same version used for STAR indexing)
wget https://ftp.ebi.ac.uk/pub/databases/gencode/Gencode_human/release_47/gencode.v47.primary_assembly.annotation.gtf.gz
gunzip gencode.v47.primary_assembly.annotation.gtf.gz

echo "GTF lines: $(wc -l < gencode.v47.primary_assembly.annotation.gtf)"

Step 2: Determine Library Strandedness

Test strandedness using a small read count to set the -s parameter correctly.

bash
# Quick strandedness check: count 1 sample with all 3 modes
# Compare assigned rates: highest = correct mode
for strand in 0 1 2; do
    echo "=== Strandedness -s $strand ==="
    featureCounts \
        -a gencode.v47.primary_assembly.annotation.gtf \
        -o /tmp/test_s${strand}.txt \
        -T 4 \
        -p --countReadPairs \
        -s $strand \
        results/sample1/Aligned.sortedByCoord.out.bam 2>&1 \
        | grep "Successfully assigned"
done
# Rule: 0=unstranded if similar rates; 1 or 2 if one is much higher

Step 3: Count Unstranded Paired-End RNA-seq

Standard configuration for unstranded libraries (most polyA-selected RNA-seq).

bash
mkdir -p counts

# Multi-sample batch counting: pass all BAMs as positional arguments
featureCounts \
    -a gencode.v47.primary_assembly.annotation.gtf \
    -o counts/gene_counts.txt \
    -T 8 \
    -p \
    --countReadPairs \
    -s 0 \
    -t exon \
    -g gene_id \
    results/ctrl_1/Aligned.sortedByCoord.out.bam \
    results/ctrl_2/Aligned.sortedByCoord.out.bam \
    results/treat_1/Aligned.sortedByCoord.out.bam \
    results/treat_2/Aligned.sortedByCoord.out.bam

echo "Count matrix: $(wc -l < counts/gene_counts.txt) genes"
# Also generates: counts/gene_counts.txt.summary (assignment stats)
cat counts/gene_counts.txt.summary

Step 4: Count Stranded Libraries

For strand-specific libraries (TruSeq Stranded, QuantSeq), set the correct strandedness.

bash
# Reverse-stranded library (most TruSeq Stranded protocols): -s 2
featureCounts \
    -a gencode.v47.primary_assembly.annotation.gtf \
    -o counts/gene_counts_stranded.txt \
    -T 8 \
    -p --countReadPairs \
    -s 2 \
    results/*/Aligned.sortedByCoord.out.bam

# Forward-stranded (e.g., Lexogen QuantSeq, Takara SMARTer): -s 1
# featureCounts ... -s 1 ...

echo "Stranded count complete."
head -2 counts/gene_counts_stranded.txt

Step 5: Load Count Matrix into Python for DESeq2

Parse the featureCounts output file and prepare for differential expression.

python
import pandas as pd

# featureCounts output has 6 metadata columns before count columns
counts_raw = pd.read_csv("counts/gene_counts.txt", sep="\t", comment="#")
print(f"Columns: {list(counts_raw.columns)}")

# Metadata columns: Geneid, Chr, Start, End, Strand, Length
# Count columns start at index 6
count_cols = counts_raw.columns[6:]  # BAM file paths as column names
counts = counts_raw.set_index("Geneid")[count_cols].copy()

# Rename columns to sample names (strip path and file extension)
import re
counts.columns = [re.sub(r".*/|Aligned\.sortedByCoord\.out\.bam", "", col)
                  for col in counts.columns]

print(f"Count matrix shape: {counts.shape}")  # (genes × samples)
print(f"Samples: {list(counts.columns)}")
print(f"Genes with counts > 0: {(counts.sum(axis=1) > 0).sum()}")
counts.to_csv("gene_count_matrix.tsv", sep="\t")
print("Saved: gene_count_matrix.tsv")

Step 6: Run DESeq2 with featureCounts Matrix

Use the count matrix directly in pydeseq2 for differential expression.

python
import pandas as pd
from pydeseq2.dds import DeseqDataSet
from pydeseq2.default_inference import DefaultInference
from pydeseq2.ds import DeseqStats

# Load count matrix (genes × samples)
counts = pd.read_csv("gene_count_matrix.tsv", sep="\t", index_col=0).T
print(f"Count matrix: {counts.shape} (samples × genes)")

# Sample metadata
metadata = pd.DataFrame({
    "condition": ["control", "control", "treated", "treated"]
}, index=counts.index)

# Filter low-count genes (recommended before DESeq2)
counts_filtered = counts.loc[:, counts.sum() > 10]
print(f"Genes after low-count filter: {counts_filtered.shape[1]}")

# Run DESeq2
dds = DeseqDataSet(counts=counts_filtered, metadata=metadata,
                   design_factors="condition",
                   inference=DefaultInference(n_cpus=8))
dds.deseq2()

stat_res = DeseqStats(dds, contrast=["condition", "treated", "control"],
                      inference=DefaultInference())
stat_res.summary()
results = stat_res.results_df
sig = results[results["padj"] < 0.05]
print(f"DE genes (padj < 0.05): {len(sig)}")
print(sig.sort_values("log2FoldChange", ascending=False).head())

Key Parameters

ParameterDefaultRange/OptionsEffect
-arequiredGTF/GFF3 pathAnnotation file; must match genome assembly used for alignment
-orequiredfile pathOutput count table path (also creates <output>.summary)
-T11–64CPU threads; 8–16 is typical
-s00 (unstranded), 1 (stranded), 2 (reverse-stranded)Library strandedness; wrong value causes major undercounting
-poffflagPaired-end mode; reads counted as fragments not individual reads
--countReadPairsoffflagFor PE: count pairs not reads (use with -p)
-texonfeature type stringFeature type to count from GTF column 3
-ggene_idattribute stringGTF attribute to group features (use gene_id for genes)
--minOverlap11–100Minimum bases a read must overlap a feature to be counted
--fracOverlap00–1Fraction of read that must overlap; 0.2 for stricter counting
-OoffflagAllow reads to be assigned to multiple overlapping features
-MoffflagCount multi-mapping reads (default: only uniquely mapped)

Common Recipes

Recipe 1: Count with Subread Package via Python subprocess

python
import subprocess
import re
from pathlib import Path

def run_featurecounts(bam_files: list, gtf: str, outfile: str,
                      threads: int = 8, strandedness: int = 0,
                      paired_end: bool = True) -> dict:
    """Run featureCounts and return assignment statistics."""
    cmd = [
        "featureCounts",
        "-a", gtf,
        "-o", outfile,
        "-T", str(threads),
        "-s", str(strandedness),
        "-t", "exon",
        "-g", "gene_id",
    ]
    if paired_end:
        cmd += ["-p", "--countReadPairs"]
    cmd += bam_files

    result = subprocess.run(cmd, capture_output=True, text=True)

    # Parse summary from stderr
    stats = {}
    for line in result.stderr.splitlines():
        if "Assigned" in line:
            stats["assigned_pct"] = float(re.search(r"(\d+\.\d+)%", line).group(1))
    return stats

bams = list(Path("results").glob("*/Aligned.sortedByCoord.out.bam"))
bam_list = [str(b) for b in sorted(bams)]
stats = run_featurecounts(bam_list, "gencode.v47.primary_assembly.annotation.gtf",
                          "counts/gene_counts.txt")
print(f"Assigned reads: {stats.get('assigned_pct', 'N/A')}%")

Recipe 2: Add featureCounts to a Snakemake Pipeline

python
# Snakefile — featureCounts rule after STAR alignment
configfile: "config.yaml"
SAMPLES = config["samples"]

rule featurecounts:
    input:
        bams = expand("results/{sample}/Aligned.sortedByCoord.out.bam", sample=SAMPLES),
        gtf = config["gtf"]
    output:
        counts = "counts/gene_counts.txt",
        summary = "counts/gene_counts.txt.summary"
    params:
        strandedness = config.get("strandedness", 0)
    threads: 8
    shell:
        """
        featureCounts \
            -a {input.gtf} \
            -o {output.counts} \
            -T {threads} \
            -p --countReadPairs \
            -s {params.strandedness} \
            -t exon -g gene_id \
            {input.bams}
        """

Expected Outputs

OutputFormatDescription
gene_counts.txtTSVCount matrix: gene metadata + one count column per BAM
gene_counts.txt.summaryTSVRead assignment statistics per sample (Assigned, Unassigned_*)
stderr logTextPer-sample assignment percentages and warnings

Troubleshooting

ProblemCauseSolution
Very low assigned rate (< 40%)Wrong strandedness -s valueTest all 3 -s modes; match to library prep protocol
GTF not matching genomeDifferent assembly or annotation versionVerify genome + GTF are same version (e.g., both GRCh38/GENCODE v47)
Error: Failed to open the annotation fileGTF file path wrong or compressedDecompress GTF; use absolute path
Count matrix has 0 for all genesWrong -t feature typeCheck GTF column 3 with awk '{print $3}' file.gtf | sort -u | head
Multi-mapping reads not counted-M not setAdd -M to count multi-mappers; may inflate counts for repetitive regions
Paired-end reads counted as single-p flag missingAdd -p --countReadPairs for paired-end BAMs
Very slow on large BAM filesLow thread countIncrease -T to 8–16; ensure BAMs are sorted by coordinate
gene_id attribute missingGFF3 file uses different attributeUse -g ID for GFF3; check attributes with grep -v "^#" file.gff3 | head -5

References

Frequently asked questions

What does the Featurecounts Rna Counting AI skill do?

Counts RNA-seq reads overlapping GTF gene features. Takes sorted STAR BAMs plus GTF; outputs a per-gene tab-delimited matrix across samples. Handles strandedness (0/1/2), paired-end, multi-sample batch counting in one command, and outputs assignment statistics. Use Salmon for alignment-free quantification; use featureCounts when STAR BAMs already exist.

Why use Featurecounts Rna Counting on TypingMind?

Because you install it once and use it with any model. Featurecounts Rna Counting is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Featurecounts Rna Counting in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/jaechang-hits/SciAgent-Skills/tree/main/skills/genomics-bioinformatics/rnaseq/featurecounts-rna-counting. TypingMind reads its SKILL.md and installs it as a skill you can enable per chat.

Which AI models can use Featurecounts Rna Counting?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Featurecounts Rna Counting?

As many as you like. As long as a model supports skills, you can use Featurecounts Rna Counting with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Featurecounts Rna Counting AI skill free?

Yes. It is published on GitHub by jaechang-hits under the GPL-3.0 license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇