# xarray-blosc2

> A blosc2 storage backend for xarray — compressed, lazy, with CF-1.11 metadata, AES-256-GCM encryption, ACID versioned storage, and a single embeddable Python file that runs in Pyodide. The wheel is the distribution; the repository is not public at this time.

## Loaded with `import xarray_blosc2`

- `xarray_blosc2.__doc__` — module docstring leading with the universal `open()` dispatch table
- `xarray_blosc2.AGENTS_MD` — full reference (see `importlib.resources` block below)
- `help(xarray_blosc2.open)` — universal reader signature + semantics
- `help(xarray_blosc2.save_dataset)` — write options (preset, lossy, chunks/blocks, CF metadata)
- `help(xarray_blosc2.append_dataset)` — append semantics + concurrency caveat
- `help(xarray_blosc2.save_encrypted_dataset)` — AES-256-GCM sealed `.b2z`
- `help(xarray_blosc2.versioned_store.Repository)` — ACID versioned store (local + S3)

## Inside the wheel

- `xarray_blosc2/AGENTS.md` — task-organized playbook (design constraints, save/read idioms, ACID patterns A/B/C, remote/S3, encryption, troubleshooting). Read this first.
- `xarray_blosc2/skills/` — narrow per-task agent skills (Claude Code compatible).
- `xarray_blosc2/llms.txt` — this file.

## Loading from Python

```python
from importlib.resources import files
agents_md = files("xarray_blosc2").joinpath("AGENTS.md").read_text()
llms_txt  = files("xarray_blosc2").joinpath("llms.txt").read_text()
```

## API surface (most-used)

- `xarray_blosc2.open(src, *, key=None, storage_options=None, group=None, drop_variables=None, trim_to_commit=True)` — universal lazy reader; bytes/path/URL/`s3://`/`zip://m::s3://…`/glob/sealed-blob; magic-checked.
- `xarray_blosc2.save_dataset(ds, path, *, preset=None, precision=None, lossy=None, chunks=None, blocks=None, cf_metadata=None, ...)` — write a directory.
- `xarray_blosc2.append_dataset(ds, path, dim="time", ...)` — true resize-append; single-writer / offline only.
- `xarray_blosc2.freeze_dataset(dirpath)` — directory → `.b2z` portable zip.
- `xarray_blosc2.to_blob(ds, key=None)` — `.b2z` bytes (sealed with key).
- `xarray_blosc2.save_encrypted_dataset(ds, path, key)` / `open_encrypted_dataset(path, key)` — sealed `.b2z` file.
- `xarray_blosc2.generate_encryption_key()` — urlsafe-base64 32-byte key.
- `xarray_blosc2.memory_guard(max_gb=...)` — decorator; refuses oversize Dataset returns.
- `ds.b2.materialised_gb` / `ds.b2.materialised_nbytes` — `.load()` cost estimate.
- `xarray_blosc2.open_remote(url, path)` → `.estimate_size(**isel)` → `.materialize(**isel)` — bounded remote pull.
- `xarray_blosc2.versioned_store.Repository(...)` — ACID versioned store, snapshots/branches/tags/GC.

## Read this when

- writing data → `xarray_blosc2/AGENTS.md` § Idiomatic save
- reading data → `xarray_blosc2/AGENTS.md` § Idiomatic read
- appending → § Append patterns (A/B/C) + warning on `append_dataset` concurrency
- S3 / globs / one-member reads → § Remote & S3
- encryption → § Encryption (one sealed-`.b2z` mechanism)
- troubleshooting an AttributeError, OOM, or netCDF export failure → § Troubleshooting

## One foundational constraint to remember

blosc2 IO is **chunk-granular**, not block-granular. Blocks are a *decompression* unit (CPU / L2 cache), not a *storage* unit. Size **chunks** to your query pattern; size **blocks** for cache fit. See `xarray_blosc2/AGENTS.md` § Storage layout + `docs/blocks-vs-chunks.md`.
