Getting Started with scPassport

Sedat Kacar

Indiana University

2026-04-02

Introduction

scPassport solves a common problem in single-cell RNA-seq analysis: Seurat objects accumulate complex processing histories, but that context disappears once collaborators open the .rds file.

This package embeds a persistent metadata passport directly inside @misc$passport of every Seurat object. Because the passport travels inside the .rds file, there are no external spreadsheets to lose track of.

The package provides three functions:

Function Purpose
scPassport() Open the Shiny popup to fill or update a passport
read_passport() Print the full passport and processing log to console
log_step() Append a processing step to the object’s log

Installation

# From Bioconductor (once accepted):
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
BiocManager::install("scPassport")

# Development version from GitHub:
# devtools::install_github("sedatkacar56/scPassport")

Quick Start with SummarizedExperiment

The following examples use a minimal SummarizedExperiment object and run without any external data. The same functions work identically with Seurat and SingleCellExperiment objects.

Load the package

library(scPassport)

Create a minimal object

se <- SummarizedExperiment::SummarizedExperiment()
se
#> class: SummarizedExperiment 
#> dim: 0 0 
#> metadata(0):
#> assays(0):
#> rownames: NULL
#> rowData names(0):
#> colnames: NULL
#> colData names(0):

Check passport on unstamped object

# Before stamping — prints "No passport found"
read_passport(se)
#> No passport found. Use scPassport() to create one.

Log processing steps

# Log a quality control step
se <- log_step(se, "QC filter", params = list(min_cells = 3))

# Log a normalization step
se <- log_step(se, "Normalization", params = list(method = "LogNormalize"))

# Log a dimension reduction step
se <- log_step(se, "PCA", params = list(npcs = 30))

Read the processing log

# Now read_passport shows the processing log
read_passport(se)
#> No passport found. Use scPassport() to create one.

Stamping with interactive popup (Seurat workflow)

The scPassport() function opens an interactive Shiny popup. This requires an existing Seurat object in your R session.

# Stamp a root object
WTHeme <- scPassport(WTHeme)

# Stamp a child subset, linking lineage to parent automatically
EndofrHeme <- subset(WTHeme, idents = "Endothelial")
EndofrHeme <- scPassport(EndofrHeme, parent = WTHeme)

# Read passport
read_passport(WTHeme)
scPassport(WTHeme, read = TRUE)

Example output:

========== PASSPORT ==========
Object ID  : WTHeme
RDS Self   : 224
Created    : 2026-03-19 05:00:00
-------- Animal --------
Animal ID  : M01
Species    : Mus musculus
Sex        : male
Age        : P60
Condition  : control
Tissue     : lung
-------- Experiment --------
Project    : memory_study
Researcher : Sedat Kacar
Date       : 2026-03-19
Notes      : First sequencing run
-------- Lineage --------
Parent     : root
RDS Parent : root
Chain      : root
Children   : EndofrHeme224, gCapC
RDS Children: 225, 226
======= PROCESSING LOG =======
No processing steps logged yet.
==============================

Logging Processing Steps

Use log_step() after each major processing step. This creates an auditable record of what was done to the object, with timestamps and cell counts.

library(Seurat)
WTHeme <- NormalizeData(WTHeme)
WTHeme <- log_step(WTHeme, "NormalizeData",
                   params = list(method = "LogNormalize", scale_factor = 10000))
WTHeme <- RunPCA(WTHeme, npcs = 30)
WTHeme <- log_step(WTHeme, "RunPCA", params = list(npcs = 30))
read_passport(WTHeme)

The processing log is visible at the bottom of read_passport() output:

======= PROCESSING LOG =======
[1] NormalizeData             | 8423 cells | 2026-03-19 05:01:00
[2] FindVariableFeatures      | 8423 cells | 2026-03-19 05:01:05
[3] ScaleData                 | 8423 cells | 2026-03-19 05:01:20
[4] RunPCA                    | 8423 cells | 2026-03-19 05:01:45
==============================

Custom Fields

The Shiny popup includes a Custom Fields section where you can add any extra key-value pairs. These are stored alongside the standard fields and printed by read_passport().

For example, you might add: - sequencing_platform = 10x Chromium v3 - genome_build = mm10 - batch = batch_01

Custom fields from a previous passport are automatically pre-loaded when you re-open the popup, so you only update what changed.

Passport Fields Reference

Identity

Field Description Example
object_id Name/ID of this object "WTHeme"
rds_self RDS registry number "224"
created Timestamp of stamping auto-filled

Animal Info

Field Description Example
animal_id Individual animal ID "M01"
species Species "Mus musculus"
sex Sex "male"
age Age "P60"
condition Experimental condition "control"
tissue Tissue of origin "lung"

Experiment Info

Field Description Example
project Project name "memory_study"
researcher Researcher name "Sedat Kacar"
date Experiment date "2026-03-19"
notes Free-text notes any string

Lineage

Field Description
parent_id Object ID of the direct parent (or "root")
rds_parent RDS number of the parent (or "root")
lineage Full ancestry chain as a character vector
children Object IDs of children subset from this object
rds_children RDS numbers of children

Session Info

sessionInfo()
#> R version 4.6.0 alpha (2026-03-30 r89742)
#> Platform: x86_64-pc-linux-gnu
#> Running under: Ubuntu 24.04.4 LTS
#> 
#> Matrix products: default
#> BLAS:   /home/biocbuild/bbs-3.23-bioc/R/lib/libRblas.so 
#> LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.12.0  LAPACK version 3.12.0
#> 
#> locale:
#>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#>  [3] LC_TIME=en_GB              LC_COLLATE=C              
#>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#>  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
#> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
#> 
#> time zone: America/New_York
#> tzcode source: system (glibc)
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] scPassport_0.99.2
#> 
#> loaded via a namespace (and not attached):
#>  [1] Matrix_1.7-5                miniUI_0.1.2               
#>  [3] jsonlite_2.0.0              compiler_4.6.0             
#>  [5] promises_1.5.0              Rcpp_1.1.1                 
#>  [7] SummarizedExperiment_1.41.1 Biobase_2.71.0             
#>  [9] GenomicRanges_1.63.1        later_1.4.8                
#> [11] jquerylib_0.1.4             IRanges_2.45.0             
#> [13] Seqinfo_1.1.0               yaml_2.3.12                
#> [15] fastmap_1.2.0               lattice_0.22-9             
#> [17] mime_0.13                   XVector_0.51.0             
#> [19] R6_2.6.1                    S4Arrays_1.11.1            
#> [21] generics_0.1.4              knitr_1.51                 
#> [23] BiocGenerics_0.57.0         DelayedArray_0.37.1        
#> [25] MatrixGenerics_1.23.0       shiny_1.13.0               
#> [27] bslib_0.10.0                rlang_1.1.7                
#> [29] cachem_1.1.0                httpuv_1.6.17              
#> [31] xfun_0.57                   sass_0.4.10                
#> [33] otel_0.2.0                  SparseArray_1.11.13        
#> [35] cli_3.6.5                   magrittr_2.0.4             
#> [37] grid_4.6.0                  digest_0.6.39              
#> [39] xtable_1.8-8                lifecycle_1.0.5            
#> [41] S4Vectors_0.49.0            evaluate_1.0.5             
#> [43] abind_1.4-8                 stats4_4.6.0               
#> [45] rmarkdown_2.31              matrixStats_1.5.0          
#> [47] tools_4.6.0                 htmltools_0.5.9