Skip to content

Configuration Reference

Client apps configure geo-agent via layers-input.json. All fields except catalog and collections are optional.

Top-level fields

FieldRequiredDescription
catalogYesSTAC catalog root URL. The app traverses child links to find collection metadata.
collectionsYesArray of collection specs — see below.
titiler_urlNoTiTiler server for COG/raster tile rendering. Defaults to https://titiler.nrp-nautilus.io.
mcp_urlNoMCP server URL for DuckDB SQL queries. Omit to disable analytics.
viewNoInitial map view — see below.
llmNoLLM configuration — see below. Omit for server-provided mode.
welcomeNoWelcome message: { "message": "...", "examples": ["...", "..."] }
default_basemapNoWhich basemap is active on load: "natgeo" (default), "satellite", or "plain".
custom_basemapNoReplace the NatGeo slot with a custom tile URL — see below.
linksNoOptional links shown in the chat UI — see below.

View

Controls the initial camera position. All fields are optional.

FieldTypeDefaultDescription
center[lon, lat][-119.4, 36.8]Initial map center (longitude first).
zoomnumber6Initial zoom level (0–22).
pitchnumber0Camera tilt in degrees (0 = flat, 60 = steep).
bearingnumber0Map rotation in degrees clockwise from north (0 = north-up).
globebooleanfalseStart in globe (spherical Earth) projection. Users can also toggle this at runtime via the "Globe view" checkbox in the basemap panel. Globe view automatically transitions back to flat Mercator at zoom ~12, where the projections converge — this is handled by MapLibre internally.
json
"view": { "center": [-119.4, 36.8], "zoom": 6, "pitch": 0, "bearing": 0 }

For apps with 3D terrain, a modest pitch reveals elevation more effectively:

json
"view": { "center": [-110, 43], "zoom": 6, "pitch": 45, "bearing": -15 }

To start in globe projection:

json
"view": { "center": [0, 20], "zoom": 2, "globe": true }

Collections

Each entry in collections is either a bare string (loads all visual assets from that collection) or an object:

FieldTypeDescription
collection_idstringSTAC collection ID to load.
collection_urlstringDirect URL to the STAC collection JSON. Bypasses root catalog traversal — useful for private or external catalogs.
groupstring or objectGroup label shown in the layer toggle panel. Use an object { "name": "...", "collapsed": true } to start the group folded — see Collapsed groups.
assetsarrayAsset selector — see below. Omit to load all visual assets.
display_namestringOverride the collection title shown in the UI.
preloadbooleanInject the full column schema into the LLM system prompt — see Preloaded schemas. Default: false.

Asset config — vector (PMTiles)

Each entry in assets may be a bare string (the STAC asset key, loaded with defaults) or a config object:

FieldTypeDescription
idstringRequired. STAC asset key (e.g., "pmtiles").
aliasstringAlternative layer ID when you need two logical layers from one STAC asset (e.g., two default_filter views of the same file).
display_namestringLabel in the layer toggle UI. Falls back to the STAC asset title.
visiblebooleanDefault visibility on load. Default: false.
default_styleobjectMapLibre fill paint properties for polygon layers (e.g., fill-color, fill-opacity).
outline_styleobjectMapLibre line paint for an auto-added outline on top of the fill. Use this — not layer_type — to draw polygon borders.
layer_type"line" or "circle""line" for LineString/MultiLineString features; "circle" for Point/MultiPoint features.
default_filterarrayMapLibre filter expression applied at load time.
tooltip_fieldsarrayFeature property names shown in the hover tooltip.
groupstringOverrides the collection-level group for this specific layer.

Asset config — raster (COG)

FieldTypeDescription
idstringRequired. STAC asset key.
display_namestringLabel in the layer toggle UI.
visiblebooleanDefault visibility. Default: false.
colormapstringTiTiler colormap name (e.g., "reds", "blues", "viridis"). Default: "reds".
rescalestringTiTiler min,max range for color scaling (e.g., "0,150").
legend_labelstringLabel shown next to the color legend.
legend_typestring"categorical" to use STAC classification:classes color codes for a discrete legend.

Collapsed groups

By default, layer groups in the panel start expanded. To start a group folded (useful when a collection has many layers), use the object form for group:

