agentleFS
TerraLabAITerraLabAI/geoai-skills/skills/remote-sensing/SKILL.md

remote-sensing

Skill0 starsChanged 32 days agoMITView on GitHub

Picks satellite imagery and processes it correctly as ordered workflows with checks. Covers choosing Sentinel-2, Landsat, Sentinel-1 SAR, DEMs and orthophotos, STAC search on Earth Search and Planetary Computer, Sentinel-2 and Landsat reflectance scale and offsets (processing baseline 04.00, Collection 2 Level-2), cloud masks (SCL, QA_PIXEL, Cloud Score+), composites, NDVI, NDWI, NDMI, NBR and other indices, Google Earth Engine collection ids, scale factors and reduceRegion scale, change detection (dNBR, NDVI difference), land cover classification with training samples and a confusion matrix, and raster operations in QGIS and GDAL (clip by mask, warp, raster calculator, alignment). Use when the user asks for NDVI or another index, satellite images of an area, a cloud-free composite, Sentinel-2 or Landsat in QGIS, rasterio or Earth Engine, burn severity, before and after change, a land cover map, accuracy assessment, or to clip, reproject or combine rasters.

4 other projects use a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

3 rules. 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • 0

    Common

    Most of the 4 edited versions we read keep these.

  • 1

    Distinctive

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Never mix harmonized and non-harmonized Sentinel-2, or Landsat 7 with 8 without noting the sensor difference.

    line 80
  2. Very specific:

    Check: count of valid observations per pixel (Earth Engine .count(), or a sum of masks).

    line 81
  3. Very specific:

    After any operation, compare gdalinfo -stats of input and output: same value range, expected pixel size, expected extent.

    line 101

“Common” is measured: kept by at least 6 in 10 of the 4 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Remote sensing

Each workflow below is ordered; run the check after each step. Most wrong answers in remote sensing come from a skipped step (no cloud mask, offset forgotten, rasters not aligned), not from the formula.

Always first

  1. Inspect each raster: gdalinfo -stats file.tif. Note CRS, pixel size, band count and order, data type, NoData, min and max. Integer values in the thousands mean DN, not reflectance.
  2. Frame: which area (exact boundary), which dates or season, which sensor resolution is enough for the smallest object, and which product the user expects (map, statistic, time series). Ask when the area or the period is missing. When the imagery cannot answer (single trees on 10 m pixels, a date before the sensor existed), say so and propose what can.
  3. Return the code that was run, with dataset ids, dates and thresholds, so the user can rerun it.

Workflow index

TaskWhere
Which imagery for this job, where to download itChoose imagery, references/imagery-sources.md
Sentinel-2 or Landsat to reflectance, cloud masksReflectance and masks, references/optical-reflectance.md
NDVI, NDWI, NDMI, NDBI, NBR, EVIIndices
Cloud-free composite for a seasonComposites
Earth Engine scriptsreferences/earth-engine.md
Burn severity, before and after, change mapreferences/change-and-sar.md
Sentinel-1 SAR (floods, through clouds)references/change-and-sar.md
Land cover map, training samples, accuracyreferences/classification.md
Clip, reproject, align, raster calculatorRaster operations
Slope, hillshade, watershed from a DEMthe spatial-analysis skill (terrain and hydrology)

Choose imagery

NeedSourcePixel
Vegetation, water, crops, burn scars since 2015Sentinel-2 L2A10 to 20 m
History before 2015, thermalLandsat Collection 2 Level-2 (Landsat 5, 7, 8, 9)30 m
Cloudy regions, floods, night, shipsSentinel-1 GRD or RTC (SAR)10 m
TerrainCopernicus DEM GLO-30 (surface model, EGM2008 heights), national lidar30 m, 1 to 5 m
Buildings, single trees, carsnational orthophotos (IGN BD ORTHO, NAIP), not Sentinel-20.2 to 1 m

Rule: the smallest object must span at least 3 to 5 pixels to be detected. Never analyze basemap tiles (Google, Bing, Esri): their terms forbid it and the capture date is unknown. Catalogs, collection ids, licenses and a STAC search example: references/imagery-sources.md.

Reflectance and masks

Convert DN to reflectance once, mask clouds, then compute. Details and code: references/optical-reflectance.md.

ProductReflectanceCloud mask
Sentinel-2 L2A, processing baseline 04.00+ (from 25 January 2022), raw DN(DN - 1000) / 10000SCL: mask 0, 1, 3, 8, 9, 10, 11
Sentinel-2 L2A before baseline 04.00, or a harmonized collection (Earth Engine S2_SR_HARMONIZED)DN / 10000SCL, or Cloud Score+ in Earth Engine
Landsat Collection 2 Level-2 surface reflectance (SR_B*)DN * 0.0000275 - 0.2QA_PIXEL bits 1 dilated cloud, 2 cirrus, 3 cloud, 4 cloud shadow (5 snow)
Landsat Collection 2 Level-2 surface temperature (ST_B10, ST_B6)DN * 0.00341802 + 149.0 kelvinsame

Checks: DN 0 is NoData, not dark; clear water NIR reflectance is near 0 to 0.05 and dense vegetation NIR 0.3 to 0.5; a water median above 0.1 means an offset was missed. Run python3 scripts/s2_offset_check.py ITEM_JSON_OR_URL on a Sentinel-2 STAC item to get the right formula.

