Build with LayrQ
From an AI-generated layer specification to a production viewport query.
Agent contract
Copy the reference or the ready-made prompt into ChatGPT, Claude, Gemini, or another LLM. The model can then produce a valid LayrQ layer definition without needing GIS-specific knowledge.
Mention what each feature represents, its geometry, the properties to keep, and who should be able to read it.
Replace the bracketed application description. The full contract is already included below it.
You are designing a LayrQ spatial layer. Read the LayrQ agent reference below, then return exactly one valid layer specification JSON object. Do not return Markdown or commentary. Use one geometry family, lowercase snake_case names, and only supported field types. My application needs: [DESCRIBE THE DATA, GEOMETRY, FIELDS, AND VISIBILITY HERE] LAYRQ AGENT REFERENCE: [the complete reference shown in section 4]
Paste the generated object into New layer → JSON specification.
{
"name": "inspection_assets",
"title": "Inspection Assets",
"geometry": "line",
"visibility": "private",
"fields": {
"asset_id": {
"type": "string",
"required": true
},
"condition": {
"type": "enum",
"values": [
"Good",
"Fair",
"Poor"
]
},
"inspection_date": {
"type": "date"
},
"needs_repair": {
"type": "boolean"
},
"length_m": {
"type": "number"
}
}
}This machine-readable contract includes the schema, geometry compatibility, field rules, feature format, query contract, limits, and AI instructions.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://www.layrq.com/layrq-agent-spec.json",
"title": "LayrQ agent reference",
"version": "1.0.0",
"purpose": "Create one schema-constrained spatial layer and its live API from one JSON object.",
"canonicalBaseUrl": "https://www.layrq.com",
"rules": {
"oneGeometryFamilyPerLayer": true,
"mixedGeometry": false,
"geometryCollection": false,
"coordinateReferenceSystem": "EPSG:4326",
"coordinateOrder": [
"longitude",
"latitude"
],
"maximumFields": 100,
"maximumVerticesPerGeometry": 10000,
"maximumGeometryBytes": 5242880,
"fieldNames": "lowercase snake_case; start with a letter; contain only letters, numbers, and underscores",
"featureProperties": "Every property must be declared in fields. Required fields must be present and non-null.",
"polygonValidity": "Polygons must pass PostGIS ST_IsValid. LayrQ returns the validation reason and never silently repairs geometry."
},
"layerSpecificationSchema": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"title",
"geometry",
"visibility",
"fields"
],
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z][a-z0-9_]{0,62}$",
"description": "Stable machine name. Use lowercase snake_case."
},
"title": {
"type": "string",
"minLength": 1,
"maxLength": 120,
"description": "Human-readable layer title."
},
"geometry": {
"type": "string",
"enum": [
"point",
"line",
"polygon"
],
"description": "Geometry family. Singular and matching multipart GeoJSON variants are accepted."
},
"visibility": {
"type": "string",
"enum": [
"public",
"private",
"unlisted"
],
"description": "Public is internet-readable. Private and unlisted layers require an owner session or API key; unlisted layers are also omitted from public listings."
},
"fields": {
"type": "object",
"maxProperties": 100,
"propertyNames": {
"pattern": "^[a-z][a-z0-9_]{0,62}$"
},
"additionalProperties": {
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"string",
"number",
"boolean",
"date"
]
},
"required": {
"type": "boolean",
"default": false
}
}
},
{
"type": "object",
"additionalProperties": false,
"required": [
"type",
"values"
],
"properties": {
"type": {
"const": "enum"
},
"required": {
"type": "boolean",
"default": false
},
"values": {
"type": "array",
"minItems": 1,
"maxItems": 100,
"uniqueItems": true,
"items": {
"type": "string",
"minLength": 1,
"maxLength": 120
}
}
}
}
]
}
}
}
},
"geometryCompatibility": {
"point": [
"Point",
"MultiPoint"
],
"line": [
"LineString",
"MultiLineString"
],
"polygon": [
"Polygon",
"MultiPolygon"
]
},
"fieldTypes": {
"string": {
"jsonType": "string",
"example": "Bridge 12"
},
"number": {
"jsonType": "number",
"example": 98.5
},
"boolean": {
"jsonType": "boolean",
"example": true
},
"date": {
"jsonType": "string",
"format": "YYYY-MM-DD",
"example": "2026-07-29"
},
"enum": {
"jsonType": "string",
"rule": "Value must exactly match one entry in values.",
"example": "Good"
}
},
"layerSpecificationExample": {
"name": "inspection_assets",
"title": "Inspection Assets",
"geometry": "line",
"visibility": "private",
"fields": {
"asset_id": {
"type": "string",
"required": true
},
"condition": {
"type": "enum",
"values": [
"Good",
"Fair",
"Poor"
]
},
"inspection_date": {
"type": "date"
},
"needs_repair": {
"type": "boolean"
},
"length_m": {
"type": "number"
}
}
},
"featureInput": {
"format": "GeoJSON Feature",
"schema": {
"type": "object",
"additionalProperties": false,
"required": [
"type",
"geometry",
"properties"
],
"properties": {
"type": {
"const": "Feature"
},
"geometry": {
"type": "object",
"required": [
"type",
"coordinates"
],
"properties": {
"type": {
"enum": [
"Point",
"MultiPoint",
"LineString",
"MultiLineString",
"Polygon",
"MultiPolygon"
]
},
"coordinates": {
"description": "Valid GeoJSON coordinates in EPSG:4326 longitude-latitude order."
}
}
},
"properties": {
"type": "object",
"description": "Keys and value types must match the layer fields schema."
}
}
},
"example": {
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": [
[
-97.7431,
30.2672
],
[
-97.741,
30.269
]
]
},
"properties": {
"asset_id": "A-1001",
"condition": "Good",
"inspection_date": "2026-07-29",
"needs_repair": false,
"length_m": 284.6
}
}
},
"createLayerRequest": {
"method": "POST",
"path": "/api/v1/layers",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_LAYRQ_API_KEY_OR_SUPABASE_ACCESS_TOKEN"
},
"body": "One object that validates against layerSpecificationSchema."
},
"successfulLayerResponse": {
"layerId": "lyr_123",
"featuresUrl": "https://www.layrq.com/api/v1/layers/lyr_123/features",
"geojsonUrl": "https://www.layrq.com/api/v1/layers/lyr_123.geojson",
"csvUrl": "https://www.layrq.com/api/v1/layers/lyr_123.csv",
"tileUrl": "https://www.layrq.com/api/v1/layers/lyr_123/tiles/{z}/{x}/{y}.pbf",
"tileJsonUrl": "https://www.layrq.com/api/v1/layers/lyr_123/tiles.json",
"styleUrl": "https://www.layrq.com/api/v1/layers/lyr_123/style.json",
"schemaUrl": "https://www.layrq.com/api/v1/layers/lyr_123",
"ogcUrl": "https://www.layrq.com/ogc",
"ogcCollectionUrl": "https://www.layrq.com/ogc/collections/lyr_123",
"ogcItemsUrl": "https://www.layrq.com/ogc/collections/lyr_123/items",
"wfsUrl": "https://www.layrq.com/wfs",
"arcgisServiceUrl": "https://www.layrq.com/arcgis/rest/services/lyr_123/FeatureServer",
"arcgisLayerUrl": "https://www.layrq.com/arcgis/rest/services/lyr_123/FeatureServer/0"
},
"queryContract": {
"path": "/api/v1/layers/{layerId}/features",
"parameters": {
"bbox": "minLongitude,minLatitude,maxLongitude,maxLatitude",
"limit": "Default 100; maximum 1000.",
"cursor": "Opaque nextCursor from the previous response.",
"fields": "Comma-separated property names.",
"sort": "A layer field, id, created_at, or updated_at.",
"direction": "asc or desc. Requires sort and remains bound to the returned cursor.",
"filter.FIELD": "Equality filter.",
"filter.FIELD__OPERATOR": "OPERATOR is neq, gt, gte, lt, or lte."
},
"paginationRule": "Continue until pagination.hasMore is false. Never invent, decode, or modify the cursor.",
"example": "/api/v1/layers/lyr_123/features?bbox=-98,29,-96,31&limit=100&fields=asset_id,condition&sort=inspection_date&direction=desc&filter.condition=Good"
},
"importContract": {
"method": "POST",
"path": "/api/v1/layers/{layerId}/import",
"contentType": "multipart/form-data",
"formats": [
"CSV",
"GeoJSON",
"NDJSON",
"ZIP shapefile"
],
"fileField": "file",
"shapefileRule": "Upload a ZIP containing matching .shp, .dbf, and .shx files. Include .prj when coordinates require conversion to EPSG:4326.",
"fieldMap": {
"encoding": "JSON object in the multipart fieldMap form field",
"rule": "Keys are target layer fields. Values are source field names; null skips the target field.",
"example": {
"asset_id": "ASSETID",
"condition": "STATUS",
"inspection_date": "INSPECT_DT"
}
},
"csvCoordinates": {
"longitudeField": "Optional custom source longitude column.",
"latitudeField": "Optional custom source latitude column."
},
"batchSize": 500
},
"externalArcGisContract": {
"purpose": "Connect one existing ArcGIS FeatureServer layer as read-only data without importing the complete dataset.",
"inspect": {
"method": "POST",
"path": "/api/v1/external-sources/inspect"
},
"connect": {
"method": "POST",
"path": "/api/v1/external-sources"
},
"requiredUrlShape": "A concrete HTTPS URL ending in /FeatureServer/{layerId}.",
"access": [
"public",
"token"
],
"defaultMonitoring": "Adaptive. Monitoring remains idle until an active automation requires the source.",
"monitoringManagement": "Change source-level monitoring while activating an automation or later from the Source panel. Free fixed minimum is 5 minutes; Flex fixed minimum is 1 minute.",
"rules": [
"Never send an ArcGIS token directly from a browser to ArcGIS.",
"Never expect the token in a response after inspection or connection.",
"External features are read-only and are queried in bounded pages or viewports.",
"Identical public canonical URLs share one physical monitor while logical account layers remain isolated.",
"Monitoring remains idle until an active automation exists."
]
},
"limits": {
"normalApiResponseFeatures": 1000,
"defaultGeoJsonFeatures": 1000,
"maximumSynchronousGeoJsonFeatures": 10000,
"maximumImportBytes": 10485760,
"maximumVerticesPerGeometry": 10000,
"maximumGeometryBytes": 5242880,
"note": "A response that has more data exposes hasMore or truncated metadata and a next cursor. LayrQ never silently truncates."
},
"structuredError": {
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable explanation",
"details": {},
"requestId": "request UUID for support"
}
},
"instructionsForAnAiModel": [
"Return JSON only unless the user asks for an explanation.",
"Ask which geometry family to use if it cannot be inferred safely.",
"Use exactly one of point, line, or polygon for geometry.",
"Use lowercase snake_case for the layer name and every field name.",
"Declare every property the user wants to store.",
"Use enum only when the allowed values are known and finite.",
"Mark only truly mandatory fields as required.",
"Choose public, private, or unlisted deliberately; prefer private for sensitive data.",
"Do not include features, API keys, prose, Markdown, GeometryCollection, or mixed geometry in a layer specification.",
"Validate the final object against layerSpecificationSchema before returning it."
]
}