geo-data-engineering — Claude Code data skill: what it does
Keeps an agent on track when spatial data has to be fetched, cleaned or pushed through a pipeline that has to run again next month.
npx skills add muend/geoai-skills --skill geo-data-engineering -a claude-codeWhat geo-data-engineering does
The skill picks up at the messy middle of GIS work: acquiring data, repairing it, then writing something downstream tools can read. Format choice comes first in its guidance. GeoParquet for columnar analysis, GeoPackage for desktop exchange, FlatGeobuf for range reads over HTTP, COG for every raster deliverable, Zarr or NetCDF when time and band dimensions both exist. Shapefile gets a short list of reasons to avoid it: truncated column names, the 2 GB cap, encoding trouble.
Sources are handled one by one. Small OSM extracts go through osmnx; bigger ones come from Geofabrik PBF with pyrosm or osmium. Overture Maps on S3 or Azure, queried with DuckDB spatial, is the suggested route for buildings and places at scale. Whatever you pull, the skill wants a DATA_SOURCES.md beside the data with URL, query parameters, retrieval date and license. Coordinate systems get their own section: keep EPSG:4326 or the source CRS on disk, analyse in a projected one fitted to the extent, and enable transformation grids when sub-meter accuracy matters.
For the cleanup pass there is scripts/clean_vector.py, or call clean_vector() directly. It removes empty and null geometries, runs make_valid on broken ones, dedupes, reprojects, and prints counts at each step. That printout is the point — silent feature loss gets caught. Data too large for memory should go to DuckDB spatial over GeoParquet or dask-geopandas, and rasters should be read in windows rather than loaded whole.
What it helps with
- pull an OSM extract and filter it by tag values
- convert a vector layer to GeoParquet without dropping the CRS
- repair invalid geometries and report how many features were lost
- run a cross-table join that outgrows one machine's memory
- record data provenance so a download can be repeated later
Example prompts for the agent
- Grab Overture buildings for my area and save them as GeoParquet
- Run
buildings.geojsonthroughclean_vector.pyand show me the count report - Reproject the layer into its local UTM zone before I compute areas
How to install geo-data-engineering
1Skills CLI (Vercel)
npx skills add muend/geoai-skills --skill geo-data-engineering -a claude-code2Manually: put the files in place
~/.claude/skills/geo-data-engineering/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/geo-data-engineering/
1Skills CLI (Vercel)
npx skills add muend/geoai-skills --skill geo-data-engineering -a codex2Manually: put the files in place
.agents/skills/geo-data-engineering/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add muend/geoai-skills --skill geo-data-engineering -a cursor2Manually: put the files in place
.cursor/skills/geo-data-engineering/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install muend/geoai-skills geo-data-engineering2Manually: put the files in place
.github/skills/geo-data-engineering/SKILL.md1Skills CLI (Vercel)
npx skills add muend/geoai-skills --skill geo-data-engineering -a gemini-cli2Platform CLI
gemini skills install https://github.com/muend/geoai-skills --path skills/geo-data-engineeringManually: put the files in place
.devin/skills/geo-data-engineering/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add muend/geoai-skills --skill geo-data-engineering -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about geo-data-engineering
How do I install geo-data-engineering in Claude Code?
Run npx skills add muend/geoai-skills --skill geo-data-engineering -a claude-code, then confirm ~/.claude/skills/geo-data-engineering/SKILL.md exists.
What does geo-data-engineering do?
It walks an agent through the spatial data workflow: acquire with provenance, inspect CRS and schema, clean deterministically, validate, write an analysis-ready artifact. It also advises on format and engine for the data at hand.
Does it replace PostGIS?
No. For database execution the skill defers to PostGIS and its companion skill. On files alone it works with GeoPandas, DuckDB spatial and pyrosm.
Source text
SKILL.md · MIT
--- name: geo-data-engineering description: >- Always invoke when geospatial data must be acquired, prepared, repaired, scaled, or moved through a repeatable pipeline. Covers open-data/OSM/STAC acquisition, spatial formats, CRS transforms, quality checks, and batch ETL architecture for growing or recurring joins. Invoke alongside PostGIS for database execution and alongside SWE standards when code is delivered. Do not trigger merely because another specialist reads analysis-ready data. license: MIT metadata: author: Muhammed Enes Duran --- # Geospatial Data Engineering Purpose: get spatial data into a clean, validated, analysis-ready state with a repeatable pipeline — the stage where most real-world GIS time is spent and most silent errors are born. ## Format selection | Format | Use for | Avoid because | |---|---|---| | **GeoParquet** | Analysis interchange, big vector, columnar workflows | Not yet readable by some legacy desktop GIS | | **GeoPackage** | Desktop GIS exchange, multi-layer projects | Slower than Parquet at scale; SQLite locking | | **FlatGeobuf** | Streaming, HTTP range reads | Single layer | | **COG** (Cloud-Optimized GeoTIFF) | All raster deliverables | — (make every GeoTIFF a COG) | | **Zarr/NetCDF** | Multi-dimensional (time × band × y × x) | Overkill for single rasters | | Shapefile | Only when a legacy tool demands it | 10-char columns, 2 GB cap, encoding chaos, multi-file fragility | | CSV + WKT/lon-lat | Simple point exchange | No CRS metadata — document it explicitly | ## Acquisition playbook - **OpenStreetMap**: small areas → `osmnx`; large extracts → Geofabrik PBF + `pyrosm`/`osmium`. Respect tag heterogeneity: always inspect tag value distributions before filtering. - **Buildings/places at scale**: Overture Maps (GeoParquet on S3/Azure, query with DuckDB spatial — often the fastest path). - **Satellite/raster**: STAC APIs via `pystac-client` + `odc-stac` — see `remote-sensing-analysis`; planetary archives → `google-earth-engine`. - **Boundaries**: authoritative national source first; Natural Earth / GADM / geoBoundaries for global work — record which, versions differ materially. - Record every acquisition: source URL, query parameters, retrieval date, license. Put it in a `DATA_SOURCES.md` next to the data. ## CRS engineering - Store in EPSG:4326 or source CRS; **analyze** in a projected CRS suited to the extent: local UTM zone (`gdf.estimate_utm_crs()`), national grid, or equal-area (EPSG:6933/Mollweide) for cross-region area stats. - Datum shifts matter at sub-meter precision: transformations between datums need the right transformation grid (`pyproj.network.set_network_enabled(True)` when accuracy matters). - Never strip or overwrite a CRS to "fix" misaligned layers — diagnose which layer is wrong with a known landmark instead. ## Cleaning pipeline Run `scripts/clean_vector.py` (or import its `clean_vector()` function) as the standard hygiene pass: drops empty/null geometries, repairs invalid ones with `make_valid`, de-duplicates, reprojects, and **prints an accounting report** so silent data loss is impossible. Then: normalize text attributes (trim, collapse whitespace, locale-aware casefold — beware Turkish İ/ı, German ß), coerce dtypes explicitly, and show `value_counts()` of every categorical you will later filter on. ## Scale strategies - **Fits in RAM**: GeoPandas + Shapely 2 vectorized ops. Ensure the spatial index is used (`sjoin`, `query_bulk`) — hand-rolled loops are O(n²). - **Bigger than RAM, single machine**: DuckDB `spatial` extension over GeoParquet (predicate pushdown + spatial SQL), or `dask-geopandas`. - **Served / concurrent / transactional**: PostGIS — see `postgis-spatial-sql`. - Rasters: windowed reads (`rasterio.windows`), chunked xarray + dask; never `read()` a 50 GB mosaic into memory. ## Pipeline standards - Idempotent steps with explicit inputs/outputs on disk; re-running never corrupts state. - Checkpoint after expensive stages (download, big join) in GeoParquet/GPKG. - Log an accounting line per stage: rows/features/pixels in → out. - Deterministic ordering before writing (sort by stable key) so diffs are meaningful. ## Pitfalls checklist - CSV opened without declaring lon/lat columns' CRS. - Shapefile column names silently truncated on export. - Encoding mojibake from legacy files (try `encoding="utf-8"` then cp1252). - Mixed geometry types in one layer (Polygon + MultiPolygon breaks some tools — normalize with `.explode()` or promote to Multi*). - Antimeridian and pole-crossing geometries after naive reprojection. - Downloaded "latest" data with no recorded version/date — unreproducible. ## Execution contract - **Workflow:** inventory sources and contracts; acquire with provenance; inspect CRS, schema, geometry, and scale; clean deterministically; validate; write an analysis-ready artifact. - **Decision rules:** select formats and engines from size, geometry, concurrency, and downstream access needs; never infer CRS or destructive repairs silently. - **Verification protocol:** reconcile feature or pixel counts at every stage, assert CRS and geometry invariants, sample outputs spatially, and rerun to confirm idempotence. - **Failure modes:** quarantine ambiguous CRS, mixed units, invalid encodings, lossy format conversions, or unexplained row loss instead of guessing. - **Deliverables:** validated dataset, machine-readable schema and CRS, provenance manifest, accounting log, rejected-record report, and reproducible pipeline. - **Source freshness:** consult [the authoritative source registry](references/authoritative-sources.md) before using version-sensitive formats or APIs and record the checked date.
© Muhammed Enes Duran · MIT · muend/geoai-skills