diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index 709ca89..af1203f 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -14,6 +14,7 @@ src/lazycogs/
_grid.py output affine transform and grid dimensions
_reproject.py warp-map computation and nearest-neighbor sampling
_storage_ext.py STAC Storage Extension metadata parsing
+ _single.py open_cog()/open_item(): native-resolution single-COG and single-item reads
_store.py HREF-to-store resolution and store_for()
_temporal.py temporal grouping strategies and _TimeStep predicates
_mosaic_methods.py pixel-selection strategies
diff --git a/README.md b/README.md
index 5c02cdc..08da4d9 100644
--- a/README.md
+++ b/README.md
@@ -83,6 +83,35 @@ da = lazycogs.open(
)
```
+### Single COG and single item reads
+
+Sometimes you don't want a reprojected mosaic — you want to read one asset (or
+a few bands of one item) exactly as stored. `lazycogs.open_cog` and
+`lazycogs.open_item` read COGs **at their native grid** (native CRS, resolution,
+and shape, no reprojection), returning eagerly-loaded `(band, y, x)` DataArrays
+with the same rioxarray-compatible metadata as `lazycogs.open`.
+
+```python
+import lazycogs
+
+# One COG → (band, y, x) at native resolution, band labelled 1..N.
+da = lazycogs.open_cog("s3://bucket/scene/B04.tif")
+
+# Several same-grid assets of one STAC item, stacked and labelled by asset key.
+# `item` is a STAC item dict (e.g. a rustac search result) or a pystac Item.
+da = lazycogs.open_item(item, bands=["B04", "B08"])
+# da.dims == ("band", "y", "x"); da["band"] == ["B04", "B08"]
+```
+
+`open_item` requires every selected asset to be a single-band COG sharing the
+same native grid (CRS, resolution, extent); it raises a `ValueError` otherwise.
+`nodata`/`scale`/`offset` are read from each asset file and surfaced as scalar
+CF attributes (`_FillValue`/`scale_factor`/`add_offset`) only when all selected
+bands agree. For assets at differing resolutions, or to mosaic across a whole
+collection, use `lazycogs.open` instead. Both functions accept the same
+`store=`/`path_from_href=` arguments as `lazycogs.open`, and each has an
+`await`-able `_async` variant (`open_cog_async`, `open_item_async`).
+
### Temporal grouping
By default, `lazycogs.open()` groups items into one time step per calendar day (`time_period="P1D"`). You can also request coarser composites with `"PnD"`, `"P1W"`, `"P1M"`, or `"P1Y"`.
diff --git a/docs/api/single.md b/docs/api/single.md
new file mode 100644
index 0000000..fc6cd7e
--- /dev/null
+++ b/docs/api/single.md
@@ -0,0 +1,17 @@
+# Single COG / item
+
+Read a single Cloud-Optimized GeoTIFF or the assets of one STAC item at their
+native grid — no reprojection or mosaicking. Use `lazycogs.open` for a
+reprojected mosaic across a whole collection.
+
+!!! tip "See also"
+ [Loading single item on native grid](../notebooks/single-item.ipynb)
+
+::: lazycogs.open_cog
+
+::: lazycogs.open_item
+
+::: lazycogs.open_cog_async
+
+::: lazycogs.open_item_async
+
diff --git a/docs/notebooks/single-item.ipynb b/docs/notebooks/single-item.ipynb
new file mode 100644
index 0000000..b5cee0a
--- /dev/null
+++ b/docs/notebooks/single-item.ipynb
@@ -0,0 +1,1354 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "633084e9",
+ "metadata": {},
+ "source": [
+ "# Single STAC Item: `open_item` and `open_cog`\n",
+ "\n",
+ "Two single-item helpers in `lazycogs`, both lazy and read at the asset's native grid:\n",
+ "\n",
+ "- `lazycogs.open_item` — stack several same-grid bands of one STAC item into a `(band, y, x)` DataArray.\n",
+ "- `lazycogs.open_cog` — read one Cloud-Optimized GeoTIFF at its native CRS, resolution, and shape.\n",
+ "\n",
+ "First, find one low-cloud Sentinel-2 scene and configure a store for the public bucket (no credentials needed)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "5b3e1557",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import rustac\n",
+ "from obstore.store import S3Store\n",
+ "\n",
+ "import lazycogs\n",
+ "\n",
+ "items = await rustac.search(\n",
+ " href=\"https://earth-search.aws.element84.com/v1\",\n",
+ " collections=[\"sentinel-2-c1-l2a\"],\n",
+ " bbox=[4.8, 52.3, 5.0, 52.5], # Amsterdam\n",
+ " datetime=\"2023-06-01/2023-06-30\",\n",
+ " query={\"eo:cloud_cover\": {\"lt\": 10}},\n",
+ " limit=1,\n",
+ ")\n",
+ "item = items[0]\n",
+ "\n",
+ "store = S3Store(\n",
+ " bucket=\"e84-earth-search-sentinel-data\",\n",
+ " region=\"us-west-2\",\n",
+ " skip_signature=True,\n",
+ " virtual_hosted_style_request=True,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "62a2cb1a",
+ "metadata": {},
+ "source": [
+ "## Open a Multi-Band Item with `open_item`\n",
+ "\n",
+ "`lazycogs.open_item` stacks several single-band assets of one STAC item into a `(band, y, x)` DataArray at their shared native grid. Here we request the `red` and `green` bands. Notice that both of these assets have the same grid. If we were to pick bands with different grids, `lazycogs.open_item` would raise an error, `lazycogs.open` would then be the correct function to use."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "3ab37ec3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
PROJCRS["WGS 84 / UTM zone 31N",BASEGEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],MEMBER["World Geodetic System 1984 (G2296)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Navigation and medium accuracy spatial referencing."],AREA["Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Andorra. Belgium. Benin. Burkina Faso. Denmark - North Sea. France. Germany - North Sea. Ghana. Luxembourg. Mali. Netherlands. Niger. Nigeria. Norway. Spain. Togo. United Kingdom (UK) - North Sea."],BBOX[0,0,84,6]],ID["EPSG",32631]]
spatial_ref :
PROJCRS["WGS 84 / UTM zone 31N",BASEGEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],MEMBER["World Geodetic System 1984 (G2296)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Navigation and medium accuracy spatial referencing."],AREA["Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Andorra. Belgium. Benin. Burkina Faso. Denmark - North Sea. France. Germany - North Sea. Ghana. Luxembourg. Mali. Netherlands. Niger. Nigeria. Norway. Spain. Togo. United Kingdom (UK) - North Sea."],BBOX[0,0,84,6]],ID["EPSG",32631]]
PROJCRS["WGS 84 / UTM zone 31N",BASEGEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],MEMBER["World Geodetic System 1984 (G2296)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Navigation and medium accuracy spatial referencing."],AREA["Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Andorra. Belgium. Benin. Burkina Faso. Denmark - North Sea. France. Germany - North Sea. Ghana. Luxembourg. Mali. Netherlands. Niger. Nigeria. Norway. Spain. Togo. United Kingdom (UK) - North Sea."],BBOX[0,0,84,6]],ID["EPSG",32631]]
spatial_ref :
PROJCRS["WGS 84 / UTM zone 31N",BASEGEOGCRS["WGS 84",ENSEMBLE["World Geodetic System 1984 ensemble",MEMBER["World Geodetic System 1984 (Transit)"],MEMBER["World Geodetic System 1984 (G730)"],MEMBER["World Geodetic System 1984 (G873)"],MEMBER["World Geodetic System 1984 (G1150)"],MEMBER["World Geodetic System 1984 (G1674)"],MEMBER["World Geodetic System 1984 (G1762)"],MEMBER["World Geodetic System 1984 (G2139)"],MEMBER["World Geodetic System 1984 (G2296)"],ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]],ENSEMBLEACCURACY[2.0]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4326]],CONVERSION["UTM zone 31N",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",3,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",0.9996,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["(E)",east,ORDER[1],LENGTHUNIT["metre",1]],AXIS["(N)",north,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Navigation and medium accuracy spatial referencing."],AREA["Between 0°E and 6°E, northern hemisphere between equator and 84°N, onshore and offshore. Algeria. Andorra. Belgium. Benin. Burkina Faso. Denmark - North Sea. France. Germany - North Sea. Ghana. Luxembourg. Mali. Netherlands. Niger. Nigeria. Norway. Spain. Togo. United Kingdom (UK) - North Sea."],BBOX[0,0,84,6]],ID["EPSG",32631]]