Skip to contents

[!NOTE] This package was created as an experiment in using Claude Code to autonomously port a package from Python to R. It is NOT intended to be used in practice, you should use {anndataR} instead.

See https://lazappi.id.au/posts/2026-10-25-anndata-r-claude/ for a blog post describing how this package was created.

{anndata.claude} is an R port of Python anndata for annotated data matrices.

Its first priority is full compatibility with the anndata on-disk formats. An object read from an h5ad file or zarr store is equal whichever language wrote it, and files written by R are structurally equivalent to files written by Python. The in-memory AnnData object supports that goal and aims for feature parity with Python.

The package was written by Claude (Anthropic’s AI models) in an autonomous development loop, supervised by a human maintainer (see Development).

Relationship to Python anndata

Python anndata release 0.13.4 is the only reference for behaviour. This package matches its observable behaviour (values, errors, warnings and files written) but is idiomatic R rather than a line-by-line translation. Indexing is 1-based with negative exclusion, and AnnData objects have reference semantics (R6) like their Python counterparts.

Every known difference is listed with its reason in vignette("deviations").

Features

Not supported: loom (deprecated in Python), writing zarr v2, zip stores and the experimental Python features (AnnCollection, concat_on_disk, awkward arrays). Reading is slower than Python on large files. See the known limitations in NEWS.md for details.

Installation

Install the development version from GitHub with pak, which also installs the Bioconductor dependencies and the development version of Rarr:

# install.packages("pak")
pak::pak("lazappi/R-anndata-claude")

The package has compiled code that links to the HDF5 library from Rhdf5lib. On macOS that library needs OpenSSL, which can be installed with source("https://mac.R-project.org/bin/install.R"); install.libs("openssl") (run as an administrator) or Homebrew.

Usage

library(anndata.claude)

X <- matrix(as.numeric(1:12), nrow = 3)
obs <- data.frame(cell_type = c("T", "B", "T"), row.names = paste0("cell", 1:3))
var <- data.frame(row.names = paste0("gene", 1:4))
adata <- AnnData(X, obs = obs, var = var)
adata$layers[["counts"]] <- X * 2

path <- tempfile(fileext = ".h5ad")
write_h5ad(adata, path)
read_h5ad(path)

Start with vignette("anndata-claude"), or browse the documentation at https://lazappi.github.io/R-anndata-claude/.

Directory structure

The package

Path Contents
R/ Package code, grouped by file prefix (anndata*, io-*, backed*, lazy-*, concat* and so on)
src/ A small C helper for HDF5 compound types, linked to Rhdf5lib (ADR 0008)
man/ Help pages generated by roxygen2
vignettes/ The getting started guide and the list of deviations from Python
tests/testthat/ testthat tests and their helpers
tests/testthat/fixtures/ Files written by Python anndata and JSON tables of Python’s expected behaviour
tests/python/ The uv project pinning Python anndata 0.13.4, with scripts that generate fixtures and compare files
DESCRIPTION, NAMESPACE, NEWS.md, LICENSE Standard package files
_pkgdown.yml pkgdown site configuration (built into the git-ignored pkgdown-site/)
.github/workflows/ GitHub Actions for R CMD check, lint, coverage and the pkgdown site
air.toml, .lintr Formatter and linter settings

Development

These files are excluded from the built package.

Path Contents
CONTEXT.md Domain glossary (Slot, Element, Encoding type, On-disk dtype and so on)
docs/adr/ Architecture decision records
docs/agents/ Conventions for the issue tracker, triage labels and domain docs
.scratch/ Specs and tickets, one directory per sub-project, starting from .scratch/roadmap/spec.md
fix_plan.md The queue of tickets for the development loop
PROMPT.md The prompt given to each run of the development loop
CLAUDE.md Instructions and accumulated build, test and tooling learnings for agents
ralph/, .claude/ Claude Code settings for loop runs and interactive sessions, and the project subagents
scripts/ The full check (check.sh), the loop (ralph.sh), fixture regeneration, benchmarks and fetching the Python reference
.reference/ Git-ignored clone of Python anndata 0.13.4 (from scripts/fetch-reference.sh)
.ralph/ Git-ignored loop logs, scratch experiments and downloaded test files

Development

Development runs as a “Ralph loop”: scripts/ralph.sh starts a fresh Claude Code run for each ticket in fix_plan.md, which works test-first, checks its result against Python and commits. The human maintainer writes the specs with Claude, approves tickets and decides releases.

The full check, which must pass before every commit, is:

scripts/check.sh --package  # format, lint, document and R CMD check without tests
scripts/check.sh --tests    # every test

Tests that compare with Python need uv, and are skipped without it or when ANNDATA_SKIP_PYTHON is set.

Acknowledgements

Thanks to the authors of Python anndata, whose design and file formats this package follows.

License

BSD 3-Clause, see LICENSE.md.