json
{
  "collection_id": "fishing-effort",
  "group": { "name": "Fishing Effort", "collapsed": true },
  "assets": [
    { "id": "fishing-effort-cog-2012", "display_name": "2012" },
    { "id": "fishing-effort-cog-2024", "display_name": "2024", "visible": true }
  ]
}

The string form ("group": "Fishing Effort") still works and defaults to expanded. The per-asset group field (used to reassign a layer to a different group) is always a plain string.

Preloaded schemas

By default, the system prompt includes only a compact hint for each collection — enough for the LLM to know the dataset exists, but it must call get_dataset_details before writing SQL. This keeps token usage low when many collections are configured.

Set "preload": true on a collection to inject its full column schema (names, types, descriptions, and H3 index columns) directly into the system prompt. This lets the LLM write correct SQL on the first turn without an extra tool call, at the cost of more prompt tokens.

Use preload for the datasets users query most often:

json
{
  "collection_id": "cpad-2025b",
  "preload": true,
  "group": "Protected Areas",
  "assets": [{ "id": "cpad-holdings-pmtiles", "visible": true }]
}

Collections without preload (or with preload: false) show a compact summary with coded-value hints and a prompt to call get_dataset_details. The get_dataset_details tool always returns the full schema regardless of the preload setting.

Versioned assets

When a dataset has multiple related assets that differ along one axis (resolution level, year, scenario), declare them as versions of a single logical layer. The layer panel shows one checkbox plus a dropdown selector instead of separate entries for each asset.

json
{
  "id": "watersheds",
  "display_name": "Watersheds",
  "versions": [
    { "label": "L3 – Major Basins",   "asset_id": "hydrobasins_level_03" },
    { "label": "L4",                   "asset_id": "hydrobasins_level_04" },
    { "label": "L5",                   "asset_id": "hydrobasins_level_05" },
    { "label": "L6 – Sub-catchments",  "asset_id": "hydrobasins_level_06" }
  ],
  "default_version": "L6 – Sub-catchments"
}
FieldTypeDescription
versionsarrayList of { "label": "...", "asset_id": "..." } entries. Each asset_id must be a key in the STAC collection's assets.
default_versionstringLabel of the version to show by default. Falls back to the first entry if not found.

Switching versions swaps the visible map layer without adding or removing panel entries. All per-asset config options (default_style, default_filter, colormap, etc.) apply uniformly to every version. Works for both PMTiles (vector) and COG (raster) assets; all versions must share the same layer type.

Basemap configuration

Three basemap presets are always available via the toggle buttons: NatGeo (default), Satellite, and Plain.

default_basemap — controls which preset is active when the map loads:

json
{ "default_basemap": "plain" }

Valid values: "natgeo" (default), "satellite", "plain".

custom_basemap — replaces the NatGeo slot with a custom raster tile URL:

json
{
  "custom_basemap": {
    "url": "https://example.com/tiles/{z}/{x}/{y}.png",
    "label": "My Basemap"
  }
}
FieldDescription
urlXYZ raster tile URL with {z}/{x}/{y} placeholders.
labelButton label to show in the basemap toggle group (replaces "NatGeo").

Both fields are optional independently — you can swap the URL without changing the label, or vice versa. Terrain is disabled when a custom URL is set. The two options compose independently:

json
{
  "custom_basemap": { "url": "...", "label": "My Style" },
  "default_basemap": "plain"
}

Optional links surfaced in the chat UI. All fields are optional — omit any you don't need.

json
{
  "links": {
    "github": "https://github.com/org/my-app",
    "docs": "https://my-app-website.org",
    "carbon": true
  }
}
FieldDescription
githubURL to the app's source repository. Renders as a GitHub octocat icon in the chat header.
docsURL to a documentation or about page for the app. Renders as an "About" text link in the chat header.
carbonSet to true to show a carbon dashboard link (leaf icon) in the chat footer. Only meaningful for apps using NRP-hosted LLMs — links to the NRP carbon API dashboard.

LLM configuration

The llm section controls how the chat agent connects to a language model. Two modes:

Server-provided (default — omit llm): a config.json on the same server provides model endpoints and API keys (e.g., injected by Kubernetes at deploy time). See Deployment.

User-provided ("user_provided": true): no config.json needed. A ⚙ button appears in the chat footer; visitors enter their own API key, stored in localStorage (never sent to the server). Ideal for static-site deployments.

