← GeoAI SkillsCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to GeoAI Skills
Snapshot Sep 30, 2026 · 23:13 UTC · version 0.4.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "google-earth-engine",
"description": "Invoke when Earth Engine, GEE, ee., or geemap is named; when work needs its server-side catalog; or when choosing Earth Engine versus local xarray or desktop processing for a large area or long archive. Covers image collections, masking, compositing, reducers, zonal statistics, time series, classification, quota-aware batching, and exports. This is an execution platform skill; combine it with remote-sensing-analysis or change-detection when those skills own the scientific method.",
"included_files": [
{
"relative_path": "agents/openai.yaml",
"size_in_bytes": 219
},
{
"relative_path": "references/authoritative-sources.md",
"size_in_bytes": 920
}
],
"skill_md_contents": "---\nname: google-earth-engine\ndescription: >-\n Invoke when Earth Engine, GEE, ee., or geemap is named; when work needs its\n server-side catalog; or when choosing Earth Engine versus local xarray or\n desktop processing for a large area or long archive. Covers image\n collections, masking, compositing, reducers, zonal statistics, time series,\n classification, quota-aware batching, and exports. This is an execution\n platform skill; combine it with remote-sensing-analysis or change-detection\n when those skills own the scientific method.\nlicense: MIT\nmetadata:\n author: Muhammed Enes Duran\n---\n\n# Google Earth Engine\n\nPurpose: use GEE's server-side model correctly. The recurring failure\nmodes are **client/server confusion** (calling `.getInfo()` in loops,\nPython `if` on server objects), **unbounded computation** (timeouts from\nunscaled reductions), and **silent default scales** (statistics computed\nat the wrong resolution).\n\n## Should this run here at all? — Earth Engine versus local\n\nAnswer this before writing any `ee.` code. The decision turns on six things, and\nyou cannot make it without them, so establish them first — asking alongside a\nprovisional recommendation, never instead of one:\n\n1. **Archive extent and duration** — area, and how many years at what revisit.\n This is what makes server-side worth its constraints; a single scene does not.\n2. **Algorithm expressibility** — can the work be written as masks, reducers and\n band math? Anything needing arbitrary per-pixel iteration, a custom solver, or\n a Python library GEE does not host belongs local.\n3. **Data locality and sensitivity** — restricted or offline data cannot be\n uploaded, and that ends the discussion regardless of scale.\n4. **Interactive limits versus batch** — see [Quotas and etiquette](#quotas-and-etiquette).\n Anything beyond a ~5 minute interactive request has to be designed as a batch\n export from the start, not retrofitted when `getInfo` times out.\n5. **Export volume** — what actually comes back: a few reduced statistics, or\n full-resolution per-pixel stacks you will store and reprocess locally.\n6. **Reproducibility cost** — the real price of moving server-side. The catalog\n version can shift under you and the computation leaves no local trace, so\n choosing GEE obliges you to ship the [provenance record](#provenance-record).\n State this cost when you recommend GEE; a recommendation that omits it is\n incomplete.\n\nRecommend Earth Engine only when 1 and 2 favour it and 3 permits it. When the\nanswer is genuinely balanced, say so and name the deciding question rather than\ndefaulting to the platform this skill is about. `xee` and STAC + `stackstac` /\n`odc-stac` are the middle paths worth naming: catalog access with local compute.\n\n## Mental model — everything is deferred\n\n`ee.Image`, `ee.ImageCollection`, `ee.FeatureCollection` are **server-side\ndescriptions**, not data. Nothing computes until an output is requested\n(`getInfo`, export, map tile). Consequences:\n\n- Never use Python `if`/`for` on server values — use `ee.Algorithms.If`\n sparingly, prefer `.map()` + filters. A Python loop that calls\n `.getInfo()` per element is the #1 GEE performance bug.\n- `.getInfo()` blocks and transfers; use it for tiny scalars only.\n Anything sized → **Export** (to Drive/GCS/Asset).\n- Debug with `.aggregate_array()`, `.first()`, `.limit(3)` probes — not by\n printing whole collections.\n\n## Canonical pipeline (Sentinel-2 cloud-free composite)\n\n```python\nimport ee\nee.Initialize(project=\"my-project\")\n\naoi = ee.Geometry.Rectangle([27.0, 38.3, 27.4, 38.6])\n\ndef mask_s2(img):\n # Cloud Score+ is the current best practice (threshold ~0.5-0.65)\n cs = img.linkCollection(csplus, [\"cs_cdf\"]).select(\"cs_cdf\")\n return img.updateMask(cs.gte(0.6))\n\ncsplus = ee.ImageCollection(\"GOOGLE/CLOUD_SCORE_PLUS/V1/S2_HARMONIZED\")\ns2 = (ee.ImageCollection(\"COPERNICUS/S2_SR_HARMONIZED\")\n .filterBounds(aoi)\n .filterDate(\"2025-05-01\", \"2025-09-30\")\n .map(mask_s2))\ncomposite = s2.median().clip(aoi)\nndvi = composite.normalizedDifference([\"B8\", \"B4\"]).rename(\"ndvi\")\n```\n\nCollection choices: `S2_SR_HARMONIZED` (post-2022 offset harmonized),\n`LANDSAT/LC08/C02/T1_L2` + friends (apply scale factors: optical\n`*0.0000275 - 0.2`), `MODIS/061/...` for daily/coarse, ERA5-Land for\nclimate. Record collection IDs + date filters in the deliverable.\n\n## Reducers and zonal statistics — scale is not optional\n\n```python\nstats = ndvi.reduceRegions(\n collection=districts,\n reducer=ee.Reducer.mean().combine(ee.Reducer.stdDev(), sharedInputs=True),\n scale=10, # ALWAYS explicit — native resolution\n tileScale=4, # raise when \"computation timed out\"\n)\n```\n\n- `scale` defaults to the map zoom level in some paths — silently coarse\n statistics. Always set it to the data's native resolution (or state the\n deliberate coarsening).\n- `bestEffort=True` silently degrades scale to fit limits — avoid in\n analysis; prefer `tileScale` + exports.\n- Large reductions → `Export.table.toDrive`, not `.getInfo()`.\n- Weighted vs unweighted reducers differ at polygon edges\n (`.unweighted()` for counts of whole pixels); state which you used.\n\n## Time series\n\n- Build per-period composites with a mapped function over\n `ee.List.sequence` of dates (monthly/seasonal medians), then reduce —\n don't export daily stacks you'll aggregate anyway.\n- For per-pixel trends: `ee.Reducer.sensSlope()` (robust) or\n `linearFit`; harmonic regression (`.addBands` of sin/cos terms) for\n phenology. Mask by count of valid observations — trends from 4 pixels\n of 200 possible are noise; report the count band.\n- For break detection at archive scale (LandTrendr/CCDC available in GEE),\n method selection follows `change-detection`.\n\n## Classification in GEE\n\n`ee.Classifier.smileRandomForest` covers most cases. Training samples via\n`image.sampleRegions`; split train/test **spatially** (add a grid-cell\nattribute and filter — random `randomColumn` splits leak; see\n`ml-experiment-standards` → `references/spatial-cv-protocol.md`). Report\nper-class accuracy from `errorMatrix`; area estimates from a classified\nmap still need design-based adjustment (`change-detection` / Olofsson).\n\n## Exports and hand-off\n\n- `Export.image.toDrive/toCloudStorage` with explicit `region`, `scale`,\n `crs`, `maxPixels`; use `crsTransform` when pixel alignment with an\n existing raster matters.\n- Export > ~10⁸ pixels: shard by tiles or use `toAsset` intermediate.\n- Hand off to the local Python stack (rasterio/xarray) via COG exports, or\n `xee` for xarray-native access; visualize interactively with `geemap`.\n\n## Quotas and etiquette\n\nBatch tasks queue (check task status; don't fire hundreds blindly).\nInteractive requests time out at ~5 min — long jobs go to batch export.\nCache intermediate products as assets when a pipeline reuses them.\n\n## Provenance record\n\nServer-side computation is invisible after the fact: the catalog moves under\nyou, a reducer default changes the number, and nothing in the exported file\nsays which archive produced it. Every Earth Engine deliverable ships with a\nprovenance record, emitted as a sidecar JSON next to the export — not left\nin the notebook:\n\n- **Catalog asset IDs with their version suffix** (`COPERNICUS/S2_SR_HARMONIZED`\n and the specific collection version), plus the date range and filters applied.\n- **Mask method and thresholds** — cloud probability source, threshold value,\n and any morphological buffer.\n- **Reducers and their arguments**, including `tileScale`, `bestEffort`, and\n any `crsTransform`.\n- **Export parameters**: `region`, `scale`, `crs`, `maxPixels`, and the task ID.\n- **Run date and the `ee.__version__` / API client version**, because\n server-side defaults change without notice.\n\nRecommending Earth Engine over a local workflow is incomplete without this:\nthe reproducibility cost is the main thing the user trades away by moving\nserver-side, so state how it is recovered.\n\n## Verification protocol\n\n1. Probe: `composite.select(\"B4\").projection().nominalScale().getInfo()`\n and band names — confirms scale/CRS assumptions before reductions.\n2. Visual check in geemap at 2 zoom levels vs a basemap.\n3. Cross-check one zonal statistic against a local computation on an\n exported clip (catches scale/masking discrepancies).\n4. Report: collection IDs, date ranges, mask method + threshold, scale,\n reducer types.\n\n## Pitfalls checklist\n\n- `.getInfo()` inside a loop (move logic server-side).\n- Missing `scale` in reduceRegion(s) → zoom-dependent statistics.\n- Landsat C2 used without scale factors → reflectance > 1.\n- `bestEffort=True` hiding resolution degradation.\n- Median composite including cloudy pixels (mask BEFORE reduce).\n- Python conditionals on server-side objects (always false-y).\n- Trend maps without valid-observation-count masking.\n\n## Execution contract\n\n- **Workflow:** define collection and period; build a server-side mask and transform pipeline; test on a small region; compute; verify scale and projection; export reproducibly.\n- **Decision rules:** use Earth Engine for planetary archives and scalable aggregation, local tools for sensitive or offline data, and batch exports for work beyond interactive limits.\n- **Verification protocol:** probe bands, projection, scale, masks, and observation counts; inspect spatial samples; cross-check one exported statistic locally; record collection versions and parameters.\n- **Failure modes:** stop for client-side loops, implicit scale, masked-pixel bias, quota-driven silent degradation, expired assets, or unbounded region operations.\n- **Deliverables:** runnable script, collection and date manifest, mask and reducer parameters, task/export settings, verification evidence, and exported asset inventory.\n- **Source freshness:** consult [the authoritative source registry](references/authoritative-sources.md) at execution time for catalog, API, quota, and policy changes.\n"
}SHA-256: 99ca63349ef6f23de39beba303a41b26c6fd360dd91fa4ac11b7fe98248b3a29