Skip to content

Using AI agents

A map document is plain YAML checked against a published schema, so an LLM agent can write one reliably: generate a document, run the validator, and repair what it reports until the file is valid. This page gives the agent (or the developer wiring one up) the loop, the validator’s JSON output, and the resources to load.

generate → validate -f json → repair → repeat until valid
  1. Generate a map document in format v1, the default: the schemas, the examples and every guide use it. An agent that writes JSON more reliably can save the same document as map.json, with a $schema key (JSON & TOML documents).

  2. Validate it with the CLI’s JSON output:

    Terminal window
    npx maplibre-yaml@latest validate map.yaml -f json
  3. Repair each entry in errors, using its path, message, line and column.

  4. Repeat until the command exits with 0 and prints "valid": true.

The exit code tells the loop where it stands:

CodeMeaning
0Every file is valid
1At least one file has errors, or warnings in strict mode
2The file wasn’t found or the pattern matched nothing: check the path, not the YAML

Strict mode is on when the CI environment variable is set, so an agent running in CI must fix warnings as well as errors. --no-strict turns it off; --strict turns it on anywhere.

An agent may write the document as JSON or TOML instead of YAML — whichever its tooling emits more reliably — and run the same loop on it: validate reads all three, reports at the same line and column, and -f json works on a .json or .toml file exactly as on a .yaml one. These docs stay YAML; see JSON & TOML documents for the schema line in each format and what else changes.

To move a document between formats, use mlym convert <file> --to yaml|json|toml:

Terminal window
npx maplibre-yaml@latest convert map.toml --to yaml
npx maplibre-yaml@latest convert map.json --to toml --out map.toml --strict

--strict exits 1 and writes nothing if the target can’t keep everything (comments, anchors, a null); without it, what’s lost is listed on stderr and the command still exits 0. Add -f json to read the result instead of prose: one object on stdout, { success, from, to, text, losses, errors } (out in place of text with --out), each loss and error with its path, line and column as validate -f json gives them (the convert JSON output):

Terminal window
npx maplibre-yaml@latest convert map.json --to toml --strict -f json

TOML has traps a generated document can hit:

  • filter = null, or any null: TOML has no null. Leave the key out.
  • An unquoted dotted key outside locale: a.b = 1 nests as a = { b = 1 }.
  • A bare # colour: circle-color = #e74c3c starts a comment. Quote it.
  • A layer’s own key written after a [layers.paint] header: it lands in paint, not the layer.
  • !html: write { "$html" = "…" } (JSON: { "$html": "…" }).

On success:

{
"valid": true,
"files": [
{
"file": "/home/you/maps/map.yaml",
"valid": true,
"errors": [],
"warnings": []
}
],
"summary": {
"total": 1,
"valid": 1,
"invalid": 0,
"errorCount": 0,
"warningCount": 0,
"noteCount": 0
}
}

On failure, here for center: -74.006, 40.7128 written without brackets:

{
"valid": false,
"files": [
{
"file": "/home/you/maps/map.yaml",
"valid": false,
"errors": [
{
"path": "config.center",
"message": "center needs square brackets: center: [-74.006, 40.7128]",
"line": 4,
"column": 11,
"severity": "error"
}
],
"warnings": []
}
],
"summary": {
"total": 1,
"valid": 0,
"invalid": 1,
"errorCount": 1,
"warningCount": 0,
"noteCount": 0
}
}
  • file is an absolute path.
  • path points into the document with dots: config.center, layers.0.paint.circle-radius. line and column locate it in the source where the YAML allows.
  • message says what is wrong and usually how to write it instead.
  • warnings entries have the same fields. Their severity is "warning" for something valid that probably isn’t what the author meant (a layer naming an undeclared source, a map with no basemap), or "note" for how a valid value is read. Notes never make a file invalid and aren’t counted in warningCount.

Other formats for the same findings (sarif, vscode) are in CLI commands › Output formats.

ResourceURL
Agent index (llms.txt)https://docs.maplibre-yaml.org/llms.txt
Full reference (llms-full.txt)https://docs.maplibre-yaml.org/llms-full.txt
JSON Schema for a map documenthttps://docs.maplibre-yaml.org/schema/latest/map.schema.json

llms.txt is a short index. llms-full.txt holds the complete JSON Schemas and example documents in one file. Both are built from the same sources as these docs. The schema for story files, and how to pin a version, are in Editor setup › Schema URLs.

To use exactly the schema of the core version a project has installed, print it with the CLI:

Terminal window
npx maplibre-yaml@latest schema map

A page that already shows a <ml-map> doesn’t need to replace the element for a new document: call el.update(doc), or assign the document to el.config, and the running map changes in place by id, moving the camera only if the document’s camera changed. The outcome arrives as ml-map:update-applied ({ summary }) or ml-map:update-rejected ({ kind, errors }); el.setState(values) / el.getState() read and write the document’s state: values at runtime, and camera="host" on the element keeps an update from moving a reader’s own view. Full rules: <ml-map> reference.

1. A map document is type: map with a config: block

Section titled “1. A map document is type: map with a config: block”

The file <ml-map src> loads starts with type: map. The camera and the basemap go under config:, not at the top level, and center is [longitude, latitude]. Don’t mix in format v2’s style: and runtime: sections.

# yaml-language-server: $schema=https://docs.maplibre-yaml.org/schema/latest/map.schema.json
type: map
id: my-map
config:
center: [-74.006, 40.7128]
zoom: 12
mapStyle: "https://tiles.openfreemap.org/styles/liberty"

popup: is a list of single-key { tag: [items] } objects, not an HTML string and not a { title, description } object. Each item is str: (fixed text) or property: (a feature’s value), optionally with else: (a fallback) and format: (a number format).

interactive:
click:
popup:
- h3:
- property: title
- p:
- str: "Magnitude "
- property: mag
format: { max-fraction-digits: 1 }

3. A named source is referenced by its name

Section titled “3. A named source is referenced by its name”

Declare a source once under sources:, then set each layer’s source: to that name as a plain string.

type: map
id: quakes
config:
center: [-120, 37]
zoom: 4
mapStyle: "https://tiles.openfreemap.org/styles/liberty"
sources:
quakes:
type: geojson
url: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson"
layers:
- id: quake-points
type: circle
source: quakes # the name, not an inline object
paint:
circle-radius: 6
circle-color: "#e55e5e"

The same command fails a CI job on an invalid document, and its SARIF output shows findings as annotations on a pull request: CLI commands › Integration examples.