Indices

Compute on float reflectance, after masking, with all bands on one grid.

IndexSentinel-2Landsat 8/9Notes
NDVI(B8 - B4) / (B8 + B4)(B5 - B4) / (B5 + B4)water below 0, bare soil about 0.1 to 0.2, dense vegetation 0.6 to 0.9
NDWI (McFeeters), open water(B3 - B8) / (B3 + B8)(B3 - B5) / (B3 + B5)water above 0
NDMI (Gao NDWI), vegetation water(B8A - B11) / (B8A + B11)(B5 - B6) / (B5 + B6)"NDWI" is ambiguous: say which
NDBI, built-up(B11 - B8) / (B11 + B8)(B6 - B5) / (B6 + B5)
NBR, burn(B8A - B12) / (B8A + B12)(B5 - B7) / (B5 + B7)
EVI2.5 (B8 - B4) / (B8 + 6 B4 - 7.5 B2 + 1)2.5 (B5 - B4) / (B5 + 6 B4 - 7.5 B2 + 1)needs reflectance 0 to 1, not DN

Landsat band numbers above are for Landsat 8 and 9 OLI; Landsat 4, 5 and 7 differ (red B3, NIR B4, SWIR1 B5, SWIR2 B7). A normalized index outside -1 to 1 means DN were not converted, NoData entered the math, or integer division was used. python3 scripts/indices.py prints Sentinel-2 formulas and computes one from band files.

Composites

  1. Filter by area, dates (same season across years), and scene cloud cover as a first cut only.
  2. Mask clouds per pixel (step above), then reduce: median for a clean picture, a percentile or max-NDVI (greenest pixel) for vegetation peaks.
  3. Never mix harmonized and non-harmonized Sentinel-2, or Landsat 7 with 8 without noting the sensor difference.
  4. Check: count of valid observations per pixel (Earth Engine .count(), or a sum of masks). Pixels with 0 or 1 observation are unreliable; report the share.

Raster operations in QGIS and GDAL

OperationQGIS idGDAL command
Clip to a polygongdal:cliprasterbymasklayer (INPUT, MASK, CROP_TO_CUTLINE, KEEP_RESOLUTION, NODATA)gdalwarp -cutline aoi.gpkg -crop_to_cutline -dstnodata 0 in.tif out.tif
Reproject, resamplegdal:warpreproject (TARGET_CRS, RESAMPLING, TARGET_RESOLUTION)gdalwarp -t_srs EPSG:32631 -tr 10 10 -r bilinear in.tif out.tif
Align to a reference gridnative:alignsingleraster (REFERENCE_LAYER), native:alignrastersgdalwarp -te xmin ymin xmax ymax -tr 10 10 -tap ...
Raster calculatornative:rastercalc (LAYERS, EXPRESSION), gdal:rastercalculatorgdal_calc.py -A b8.tif -B b4.tif --calc="(A-B)/(A+B)" --type=Float32
Mosaicgdal:merge, gdal:buildvirtualrastergdalbuildvrt, gdal_merge.py
Convert, compress, COGgdal:translategdal_translate -of COG in.tif out.tif

Verified on 2026-10-11 against QGIS 3.44 (qgis_process help).

Rules:

  • Resampling: nearest for classes (land cover, SCL, masks), bilinear or cubic for continuous values (reflectance, elevation).
  • Set NoData explicitly before math, or NoData pixels are computed as 0.
  • Integer inputs: cast or write Float32 output (--type=Float32 in gdal_calc), or a ratio truncates to 0.
  • Clip with a mask in the raster's CRS when possible; otherwise the cutline is reprojected on the fly, which is fine, but check the output extent.
  • After any operation, compare gdalinfo -stats of input and output: same value range, expected pixel size, expected extent.

Before handing over a result

  • Dataset ids, dates, cloud thresholds and the reflectance formula stated.
  • Clouds masked and the share of valid pixels reported.
  • Value range checked against the index ranges above.
  • Output looked at: a PNG or a QGIS screenshot with a sensible color ramp, over the right place.
  • Attribution line, for example "Contains modified Copernicus Sentinel data 2025" or "Landsat imagery courtesy of the U.S. Geological Survey".

Scripts

  • python3 scripts/s2_offset_check.py ITEM_JSON_OR_URL: reads a Sentinel-2 STAC item and prints the reflectance formula to use and why (stdlib only).
  • python3 scripts/indices.py [ndvi]: prints Sentinel-2 index formulas; --band B04=red.tif --band B08=nir.tif -o ndvi.tif computes one (numpy and rasterio, inputs in reflectance).
  • python3 scripts/accuracy.py matrix.csv: overall accuracy, kappa, producer's and user's accuracy from a confusion matrix, or --pairs ref_pred.csv from reference and predicted labels (stdlib only).

Going further

AI Agent for QGIS fetches Sentinel-2 and Landsat scenes and computes indices from a chat inside QGIS: https://terra-lab.ai/ai-agent?utm_source=skills&utm_medium=geoai-skills&utm_campaign=remote-sensing

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.