> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mireye.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# GET /v1/meta/fields

> Self-discovery: field + preset catalog with ETag-based caching.

## When to use this

Hit `/v1/meta/fields` once at startup to discover the catalog. The
response sets `ETag` and `Cache-Control: public, max-age=3600`, so a
long-lived agent or service fetches it once an hour at most. The catalog
drives:

* **Client-side validation** — reject unknown field names before sending
  a `/v1/fetch` request.
* **Tool descriptions** — agents that build their own UI from the
  catalog populate field pickers and preset selectors from this endpoint.
* **LLM planners** — third-party agents that route to Mireye via the MCP
  server can render the catalog into their own planner system prompt,
  same as Mireye's `/v1/ask` does internally.

## Response shape

```jsonc theme={null}
{
  "fields": [
    {
      "derivation": null,
      "description": "Ground elevation above the NAVD88 vertical datum at the queried point. Sourced from the USGS 3DEP 1/3 arc-second seamless DEM (~10m), with the USGS EPQS dynamic service as a coverage fallback.",
      "interpretation_hints": "Below 10m within 5km of the coast \u2192 storm-surge exposure relevant. Above 3000m \u2192 alpine permitting, snow loads. Combine with coast_distance_m and within_floodplain_polygon for flood-zone reasoning.",
      "layer": "terrain",
      "lifecycle": "stable",
      "name": "elevation",
      "null_meaning": null,
      "nullable": false,
      "presets": [
        "terrain",
        "flood_risk",
        "wildfire_underwrite",
        "site_selection",
        "wind_siting"
      ],
      "source": "USGS_3DEP",
      "source_url": "https://www.usgs.gov/3d-elevation-program",
      "ttl_seconds": 31536000,
      "type": "float",
      "unit": "meters"
    }
    /* ...295 more fields, ordered by layer */
  ],
  "presets": {
    "terrain": ["elevation", "slope_degrees", "aspect_cardinal", "coast_distance_m", "soil_drainage_class", "bedrock_depth_cm"],
    "flood_risk": ["elevation", "coast_distance_m", "within_floodplain_polygon", "intersects_nhd_area", "intersects_wetland", "wetland_type", "wetland_subtype", "wetland_acres", "nearest_wetland_distance_m", "wetlands_within_100m_count", "wetlands_within_500m_count", "surface_water_permanence_pct", "nearest_waterbody_name"]
    /* ...13 more presets */
  },
  "us_envelope": {
    "lat_max": 72.0,
    "lat_min": 18.0,
    "lng_max": -65.0,
    "lng_min": -180.0
  },
  "version": "0.14.0"
}
```

## Self-discovery flow

The recommended client pattern:

```python theme={null}
import httpx, time

BASE = "https://api.mireye.com"

class CatalogClient:
    def __init__(self):
        self._etag: str | None = None
        self._catalog: dict | None = None
        self._fetched_at: float = 0.0

    async def get(self) -> dict:
        # Refresh at most once an hour, even if our cache lies.
        if self._catalog and time.time() - self._fetched_at < 3600:
            return self._catalog

        headers = {}
        if self._etag:
            headers["If-None-Match"] = self._etag

        async with httpx.AsyncClient() as c:
            r = await c.get(f"{BASE}/v1/meta/fields", headers=headers)

        if r.status_code == 304:
            self._fetched_at = time.time()
            return self._catalog  # unchanged

        r.raise_for_status()
        self._etag = r.headers["ETag"]
        self._catalog = r.json()
        self._fetched_at = time.time()
        return self._catalog
```

`If-None-Match` returns `304 Not Modified` with no body when the catalog
hasn't changed. The `ETag` covers the whole payload, so any catalog
change — new fields, edited hints, preset changes — produces a fresh
`ETag` alongside the `version` bump (see the [versioning
policy](#versioning)).

Each field object also carries honesty metadata: `nullable` marks fields
that can legitimately return `null` at valid coordinates, and
`null_meaning` says what such a null means (e.g. "no wetland within the
search radius") so clients don't misread semantic absence as a fetch
failure.

## How the catalog drives the planner

Mireye's own `/v1/ask` planner renders the catalog into its system
prompt:

```
You are a geospatial data planner. Given a US coordinate and a natural-
language question, pick the catalog fields needed to answer it.

Available fields:
  elevation (terrain, float, meters) — Ground elevation above NAVD88...
    Hint: Use this when the caller asks about elevation...
    Presets: terrain, flood_risk, site_selection, wildfire_underwrite
  slope_degrees (terrain, float, degrees) — Slope at the coordinate...
    Hint: Spread potential for wildfire; higher = faster spread...
  /* ... */

Presets (use one of these instead of listing fields if it fits):
  flood_risk: elevation, coast_distance_m, within_floodplain_polygon, ...
  /* ... */
```

The system prompt is **prompt-cached** (catalog-sized — roughly 19 K
tokens at catalog 0.6.0) so subsequent planner calls pay \~90% off input
cost.
Third-party agents that build their own planner can use the exact same
pattern.

## Versioning

The `version` field is a manual SemVer bump maintained alongside the
catalog source (`src/mireye_earth/ask/catalog.py`, which carries the
version history as a changelog comment):

* **Patch** (e.g., `0.6.0` → `0.6.1`) — wording-only changes:
  `description` or `interpretation_hints` improved, no field added or
  changed. Safe to ignore for existing clients.
* **Minor** (`0.5.x` → `0.6.0`) — additive, backwards-compatible
  changes: new fields or new presets registered. Existing field names,
  types, and semantics are untouched. (This is the common case — the
  catalog moved `0.2.0` → `0.6.0` through additive field registrations.)
* **Major** (`0.x.y` → `1.0.0`) — breaking: field renamed, type changed,
  or removed. Clients hardcoding field names must be updated.

The version is only available in the response body — read it from the
JSON (there is no version response header).


## OpenAPI

````yaml GET /v1/meta/fields
openapi: 3.1.0
info:
  title: Mireye Earth
  description: >-
    Provenance-tagged geospatial data for US coordinates. POST /v1/fetch for
    deterministic field values; POST /v1/ask for natural-language Q&A; GET
    /v1/meta/fields for the catalog.
  version: 0.14.0
servers: []
security: []
paths:
  /v1/meta/fields:
    get:
      summary: Meta Fields
      description: >-
        Return the public catalog + presets + US envelope.


        ``?lifecycle=`` filters the listed fields (default hides
        ``experimental``;

        ``all`` includes everything; or a specific lifecycle). Sets ETag +

        Cache-Control so clients can skip re-download for an hour. Honors

        If-None-Match → 304.
      operationId: meta_fields_v1_meta_fields_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}

````