# Cell Type Annotation

> Generate code to assign cell type labels to single-cell RNA-seq clusters using CellTypist, SingleR, marker-based annotation, or reference label transfer (scANVI/ingest). Triggers on requests to "annotate cell types", "label clusters", "run CellTypist", "SingleR annotation", "marker gene dotplot", "transfer labels from reference atlas", "cell identity", "automated annotation", "reference mapping",…

- **Type:** Skill
- **Install:** `agentstack add skill-awslabs-hcls-agent-skills-cell-type-annotation`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [awslabs](https://agentstack.voostack.com/s/awslabs)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT-0
- **Upstream author:** [awslabs](https://github.com/awslabs)
- **Source:** https://github.com/awslabs/hcls-agent-skills/tree/main/skills/cell-type-annotation

## Install

```sh
agentstack add skill-awslabs-hcls-agent-skills-cell-type-annotation
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Cell Type Annotation

## Overview

This pipeline skill generates code for annotating cell types in single-cell RNA-seq data. It covers four complementary approaches:

1. **Automated** — CellTypist (logistic-regression classifiers trained on curated atlases).
2. **Reference-based** — SingleR (R) or scANVI/`sc.tl.ingest` (Python) label transfer.
3. **Marker-based** — Manual assignment from canonical marker gene panels.
4. **Hierarchical** — Coarse compartment assignment followed by specialized fine-grained annotation.

Use it when the user has a clustered `AnnData` (or `SingleCellExperiment`) and needs cell-type labels in `adata.obs`.

## Usage

### Decision Tree: Choosing an Annotation Approach

Follow this decision tree to select the right method:

1. **Is there a CellTypist model matching your tissue and species?**
   - YES → Use CellTypist (Steps 1–6 below)
   - NO → Go to step 2
2. **Do you have a labeled reference AnnData from the same tissue?**
   - YES, same batch/technology → Use `sc.tl.ingest` (Step 12)
   - YES, different batches → Use scANVI label transfer (Step 13)
   - NO → Go to step 3
3. **Are you working in R with bulk or sorted-cell references?**
   - YES → Use SingleR (Steps 7–9)
   - NO → Go to step 4
4. **Do you have canonical marker gene panels for expected cell types?**
   - YES → Use marker-based annotation (Steps 10–11)
   - NO → Start with CellTypist's broadest model (`Immune_All_Low.pkl` or `Developing_Human_Brain.pkl`), then refine with markers

### Annotation Workflow (15 Steps)

**Step 1 — Confirm normalization.** CellTypist requires `log1p(CP10k)`. Check `adata.uns['log1p']` exists or run normalization. If data is in `adata.raw` or a layer, subset appropriately.

**Step 2 — Verify gene symbols.** Confirm `adata.var_names` are HGNC (human) or MGI (mouse) symbols, not Ensembl IDs. Convert if needed with `sc.queries.biomart_annotations`.

**Step 3 — Select CellTypist model.** Match species + tissue. Use `celltypist.models.models_description()` to list options. If unsure, start with the broadest model for the compartment.

**Step 4 — Run CellTypist annotation.** Use `celltypist.annotate()` with `majority_voting=True` and appropriate `p_thres` (default 0.5; raise to 0.7 for stringent calls).

**Step 5 — Extract results via `to_adata()`.** Call `predictions.to_adata()` to get annotations in `.obs`. Access confidence via `adata_result.obs['conf_score']`.

**Step 6 — Filter low-confidence cells.** Mask cells with `conf_score 30%` of cells get `conf_score 80%` of cells unexpectedly, suspect wrong model or un-normalized data.
- At Step 12: if query UMAP doesn't align with reference after ingest, batch effects are too strong → switch to scANVI (Step 13).
- At Step 14: if proportions are biologically implausible (e.g., 60% fibroblasts in PBMC), re-examine normalization and model choice.

## Response Format

- Lead with the command or code the user needs — explain after.
- Structure as: confirm inputs → working code → key parameters explained → gotchas.
- One complete working example per task; do not show every alternative.
- Keep code comments minimal and functional.
- Target: 50–100 lines of code with brief surrounding explanation.
- Always include confidence score extraction and a filtering step.

## Core Concepts

### 1. CellTypist (automated, Python)

```python
import scanpy as sc
import celltypist
from celltypist import models

# Input: log1p-normalized to 10,000 counts/cell
sc.pp.normalize_total(adata, target_sum=1e4)
sc.pp.log1p(adata)

# Download models (first run only)
models.download_models()
print(models.models_description())  # list available models

# Load tissue-matched model
model = models.Model.load(model='Immune_All_Low.pkl')

# Annotate with majority voting
predictions = celltypist.annotate(
    adata,
    model=model,
    majority_voting=True,       # smooth labels over neighborhood graph
    over_clustering='leiden',   # obs key for majority voting resolution
    p_thres=0.5,               # minimum probability threshold (raise for stringency)
)

# Extract results — modern API (CellTypist >=1.3)
adata_result = predictions.to_adata()
# Annotations now in adata_result.obs:
#   'predicted_labels'        — per-cell raw predictions
#   'majority_voting'         — smoothed labels
#   'conf_score'              — max probability per cell

# Transfer to original adata
adata.obs['cell_type'] = adata_result.obs['majority_voting']
adata.obs['cell_type_conf'] = adata_result.obs['conf_score']

# Filter low-confidence assignments
adata.obs.loc[adata.obs['cell_type_conf']  3× literature range | Suspect wrong model or normalization error |

## Common Mistakes

1. **Wrong:** Feeding raw counts to CellTypist
   **Right:** Always run `sc.pp.normalize_total(adata, target_sum=1e4)` + `sc.pp.log1p(adata)` before annotation
   **Why:** CellTypist expects log1p of counts normalized to 10,000/cell — raw or SCTransform'd data produces nonsense labels

2. **Wrong:** Using a reference model that doesn't match the tissue or species
   **Right:** Match species (`Human_*` vs `Mouse_*`) and tissue type when selecting CellTypist models or SingleR references
   **Why:** Using `Immune_All_Low` on epithelial tumor cells or `HumanPrimaryCellAtlasData` on mouse data produces confident but wrong labels

3. **Wrong:** Passing Ensembl IDs or mixed-case gene symbols to CellTypist/SingleR
   **Right:** Convert `adata.var_names` to HGNC (human) or MGI (mouse) symbols before annotation
   **Why:** Ensembl IDs or wrong case (`Cd3d` vs `CD3D`) silently drop features, degrading model performance without warning

4. **Wrong:** Using `predictions.probability_matrix.max(axis=1)` to get confidence scores
   **Right:** Use `predictions.to_adata().obs['conf_score']` which is the stable API since CellTypist ≥1.3
   **Why:** The probability matrix approach is fragile and version-dependent — it may break or return incorrect values across updates

5. **Wrong:** Assigning a rare subtype label to a cluster of fewer than 20 cells
   **Right:** Collapse to the parent cell type or label as `'Unknown'` when cluster size is below 20 cells
   **Why:** Rare subtype assignments on tiny clusters lack statistical power and are unreliable without strong distinguishing markers

6. **Wrong:** Forcing a label on clusters that lack clear markers after dotplot review
   **Right:** Keep ambiguous clusters as `'Unknown'` rather than picking the next-best guess
   **Why:** Forced labels propagate errors into downstream analyses (DE, trajectory) and create false biological narratives

7. **Wrong:** Running CellTypist with `majority_voting=False` and using per-cell labels directly
   **Right:** Always enable `majority_voting=True` to smooth labels over the local neighborhood graph
   **Why:** Per-cell predictions are noisy; majority voting leverages cluster structure to produce coherent, stable annotations

8. **Wrong:** Running `sc.tl.ingest` for label transfer without batch correction
   **Right:** Integrate query and reference first, or use scANVI's `load_query_data` path which handles batch natively
   **Why:** `ingest` assumes query and reference share the same embedding — batch effects cause misalignment and wrong label transfers

9. **Wrong:** Not validating cell-type proportions against biological expectations
   **Right:** Always cross-check per-sample cell-type proportions against known tissue composition
   **Why:** A PBMC sample with 80% fibroblasts is a red flag indicating wrong model, normalization error, or data quality issues

10. **Wrong:** Annotating at one resolution only without hierarchical refinement
    **Right:** Annotate coarse compartments first (immune/stromal/epithelial), then refine each with specialized models or markers
    **Why:** Fine labels on poorly separated clusters are unstable — hierarchical annotation produces more reliable results

## References

- CellTypist: Dominguez Conde et al. Science 2022, https://doi.org/10.1126/science.abl5197
- SingleR: Aran et al. Nat Immunol 2019, https://doi.org/10.1038/s41590-018-0276-y
- scANVI: Xu et al. Mol Syst Biol 2021, https://doi.org/10.15252/msb.20209620
- celldex: Aran et al. 2019, https://bioconductor.org/packages/celldex

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [awslabs](https://github.com/awslabs)
- **Source:** [awslabs/hcls-agent-skills](https://github.com/awslabs/hcls-agent-skills)
- **License:** MIT-0

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-awslabs-hcls-agent-skills-cell-type-annotation
- Seller: https://agentstack.voostack.com/s/awslabs
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
