Skip to content

Latest commit

 

History

History
190 lines (147 loc) · 13 KB

File metadata and controls

190 lines (147 loc) · 13 KB

Usage guide — running the ECCO Skills yourself

This is the hands-on guide for developers and analysts who want to run the skills directly (rather than through an AI assistant). It covers setup, credentials, the exact commands, the call sequence behind each question, running the tests, and the technical notes worth knowing.

New here? The README explains what the project is and what you can ask. This document is the how.


What a "skill" is here

These are Agent Skills in the Claude Code / Claude Agent SDK sense — not a plain Python library. Each skill is a directory containing:

  • SKILL.md — the guidance the agent reads: which fields to load and why that one, which grid position each quantity lives on, the correct operation sequence, masking/weighting rules, unit expectations, and known failure modes. This is the guardrail.
  • scripts/ — small, tested helper code the guidance points the agent to call rather than re-derive, so outputs are reproducible instead of freshly hallucinated each run.
  • references/ (science skills) — the skill's acceptance evidence: why we trust this, kept inside the skill folder so it travels with it.

A bare library makes the AI a caller (it can still call it wrongly); a skill makes the AI a guided author that assembles the correct calculation and can fall back to the vetted helper. You can also run the scripts/ directly, as shown below.


1. Prerequisites

  • Python 3.11 or 3.12 (the supported band). The setup skill will tell you if your default python3 is out of band — a common trap is a Homebrew python3 that is too new (e.g. 3.14). On macOS: brew install python@3.12.
  • A free NASA Earthdata Login account, with credentials in ~/.netrc (needed to download ECCO data from PO.DAAC):
    machine urs.earthdata.nasa.gov
        login    YOUR_USERNAME
        password YOUR_PASSWORD
    

2. Build the environment

The ecco-setup skill surveys your machine's Python, builds an isolated project-local .venv/ (venv + pip only, no conda), installs the scientific stack, and verifies it works:

python3 .claude/skills/ecco-setup/scripts/survey.py       # read-only: what Python do I have?
python3 .claude/skills/ecco-setup/scripts/setup_env.py    # build .venv and verify

Everything afterward runs with .venv/bin/python — no manual "activate" needed.

If a skill ever fails on the environment (e.g. no such file or directory: .venv/bin/python because the gitignored .venv was deleted/never built, or an import error): run verify mode first to diagnose, then rebuild only if needed —

python3 .claude/skills/ecco-setup/scripts/verify_env.py     # verify mode: is the .venv there & healthy?
python3 .claude/skills/ecco-setup/scripts/setup_env.py --reset   # rebuild if verify says it's missing/broken

Each calc/plot/data skill's SKILL.md opens with an "Environment — do this first" block saying the same, so an AI assistant driving the skills will self-heal the environment without being told. (A healthy .venv is reused automatically — this is a one-time build.)

3. Run a calculation

# Ocean heat content, and its change between two months:
.venv/bin/python .claude/skills/compute-ocean-heat-content/scripts/run.py 2000-01 2010-01

# Geostrophic velocities for a month:
.venv/bin/python .claude/skills/compute-geostrophic-balance/scripts/run.py 2000-01

# Thermal-wind shear + velocity reconstruction for a month:
.venv/bin/python .claude/skills/compute-thermal-wind/scripts/run.py 2000-01

# Wind-stress curl + Ekman pumping for a month:
.venv/bin/python .claude/skills/compute-curl/scripts/run.py 2000-01

# Steric height (+ thermosteric/halosteric split) for a month:
.venv/bin/python .claude/skills/compute-steric-height/scripts/run.py 2000-01

# Plot a global sea-surface-temperature map:
.venv/bin/python .claude/skills/plot-ecco-field/scripts/run.py \
    --collection ECCO_L4_TEMP_SALINITY_LLC0090GRID_MONTHLY_V4R4 \
    --var THETA --month 2000-01 --mode global --cmap RdYlBu_r

