sessionstate() captures a point-in-time, human-readable snapshot of the R
session: platform details, selected machine information, session timing,
an inventory of attached and loaded-namespace packages (including remote
source tracking for packages installed from GitHub), the contents of the
global environment, and the non-package entries on the search path. It is
intended as a companion to sessioncheck(): where sessioncheck() is
typically called at the start of a script to check for a clean session,
sessionstate() is intended to be called at the end of a script to
produce an audit log of the environment the script actually ran in.
Value
An object of class sessioncheck_sessionstate, a list with
elements platform, locale, matrix, document, machine, git,
timing, rng, libpaths, packages, globalenv, and attachments.
Platform
The platform element records version (the running R version, via
R.version.string), os (the operating system, preferring
utils::osVersion() when available and falling back to Sys.info()),
system (the R build's R.version$system), ui (the interface running
the session – "non-interactive" when interactive() is FALSE,
otherwise the frontend reported by .Platform$GUI, e.g. "RStudio" or
"Positron"), tz (the session timezone via Sys.timezone()), and
date (the capture date).
Locale
The locale element records language, collate, and ctype. These
are split out from platform because they describe how text and dates
are formatted for this session, rather than what/where/when the session
is running.
Matrix
The matrix element records blas and lapack, the shared libraries
backing R's linear algebra routines (as reported by
extSoftVersion() and La_library()). Like locale, this is split out
from platform – in this case mirroring how base R's
utils::sessionInfo() treats "Matrix products" as its own block rather
than nesting it under platform info.
Document
The document element's pandoc and quarto fields record the versions
of those two document-rendering tools, if found (NA otherwise). Both
checks prefer the IDE-provided location over whatever happens to be on
PATH (RSTUDIO_PANDOC for pandoc, QUARTO_PATH for quarto), since
RStudio/Positron bundle their own copies that may differ from a
separately installed one. Deliberately not tracked: other system
dependencies (e.g. LaTeX, Hugo, spatial libraries) are package-specific
rather than session-wide, and tracking them well would mean tracking
many of them; pandoc/quarto are included because they, like
BLAS/LAPACK, are already tracked by utils::sessionInfo() or
sessioninfo::session_info(). document has no sessionInfo()
precedent (unlike matrix), but is grouped the same way for
consistency.
Machine
The machine element includes the node name and user reported by
Sys.info(), along with the working directory reported by getwd() at
capture time (cwd) – useful for a reproducibility audit since relative
paths used elsewhere in a script only resolve correctly relative to this
directory. Because this can reveal a hostname, local username, or
directory structure, be mindful about where sessionstate() output is
stored or shared. The same caution applies to the ondisk_path/
loaded_path columns of packages, since library paths often embed a
home directory.
Git
The git element records sha, the current commit
(git rev-parse HEAD, run in the working directory captured as
machine$cwd), and dirty, whether the working tree has uncommitted
changes (git status --porcelain is non-empty). Both are NA if the
working directory isn't inside a git repository, or if git itself
isn't installed. This is arguably the single most useful field for
reproducing a script's output later: sha identifies exactly which
version of the code ran, and dirty flags whether that identification is
trustworthy (a TRUE means the code that ran may not match any commit).
Timing
The timing element records captured_at, the capture time reported by
Sys.time(), and elapsed_sec, the session's elapsed run time in
seconds (the "elapsed" component of proc.time()). Together they let
an audit log show both when a snapshot was taken and how long the
session had already been running at that point.
RNG
The rng element records RNGkind() (as kind, normal_kind, and
sample_kind) together with seed_hash, an MD5 fingerprint of
.Random.seed (via tools::md5sum(), since base R has no in-memory
hashing function). seed_hash is NA if the RNG hasn't been used yet
this session (nothing has consumed a random draw, so .Random.seed
doesn't exist); sessionstate() never forces this into existence, since
doing so would itself consume a draw as a side effect of an audit call.
The hash exists to make RNG state comparable across renders without
printing the seed itself: for example, comparing seed_hash between two
rendered versions of the same Quarto/R Markdown document shows whether
an edit changed the RNG state anywhere upstream, without having to
inspect or store the (long, not directly meaningful) seed value.
Library paths
The libpaths element is the character vector returned by .libPaths(),
i.e. the library locations R searches, in search order. It complements
packages: that element records where each individual package resolved
to (ondisk_path), while libpaths records where R was looking in the
first place, which matters when, e.g., a project-local library shadows a
personal one. Unlike the other elements, there is no corresponding
display-filtering argument for libpaths, since it is already a flat
list of paths rather than a set of named fields or columns to choose
among; it is always shown in full.
Packages
The packages element covers every package that is either attached to
the search path or loaded via namespace (i.e., union(.packages(), loadedNamespaces())). It has columns package, attached,
ondisk_version (the version recorded in the installed package's
DESCRIPTION file), loaded_version (the version of the namespace
actually loaded into memory), version_mismatch (TRUE when the two
disagree, e.g. because the package was updated on disk after this
session loaded it), ondisk_path and loaded_path (the library paths a
package currently resolves to versus where its loaded namespace actually
came from), path_mismatch (TRUE when both exist but disagree, e.g.
after a .libPaths() change mid-session), removed_from_disk (TRUE
when the namespace is loaded but no longer found on disk at all), and
source, which classifies each package as "base", "CRAN (R x.y.z)",
"Github (user/repo@sha)", another remote type, or "local" when no
remote metadata is available.
Global environment
The globalenv element is a data frame with one row per object in
.GlobalEnv (including dot-prefixed objects), with columns name,
class, size (in bytes, as reported by utils::object.size()), and
hash (an MD5 fingerprint of the object's serialized value, in the same
spirit as rng$seed_hash: serialize() the object, then run
tools::md5sum() on the result). hash is NA when an object cannot be
serialized at all, which is rare in practice – objects backed by an
external pointer (e.g. a database connection) typically still serialize
to a placeholder rather than erroring. This is reported rather than
silently treated as "unchanged" by anything comparing two snapshots. Only
object names, classes, sizes, and value fingerprints are captured, never
values themselves. Because a long-running script can accumulate many objects,
the default display shows only the largest few, and omits hash (see
"Selecting which elements are displayed" below); the captured object
itself always holds every object and every column.
Hashing cost scales linearly with an object's size (roughly 5-6 seconds
per GB, dominated by serialize() itself rather than the disk I/O
tools::md5sum() requires). For a workspace holding very large objects
(e.g. multi-GB models or data frames), this can add a noticeable amount
of time to a single sessionstate() call. Setting a
sessionstate_hash_max_size field (a number of bytes) via
options(sessioncheck = list(...)) caps this: any object larger than
the limit gets hash = NA instead of being serialized at all, using the
same "not verifiable" semantics as an object that fails to serialize
(see above). There is no corresponding function argument – sessionstate()
takes none – so this is resolved purely as option-or-default (Inf by
default, i.e. no size limit and no change to prior behavior).
A related but distinct limitation: some R objects are thin wrappers
around state that lives outside R's memory entirely – a
magick image, an
Arrow Table or
RecordBatchReader, a database connection, a memory-mapped file.
Hashing such an object only fingerprints its R-level representation –
typically a fixed placeholder for the underlying pointer itself, per
serialize()'s handling of external pointers (see
compare_sessionstates()'s Details) – not the external data it points
to. If that external state changes without the R-level object itself
being reassigned (e.g. writing to a database connection, advancing a
stream's read position, mutating a file the object references), hash
can stay unchanged even though the object's real, externally-held
content did not. This is a limitation of what sessionstate() can
observe from within R, not a defect in the hashing itself: it never
inspects state outside R's memory, and so cannot distinguish "genuinely
unchanged" from "changed only outside R" for objects like these.
A different limitation runs in the opposite direction: for an object
that is, or contains, an environment – an
R6 object, a closure (via its
enclosing environment), a reference class instance – serialize()'s
traversal of an environment's bindings depends on insertion history, not
only on the environment's current contents. Two environments holding
identical bindings, populated in a different order, can therefore
serialize (and hash) differently even though nothing about them has
meaningfully changed. Where the external-pointer limitation above can
hide a real change (a false negative), this one can report a change that
never happened (a false positive) in compare_sessionstates()'s
globalenv$modified table. There is no general fix for this within base
R's serialize(); avoiding it would require a custom, order-independent
serialization of environment-backed objects, which sessionstate() does
not attempt.
Attachments
The attachments element is a data frame with one row per entry on the
search path (as returned by search()), with columns name and type
("package" or "other"). This surfaces non-package attachments (e.g.
tools:rstudio, or environments added via attach()) that aren't
reflected in packages.
Selecting which elements are displayed
sessionstate() itself always captures every field in full (globalenv
is never truncated at capture time). To display only a subset when
printing, pass platform/locale/matrix/document/machine/git/
timing/rng/packages/globalenv/attachments arguments to
print() or format() on the result, or set
defaults via options(sessioncheck = list(sessionstate_packages = ...))
(see display_methods for the full precedence rules and option names).
The globalenv_n argument separately controls how many rows of
globalenv are shown (largest objects first), independent of which
columns are selected. None of this affects the underlying object, so
x$globalenv/x$attachments always return their full data frames.
Separately, as.data.frame() returns one of the three tables captured by
sessionstate() (packages, globalenv, or attachments, selected via
its which argument); see coercion_methods for why this coercion,
unlike the one for sessioncheck(), cannot be lossless.
Examples
sessionstate()
#> ─ Platform ─────────────────────────────────────────────────────────────────────
#> • version R version 4.6.1 (2026-06-24)
#> • os Ubuntu 24.04.4 LTS
#> • system x86_64, linux-gnu
#> • ui non-interactive
#> • tz UTC
#> • date 2026-09-07
#>
#> ─ Locale ───────────────────────────────────────────────────────────────────────
#> • language en-US
#> • collate C
#> • ctype C.UTF-8
#>
#> ─ Matrix products ──────────────────────────────────────────────────────────────
#> • BLAS /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
#> • LAPACK /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so
#>
#> ─ Document products ────────────────────────────────────────────────────────────
#> • pandoc 3.8.3
#> • quarto (not found)
#>
#> ─ Machine ──────────────────────────────────────────────────────────────────────
#> • hostname runnervmejwal
#> • user runner
#> • working directory /home/runner/work/sessioncheck/sessioncheck/docs/reference
#>
#> ─ Git ──────────────────────────────────────────────────────────────────────────
#> • commit sha fb42b1e50b8c92ac71f42e64178bfa336bde6103
#> • dirty FALSE
#>
#> ─ Timing ───────────────────────────────────────────────────────────────────────
#> • captured at 2026-09-07 01:03:29 UTC
#> • session uptime 8.742 sec
#>
#> ─ RNG state ────────────────────────────────────────────────────────────────────
#> • kind Mersenne-Twister
#> • normal kind Inversion
#> • sample kind Rejection
#> • seed hash b71d56b44eb5ee9ceb53ef4cf66a2ed4
#>
#> ─ Library paths [n = 3] ────────────────────────────────────────────────────────
#> • /home/runner/work/_temp/Library
#> • /opt/R/4.6.1/lib/R/site-library
#> • /opt/R/4.6.1/lib/R/library
#>
#> ─ Packages [n = 56] (attached + loaded via namespace) ──────────────────────────
#> package attached loaded_version
#> R6 2.6.1
#> askpass 1.2.1
#> base * 4.6.1
#> brio 1.1.5
#> bslib 0.12.0
#> cachem 1.1.0
#> cli 3.6.6
#> compiler 4.6.1
#> curl 8.0.0
#> datasets * 4.6.1
#> desc 1.4.3
#> digest 0.6.39
#> downlit 0.4.5
#> evaluate 1.0.5
#> fansi 1.0.7
#> fastmap 1.2.0
#> fontawesome 0.5.3
#> fs 2.1.0
#> glue 1.8.1
#> grDevices * 4.6.1
#> graphics * 4.6.1
#> htmltools 0.5.9
#> httr2 1.3.0
#> jquerylib 0.1.4
#> jsonlite 2.0.0
#> knitr 1.51
#> lifecycle 1.0.5
#> magrittr 2.0.5
#> memoise 2.0.1
#> methods * 4.6.1
#> openssl 2.4.2
#> otel 0.2.0
#> pak 0.11.1
#> pillar 1.11.1
#> pkgconfig 2.0.3
#> pkgdown 2.2.1
#> purrr 1.2.2
#> ragg 1.5.2
#> rlang 1.3.0
#> rmarkdown 2.32
#> sass 0.4.10
#> sessioncheck * 0.1.1.9000
#> stats * 4.6.1
#> systemfonts 1.3.2
#> testthat 3.3.2
#> textshaping 1.0.5
#> tibble 3.3.1
#> tools 4.6.1
#> utils * 4.6.1
#> vctrs 0.7.3
#> waeponwifestre 0.0.0.9000
#> whisker 0.4.1
#> withr 3.0.3
#> xfun 0.60
#> xml2 1.6.0
#> yaml 2.3.12
#> source
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> base
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> base
#> RSPM (R 4.6.0)
#> base
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> base
#> base
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> base
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> local
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> local (.)
#> base
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> base
#> base
#> RSPM (R 4.6.0)
#> Github (djnavarro/waeponwifestre@6265365)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#> RSPM (R 4.6.0)
#>
#> ─ Global environment [n = 1] ───────────────────────────────────────────────────
#> name class size
#> .Random.seed integer 2.5 Kb
#>
#> ─ Attached environments [n = 10] ───────────────────────────────────────────────
#> name type
#> .GlobalEnv other
#> package:sessioncheck package
#> package:stats package
#> package:graphics package
#> package:grDevices package
#> package:utils package
#> package:datasets package
#> package:methods package
#> Autoloads other
#> package:base package