{
  "title": "Luma events - choose public calendars",
  "type": "object",
  "schemaVersion": 1,
  "properties": {
    "calendarUrls": {
      "title": "Public Luma calendars or cities",
      "type": "array",
      "editor": "stringList",
      "items": {
        "type": "string"
      },
      "description": "Up to 10 public Luma city/calendar page URLs, or their public calendar/discover iCal URLs. Empty/omitted uses San Francisco. Personal/user feeds, tokens, login-only calendars and event detail URLs are rejected. Exports are bounded; they do not promise every event.",
      "prefill": [
        "https://luma.com/sf"
      ],
      "sectionCaption": "1 · Public calendars",
      "sectionDescription": "Choose supported public calendar or city URLs."
    },
    "keywords": {
      "title": "Event words or phrases",
      "type": "array",
      "editor": "stringList",
      "items": {
        "type": "string"
      },
      "description": "Optional up to 20 literal case-insensitive phrases, each at most 100 characters. Match any phrase in title, location or the first 10,000 exported description characters. Matching excerpts are returned. This is not semantic intent inference.",
      "sectionCaption": "2 · Event filters",
      "sectionDescription": "Apply literal text and event-start date filters."
    },
    "startDate": {
      "title": "Starts on or after",
      "type": "string",
      "editor": "textfield",
      "description": "Optional real YYYY-MM-DD date, inclusive. Compared with the DTSTART date as written in the feed; UTC exports use the UTC date. Calendar timezone metadata is separate."
    },
    "endDate": {
      "title": "Starts on or before",
      "type": "string",
      "editor": "textfield",
      "description": "Optional real YYYY-MM-DD date, inclusive, in the same feed date convention as startDate."
    },
    "maxEventsPerCalendar": {
      "title": "Maximum visible events per calendar",
      "type": "integer",
      "editor": "number",
      "description": "Inspect this many usable events per current export, sorted by exported start date ascending, then stable ID. This may include historical events in organizer calendars. Filter afterward. No full-history or disappearance claims.",
      "default": 100,
      "minimum": 1,
      "maximum": 500,
      "sectionCaption": "3 · Feed and result limits",
      "sectionDescription": "A larger cap cannot expose events omitted by the publisher’s feed."
    },
    "maxResults": {
      "title": "Maximum saved results",
      "type": "integer",
      "editor": "number",
      "description": "Maximum unique matching rows saved across the whole run. Normal requested caps are bounded coverage, not source failures.",
      "default": 20,
      "minimum": 1,
      "maximum": 1000
    },
    "comparePrevious": {
      "title": "Compare with prior saved observations",
      "type": "boolean",
      "editor": "checkbox",
      "default": false,
      "description": "Return matching rows with new, changed or unchanged comparison status. Uses a named persistent store. Only confirmed saved rows advance history. The first run establishes observations, and SUMMARY confirms whether history was committed.",
      "sectionCaption": "4 · Saved comparisons",
      "sectionDescription": "The first comparison establishes history. Reuse the same scope for later observations and avoid concurrent writers."
    },
    "onlyChanges": {
      "title": "Save only new or changed observations",
      "type": "boolean",
      "editor": "checkbox",
      "default": false,
      "description": "Implies comparison. Unchanged matching observations are skipped without a dataset charge. A first run saves matching observations; subsequent unchanged runs can correctly save zero. No disappearance/deletion inference."
    },
    "snapshotName": {
      "title": "History name",
      "type": "string",
      "editor": "textfield",
      "description": "Use 1-80 letters, digits, underscores or hyphens. History also includes the sorted sources/queries and content filters. Run only one writer at a time for each scope. Start a new name for an incompatible saved baseline.",
      "default": "default"
    },
    "maxRunSeconds": {
      "title": "Run time budget (seconds)",
      "type": "integer",
      "editor": "number",
      "description": "Requests use this budget and the platform deadline minus 25 seconds. Each request is capped at 25 seconds. Partial coverage and spending stops are explicit in SUMMARY.",
      "default": 240,
      "minimum": 30,
      "maximum": 3600,
      "sectionCaption": "5 · Advanced run settings",
      "sectionDescription": "Adjust the time budget only when a larger collection needs it."
    }
  },
  "description": "Choose supported public Luma calendars or cities, filter the visible feed window and optionally compare saved events. Source feed coverage and refresh timing limit what can be observed."
}