First use downloads only the granules requested (tens of MB) and caches them in ./data/ecco/; repeat runs reuse the cache. A size guard stops you before an accidental multi-GB pull.

4. Run the tests (offline, no credentials needed)

.venv/bin/python .claude/skills/run_all_tests.py

What actually runs when you ask a question

A user arrives with a question, not a skill name. Each question maps to a small chain of skills that run in order — and every skill narrates what it's doing as it goes (teach-as-you-go). The table shows the built calculations and the exact sequence each one triggers:

You ask… Skills invoked, in order What each step does
"How much has global ocean heat content changed between January 2000 and January 2010?" 1. load-grid2. load-field (THETA/SALT, month A) → 3. validate4. load-field (THETA/SALT, month B) → 5. validate6. difference Grid gives cell volumes (rA·drF·hFacC); each month's temperature is volume-weighted and summed to OHC; the physical-bounds/benchmark checks run per month; the two are differenced (the change is what's physical).
"Compute the geostrophic velocities for January 2008." 1. load-grid2. load-field (density/pressure RHOAnoma,PHIHYDcR) → 3. compute4. validate Grid supplies dxC/dyC, YC, and the xgcm object; the pressure gradient is differenced on the C-grid and interpolated to tracer points; v_g = ρ⁻¹∂p/∂x / f; runtime checks confirm grid position, units, and off-equator bounds.
"For January 2015, if I only knew the ocean's density, how well could I reconstruct the deep currents?" / "Where does the density structure control the vertical shear of the currents in January 2010?" (thermal wind) 1. load-grid2. load-field (density RHOAnoma) → 3. compute shear ∂u/∂z,∂v/∂z4. reconstruct velocity from z0=−3000 m5. validate6. load-field (UVEL/VVEL) → 7. cross-check vs actual velocity Grid supplies dxC/dyC, drC, Z/Zl/Zu, YC; the density gradient gives the thermal-wind shear (g/fρ)∂ρ/∂x; integrating it up/down from a level of no motion reconstructs the velocity; the reconstruction is then compared to the model's actual UVEL/VVEL (the currents field is loaded only for this check).
"Where is the wind driving surface water down into the ocean (Ekman pumping) in January 2010?" 1. load-grid2. load-field (stress oceTAUX/oceTAUY) → 3. wind-stress curl (two LLC rotations) → 4. Ekman pumping w_E5. validate6. load-field (WVEL) → 7. cross-check vs actual vertical velocity Grid supplies dxC/dyC, CS/SN, YC; stress is interpolated to centers then curled via the mandatory two rotations; w_E = curl(τ)/(ρf) + β·τ/(ρf²); compared to the model's actual WVEL (loaded only for the check). Uses total stress oceTAUX/oceTAUY, not the bulk EXFtaux/y.
"How much of sea level is set by the ocean's density (steric height) in January 2000?" 1. load-grid2. load-field (density RHOAnoma) + (THETA/SALT) + (SSH/ETAN) → 3. specific-volume anomaly vs a JMD95 reference4. integrate 0→2000 dbar (z*/hFacC-weighted)5. thermo/halo split6. validate7. cross-check vs actual SSH Grid supplies Z/Zl/Zu, hFacC, Depth, rA; the base term uses the model's own RHOAnoma (no EOS), the reference profile + T/S split use the vendored JMD95 EOS; the steric anomaly is compared to the model's actual SSH.
"Show me a global map of sea-surface temperature for June 2000." 1. load-grid2. load-field (THETA) → 3. plot-ecco-field (--mode global) Grid gives XC/YC for re-projection; the field is loaded for the requested month; the official ecco_v4_py plotter stitches the 13 tiles into a lat-lon PNG in ./plots/.
"Map the salinity at 1000 m for March 2005 (and plot any calculation's result too)." 1. load-grid2. load-field (SALT) → 3. plot-ecco-field (--mode global --depth 1000) Same plotter, at a chosen depth level — as a stitched global map, a single LLC tile, or all 13 tiles. It also renders a calculation's output (e.g. geostrophic-speed, Ekman-pumping, or steric-height maps).
"Set up my environment" / "is my environment working?" 1. ecco-setup set-up mode (survey → build .venv → install → auto-run verify) — or verify mode alone for a health-check Surveys the machine's Python, builds the isolated .venv, installs the stack, then proves it works (imports + a real ecco.get_llc_grid smoke test). Verify is a mode of the same skill and is also runnable on its own (no rebuild).