FieldDescription
user_providedtrue to enable browser-side API key entry.
default_endpointPre-filled endpoint URL shown in the settings panel. OpenRouter gives access to many models via one key.
modelsArray of { "value": "<model-id>", "label": "<display name>" } entries in the model selector.

Finding STAC asset IDs

Browse the catalog in STAC Browser:

https://radiantearth.github.io/stac-browser/#/external/s3-west.nrp-nautilus.io/public-data/stac/catalog.json

Open a collection → click the Assets tab. The keys listed there (e.g., "pmtiles", "v2-total-2024-cog") are the id values to use. For PMTiles vector layers, the asset's vector:layers field gives the internal layer name used by MapLibre (the app reads this automatically).

Worked examples

Point features as circles

json
{
  "id": "pmtiles",
  "display_name": "Observation Points",
  "visible": true,
  "layer_type": "circle",
  "default_style": {
    "circle-color": "#E53935",
    "circle-radius": 5,
    "circle-opacity": 0.7
  },
  "tooltip_fields": ["species", "date", "count"]
}

Polygon fill with categorical coloring

json
{
  "id": "pmtiles",
  "display_name": "Fee Lands",
  "visible": true,
  "default_style": {
    "fill-color": ["match", ["get", "GAP_Sts"],
      "1", "#26633A",
      "2", "#3E9C47",
      "3", "#7EB3D3",
      "4", "#BDBDBD",
      "#888888"
    ],
    "fill-opacity": 0.7
  },
  "default_filter": ["match", ["get", "GAP_Sts"], ["1", "2"], true, false],
  "tooltip_fields": ["Unit_Nm", "GAP_Sts", "Mang_Type"]
}

Boundary-only (outline) layer

To render polygon features as outlines only (census tracts, admin boundaries), keep the fill type but make the fill transparent and set outline_style:

json
{
  "id": "pmtiles",
  "display_name": "Congressional Districts",
  "visible": true,
  "default_style": {
    "fill-color": "#000000",
    "fill-opacity": 0
  },
  "outline_style": {
    "line-color": "#1565C0",
    "line-width": 1.5
  },
  "tooltip_fields": ["DISTRICTID", "STATE"]
}

Common mistake

layer_type is for the geometry type of the tile features, not a styling choice. Only set it when the features really are lines or points:

  • "line" — LineString/MultiLineString features (roads, rivers, transects)
  • "circle" — Point/MultiPoint features (observations, stations, events)

For polygon outline styling, use outline_style instead — see the example below.

Filter syntax

Use ["match", ["get", "col"], ["val1", "val2"], true, false] for list membership. Do not use the legacy ["in", "col", val1, val2] form — it is silently ignored in current MapLibre.

Full example

json
{
  "catalog": "https://s3-west.nrp-nautilus.io/public-data/stac/catalog.json",
  "titiler_url": "https://titiler.nrp-nautilus.io",
  "mcp_url": "https://duckdb-mcp.nrp-nautilus.io/mcp",
  "view": { "center": [-119.4, 36.8], "zoom": 6, "pitch": 0, "bearing": 0 },

  "llm": {
    "user_provided": true,
    "default_endpoint": "https://openrouter.ai/api/v1",
    "models": [
      { "value": "anthropic/claude-sonnet-4", "label": "Claude Sonnet" },
      { "value": "google/gemini-2.5-flash", "label": "Gemini Flash" }
    ]
  },

  "welcome": {
    "message": "Explore California's protected lands. Ask me about ownership, gap status, or acreage.",
    "examples": [
      "How much land is gap status 1 or 2?",
      "Show only federal lands",
      "Which agency manages the most acreage?"
    ]
  },

  "collections": [
    {
      "collection_id": "cpad-2025b",
      "group": "Protected Areas",
      "assets": [
        {
          "id": "cpad-holdings-pmtiles",
          "display_name": "Holdings",
          "visible": true,
          "default_style": { "fill-color": "#3E9C47", "fill-opacity": 0.5 },
          "tooltip_fields": ["UNIT_NAME", "AGNCY_NAME"]
        }
      ]
    },
    {
      "collection_id": "irrecoverable-carbon",
      "group": "Carbon",
      "assets": [
        { "id": "irrecoverable-total-2018-cog", "display_name": "Irrecoverable Carbon (2018)" }
      ]
    }
  ]
}

Released under the MIT License.