Install
openclaw skills install @ruiduobao/geoskill-nasa-dataset-downloadDownload any NASA Earth observation dataset (HDF / NetCDF / GeoTIFF) end-to-end. Wraps the official earthaccess library to authenticate with NASA Earthdata Login and bulk-download granules from MODIS, VIIRS, GPM, Sentinel, SMAP, ASTER, etc. Supports BBox + temporal window filtering and QA sidecars. Default credentials are loaded from ~/.geoskill/secrets.json (NASA Earthdata bearer token). 0.2.0: alias map (description → short_name), multi-word search, --dry-run, proper exit codes (5 on 0 results), accurate --max-files, fixed granule display.
openclaw skills install @ruiduobao/geoskill-nasa-dataset-downloadEnd-to-end download of any NASA Earth observation dataset. Built on top
of earthaccess (NSIDC's
official Python SDK) so it handles MODIS, VIIRS, GPM,
Sentinel-1, SMAP, ASTER, MERRA-2, and thousands of
other NASA datasets through a uniform CLI.
# 0. one-time: put your Earthdata bearer token in ~/.geoskill/secrets.json
# (or set $EARTHDATA_TOKEN in your env)
python scripts/nasa_dataset_download.py login
# [OK] EARTHDATA_USERNAME source=user_secrets available=True
# [OK] EARTHDATA_TOKEN source=user_secrets available=True
# Attempting live login with earthaccess.login()...
# OK: earthaccess.authenticated=True
# 1. browse the 52K offline catalog for inspiration
python scripts/nasa_dataset_download.py known MOD11A1
# 2. list available granules
python scripts/nasa_dataset_download.py search MOD11A1 \
--version 061 --temporal-start 2024-06-01 --temporal-end 2024-06-01 \
--bbox 115 39 117 41
# 3. download 2 granules (defaults to ./output/<short_name>/)
python scripts/nasa_dataset_download.py download MOD11A1 \
--version 061 --temporal-start 2024-06-01 --temporal-end 2024-06-01 \
--bbox 115 39 117 41 --max-files 2
# 4. print URLs only (no download)
python scripts/nasa_dataset_download.py urls MOD11A1 \
--version 061 --temporal-start 2024-06-01 --temporal-end 2024-06-01 \
--bbox 115 39 117 41 --out urls.json
| Subcommand | Network | Purpose |
|---|---|---|
login | Yes | Authenticate with Earthdata; show credential state |
known | No | Browse the bundled 52K offline catalog + alias map (multi-word AND search) |
search | Yes | List granules for a dataset in BBox + time window. Description-style names ("land surface temperature") print an alias hint suggesting canonical short_name(s). |
download | Yes | Bulk-download granules to a local directory. --dry-run previews; --max-files actually limits downloads. |
urls | Yes | Print granule URLs (no download); also writes a structured JSON sidecar via --out. |
data/aliases.json (50 entries) maps natural-language descriptions to
canonical short_names. Lets users search by what they know, not by what
they've memorized:
# user types a description, skill suggests the right short_name
python scripts/nasa_dataset_download.py known "land surface temperature"
# -> alias match: 'land surface temperature' -> MOD11A1, MOD11A2, MOD11B, MOD11_L2, ...
# and 10 catalog records like MOD11A1 | MODIS/Terra LST/Emissivity Daily L3
# search with description also gets the hint
python scripts/nasa_dataset_download.py search "land surface temperature" --temporal-start 2024-06-01 --bbox 115 39 117 41
# stderr: hint: 'land surface temperature' matched the alias map; try the canonical short_name(s): MOD11A1, ...
# disable hinting per-invocation
python scripts/nasa_dataset_download.py search "MOD11A1" --no-alias-resolve
Other entries: MODIS LST, surface reflectance, land cover,
vegetation index, NDVI, snow cover, sea ice, precipitation,
IMERG, GPM, rainfall, soil moisture, SMAP, SST, ocean color,
active fire, evapotranspiration, Sentinel-1, Landsat, DEM, ASTER,
LAI, GPP, ET.
--format {text,json} — output format--qa PATH — write a JSON run-summary sidecar to PATH (mirrors Phase 5 convention)--bbox W S E N — geographic bounding box in WGS84--temporal-start YYYY-MM-DD / --temporal-end YYYY-MM-DD — date range (inclusive)--count N — max results--max-files N (download only) — actually limits downloads (was buggy in v0.1.0)--dry-run (download only) — print what would be downloaded; no files written--no-alias-resolve (search only) — skip the alias-map hint when short_name looks like a descriptionPer geoskill-core §2.2, search returns exit 5 when 0 granules match (v0.1.0 silently exited 0). The error output now lists possible causes and suggests a fix:
$ python scripts/nasa_dataset_download.py search NOTAREAL --temporal-start 2024-06-01 --temporal-end 2024-06-01
no granules found. Possible causes:
- 'NOTAREAL' may be a description, not a short_name
- the date 2024-06-01 may be out of range for this dataset
- try `nasa-dataset-download known "NOTAREAL"` to find a similar short_name
- or check spelling: e.g. MOD11A1 (not MOD11A-1), GPM_3IMERGHH (not IMERG)
$ echo $?
5
This skill authenticates with NASA Earthdata Login (covers all EOSDIS data centers: LAADS, GES DISC, LP DAAC, ASF, NSIDC, CMR, AppEEARS, Worldview). Resolution order:
EARTHDATA_USERNAME / EARTHDATA_PASSWORD / EARTHDATA_TOKEN env vars~/.geoskill/secrets.json (user-level, not vendored)~/.netrc entries (machine urs.earthdata.nasa.gov)Bearer token is preferred for CMR / LP DAAC earthdata cloud / GES DISC since it works with both modern (CMR-driven) and legacy endpoints.
// C:\Users\<you>\.geoskill\secrets.json
{
"EARTHDATA_USERNAME": "ruiduobao",
"EARTHDATA_PASSWORD": "Ruiduobao123",
"EARTHDATA_TOKEN": "eyJ0eXAiOiJKV1Q..."
}
Generate a bearer token at https://urs.earthdata.nasa.gov/profile.
| Service | URL | Auth | Datasets |
|---|---|---|---|
| CMR | https://cmr.earthdata.nasa.gov/search/ | optional | All NASA |
| LP DAAC earthdata cloud | https://data.lpdaac.earthdatacloud.nasa.gov/ | bearer | MODIS Land / SRTM / ASTER |
| GES DISC | https://data.gesdisc.earthdata.nasa.gov/data/ | bearer | GPM / MERRA-2 / TRMM |
| LAADS archive (legacy) | https://ladsweb.modaps.eosdis.nasa.gov/archive/allData/ | basic | MODIS L1 / atmosphere |
Verified on 2026-07-27 (Beijing BBox, 2024-06-01) — all 10 datasets downloaded successfully via Earthdata bearer token:
| # | Dataset | Provider | Size | Format |
|---|---|---|---|---|
| 1 | MOD11A1 v061 | LP DAAC | 3.95 MB | HDF4 |
| 2 | MOD09GA v061 | LP DAAC | 173.6 MB | HDF4 |
| 3 | GPM_3IMERGHH v07 | GES DISC | 16.1 MB | HDF5 |
| 4 | MOD11A2 v061 | LP DAAC | 13.6 MB | HDF4 |
| 5 | MOD10A1 v61 | NSIDC | 17.0 MB | HDF4 |
| 6 | MOD13Q1 v061 | LP DAAC | 235.2 MB | HDF4 |
| 7 | MOD09A1 v061 | LP DAAC | 130.4 MB | HDF4 |
| 8 | GPM_3IMERGDF v07 | GES DISC | 31.95 MB | HDF5 |
| 9 | MOD14A1 v061 | LP DAAC | 0.9 MB | HDF4 |
| 10 | MOD21A1D v061 | LP DAAC | 2.6 MB | HDF4 |
Total: 16 files, 625 MB, 148 seconds via VPN 7897.
23 tests (all PASSED on 2026-07-27):
test_catalog_exists, test_load_catalog, test_search_catalog_*, test_search_catalog_multiword*test_alias_map_loaded, test_resolve_alias_*test_granule_info_keystest_cli_help, test_cli_version, test_cli_login_shows_creds, test_cli_known_search, test_cli_known_qa_sidecar, test_cli_known_multikeywordtest_cli_search_no_match_exit5, test_cli_download_dry_runtest_live_login, test_live_search_mod11a1, test_live_search_gpm, test_live_search_mod09gaPlus a 20-question end-to-end regression (.user-test/regression_test.py)
that runs every realistic user question and asserts the expected outcome
(20/20 PASS in ~70s wall clock).
cd nasa-dataset-download
python -m pytest --tb=short
# ============================= 23 passed in ~24s =============================
python .user-test/regression_test.py
# 20/20 questions PASSED
The existing modis-lst-download, gpm-download, and download-dem
each target one product line. nasa-dataset-catalog searches 52K
datasets but doesn't handle bulk download well. This skill fills
both gaps:
earthaccess SDK (NSIDC's maintained library)~/.geoskill/secrets.json for credentials (single place
for all 40+ skills)Per geoskill-core §2.2: 0=success, 2=arg, 3=missing dep, 4=network, 5=no match, 6=data validation, 7=processing, 130=interrupt.
earthaccess.search_data(cloud_hosted=True))
not exposed as a separate subcommand yet — use the Python API for thosegpm1.gesdisc.eosdis.nasa.gov/opendap/) not
supported; use the new data.gesdisc.earthdata.nasa.gov/data/ path--count; raise if you need moredata/aliases.json) has 50 entries; the offline catalog has
52K. For unmapped descriptions, known falls back to multi-word AND
search across the offline catalog and may surface false positives
(e.g. "Sentinel-1" hits ESA Greenland records that mention sentinel in
the title). When in doubt, the alias hint suggests canonical short_names.search output (g.title / g.size_in_mb /
g.get_umm() were broken in earthaccess 0.18); --max-files now
actually limits downloads (was reporting-only in v0.1.0); --dry-run
on download; 0-result search returns exit 5 with hint; suppressed
FutureWarning noise; JSON output now includes granule_id, size, day/night,
production_dt, temporal range, data_links, cloud_hosted flag. 23 tests +
20-question regression. 0 fail, 0 skip-with-fail.MIT. earthaccess is Apache-2.0. Bundled data/nasa_catalog.json
from https://github.com/opengeos/NASA-Earth-Data (MIT).