Under every load-grid / load-field step sits the shared ecco_common layer: check the local ./data/ecco cache → on a miss, query the NASA CMR API for the granule's real download URL → size-guard the request → download with ~/.netrc auth → cache and open as xarray. You never call that layer directly; the skills compose it.

The rows above are the built calculations (all five science skills + plotting + environment). Questions about section transports and heat/salt budgets are designed (see design.md → Calculation Recipes) but not yet implemented — most are gated on domain-expert input — and the table will grow as those land.


Repository layout

.claude/skills/
├── ecco-setup/                 # build the project-local .venv (survey → install → verify)
│                               #   scripts/: survey.py, setup_env.py, verify_env.py (verify mode)
├── ecco-common/                # SHARED library imported by every calc skill (composition backbone)
│   ├── ecco_common/            #   loaders, cache, CMR access, plots, grid_ops (Level-1 primitives)
│   ├── ecco_preflight.py       #   stdlib-only env guard: clear "run ecco-setup" msg on a broken .venv
│   ├── vendor/                 #   pinned official ecco_po_tutorials.py + jmd95.py (verification refs)
│   └── tests/                  #   offline regression suites (ecco_common, grid_ops, preflight)
├── load-grid/                  # load LLC90 geometry + build the xgcm grid object
├── load-field/                 # download/cache any ECCO science field by month/day
├── plot-ecco-field/            # PNG of a field: single tile / all tiles / stitched global map
├── compute-ocean-heat-content/ # ✅ Recipe 1 — volume-weighted OHC + change between months
├── compute-geostrophic-balance/# ✅ Recipe 2 — geostrophic velocities from pressure/density
├── compute-thermal-wind/       # ✅ Recipe 3 — vertical shear from density + velocity reconstruction
├── compute-curl/               # ✅ wind-stress curl + Ekman pumping (vs the model's WVEL)
├── compute-steric-height/      # ✅ steric height + thermosteric/halosteric split (vs SSH)
└── run_all_tests.py            # single entry point for all offline test suites

docs/                           # living design + verification docs

Key technical notes

  • xgcm is pinned < 0.10 (we use 0.9.0). ecco_v4_py 1.8.1's get_llc_grid() calls xgcm.Grid(ds, periodic=False, ...), and periodic= was removed in xgcm 0.10 — so ECCO's own grid constructor crashes on ≥ 0.10. Do not relax this pin without re-testing ecco.get_llc_grid().
  • Downloads use the NASA CMR API + requests/.netrc directly, not ecco_access auto-resolution (which was unreliable in 0.3.1). The cache is project-local, on-demand, and size-guarded. The skills do not depend on any MCP server at runtime (see design.md → Data Access Pattern).
  • Data is never committed. .gitignore excludes /data/, /.venv/, and /plots/.
  • Environment guard. Every calc/plot/data run.py calls ecco_preflight.ensure_env() (a stdlib-only module) before importing the heavy stack, so a broken .venv yields a clear "run ecco-setup" message rather than a raw traceback. A missing .venv (script can't even start) is handled by the "Environment — do this first" block in each SKILL.md.
  • Vendored, pinned references. ecco-common/vendor/ holds ecco_po_tutorials.py (the official tutorial helpers, used as a Rung-1 verification reference) and jmd95.py (the MITgcm equation of state, needed by steric height) — both pinned to a fixed upstream commit. No EOS package (gsw) is required.

Deeper reference