Skip to main content
Glama

Ticker: Live Event Ticket Market

Create Saved View

create_view

Creates a View: a saved predicate that records a Match when an event enters it and sends it by email or to a destination, with an optional Digest. Try the predicate with screen_events first; use update_view to change a View that exists.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYes
tagsNoFree-text organization labels for this View (max 5, deduplicated). Purely for grouping/filtering in the app; tags never change what the View matches or where alerts deliver.
colorNoAccent color the app shows on this View's pill/dot. One of: red, orange, amber, green, teal, blue, violet, pink. Cosmetic only.
digestNoThe View's Digest: each Issue is the View's events with Movers, New and Gone against the previous Issue. Only the fields you pass change. Turning it on past the plan's Digest count is refused with the plan that carries more.
enabledNo
channelsYesDelivery channels, at least one. "email" mails the Matches to the account's address. The other value routes them to the destinations attached to this View instead, which is how a Slack or Discord channel receives them: add one in the Ticker web app under Settings, then attach it with set_view_target. A View may carry both.
predicateNo{} = always-true, combined with max_firings_per_eval to get a "top-N of the universe" alert. Predicate DSL (recursive JSON): a leaf is {col, op, val}; composites are {all:[...]} (AND) or {any:[...]} (OR). Columns are prefixed: "ea." = event_analytics, "e." = events, "pa." = performer_analytics, "p." = performers (p.name, the act the row is about), "v." = venues (v.venue_name, the venue's name; v.city, v.state, v.country_code, v.capacity). Ops: =, !=, >, >=, <, <=, between (val=[lo,hi]), in (val=[...]), contains (case-insensitive substring on a TEXT column; val is a plain string), not_contains (removes the rows whose TEXT column holds val as a case-insensitive substring; a row with no value stays; % and _ in val match themselves, while contains reads them as wildcards). Example: {"all":[{"col":"ea.price_self_z_7d_xs_z_subcat_tte","op":">=","val":2},{"col":"ea.days_to_event","op":"between","val":[7,60]}]}. NAMED ACTS / TEAMS / PERFORMERS, use p.name. When the user names the act the events are BY (a musician like 'Taylor Swift', a team like 'Lakers', a comedian, a touring show), filter the performer column: {col:'p.name', op:'contains', val:'Taylor Swift'}. p.name is the act the row is KEYED on. e.event_name is the TITLE, which reads 'A at B' for a sports event and so also returns the opponent's home games, and for a concert also returns parking and support billings. A performer or team ask NEVER goes to e.event_name. Keep writing 'contains' for an act name. When what was typed IS a whole act name in the catalog, the server rewrites that leaf to op '=' and says so; anything else stays a substring. REMOVING ROWS BY A WORD. 'NOT Little', 'not the Lakers', 'without Taylor', 'excluding Hamilton' remove every row whose title contains the word: {col:'e.event_name', op:'not_contains', val:'Little'}. Never write '!=' for a word: '!=' compares the WHOLE value, so e.event_name != 'Manilow' removes nothing. A MISSPELLED superlative is still a superlative. 'htotest', 'hotest', 'bigest movers', 'chepest', 'lowset price' read as the word they intend and take the ordering that word takes. A ranking word is NEVER a name: never put it in a 'contains' leaf on e.event_name or p.name, and never answer with sort null because the spelling was odd. ECONOMIC FLOOR. The server already ANDs ea.listings_current >= 25 AND ea.median_price_current >= 40 into every screen. Do NOT add a listings-depth floor of your own. A column whose name ends in d1 or 1d is a ONE-DAY CHANGE, not yesterday's value. 'Inventory dropping' or 'listings falling' is a SEVEN-DAY change or an absorption column, never a one-day ratio. A stale row, or an event that is not active, is NEVER a move: its numbers describe the last day it was priced. Gate a movement ask on ea.last_price_snapshot_date with a relative date. The economic floor CAN be turned off at the call site (apply_floor=false, or apply_economic_floor=false on a rule), only when you explicitly want the raw universe. A freshness gate is NOT applied by default, so supply it yourself: {"col":"ea.last_price_snapshot_date","op":">=","val":{"days_ago":1}} means "priced within the last day" and compiles to CURRENT_DATE - 1, re-evaluated every tick, where a literal date string silently rots. The {"days_ago": N} value form is valid on any date/timestamp column. A weekend is {"col":"e.local_date","op":"between","val":{"weekend":"this","tz":"America/New_York"}} ("next" for the one after): the coming Friday to Sunday in tz, from today on a Friday to Sunday, resolved on every run. e.event_id, e.venue_id and e.performer_id take the ids rows carry (ev..., vn..., pf...). Authoritative validation runs in SQL; an invalid predicate returns a clear error.
notification_modeNoPer-alert EMAIL delivery mode: 'instant' (email each match), 'batched' (the Matches wait and go out together in one email, at the pace notification_cadence sets: `hourly` or `daily`), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. 'digest' is the old name of 'batched', accepted until 2026-11-30 and stored as 'batched'. Alert destinations are unaffected: they always deliver instantly.
delivery_target_idNoOptionally attach an alert destination (an id from list_destinations; new destinations are added in the Ticker web app under Settings) so this alert's Matches are delivered there the instant they fire, in addition to email. Omit for email-only.
apply_economic_floorNoWhether the rule's predicate is AND-ed with the economic floor (listings_current >= 25 AND median_price_current >= 40). Default true.
max_firings_per_evalNoCap on events this rule can match per evaluation tick (top-N by event_id (deterministic cap, not magnitude-prioritized)). Bounds alert volume since percentile predicates can't self-limit. Default 25.
notification_cadenceNoHow often this alert's Matches may leave as EMAIL: `immediate` (each match), `hourly`, `daily` (batched), or `off` (Matches recorded but never emailed). Only paces EMAIL; an attached alert destination always delivers the instant a Match fires, regardless of this.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • changedInput schema / properties / digest / properties / sections / description
      Previous value: -"Sections each Issue shows: movers, new, gone (default all three). The rest of the table always shows."New value: +"Sections each Issue shows: movers, new, gone (default all three). The rest of the table always shows. When the Digest reads triggers (its triggers are not null), only new and gone are kept here and movers turns the pct_move trigger on."
    • removedInput schema / properties / digest / properties / sections / minItems
      Removed value: -1
    • addedInput schema / properties / digest / properties / triggers
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The Digest's trigger sections: each trigger on is a section of the events where it fired since the previous Issue, the same conditions a starred event alerts on, e.g. {\"weather\":{\"enabled\":true},\"pct_move\":{\"enabled\":true,\"params\":{\"threshold\":20}}}. Only the triggers you pass change. Refused while the Digest's triggers read null (trigger sections not available).",
      +  "properties": {
      +    "absorption": {
      +      "additionalProperties": false,
      +      "description": "Tickets leaving fast: A large share of the listed tickets leaves the marketplace. Off by default. Measures listings that disappear, which is not the same as confirmed sales. params: threshold 0.3 to 0.9 (default 0.5).",
      +      "properties": {
      +        "enabled": {
      +          "type": "boolean"
      +        },
      +        "params": {
      +          "additionalProperties": {
      +            "type": [
      +              "number",
      +              "string"
      +            ]
      +          },
      +          "type": "object"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "demand": {
      +      "additionalProperties": false,
      +      "description": "Demand spike: Interest in this event's listings rises versus the day before. Off by default. A change in Interest from one date to the next, not a z-score. Coverage is still filling in, so quiet events may never trigger it. params: threshold 1 to 50 (default 5).",
      +      "properties": {
      +        "enabled": {
      +          "type": "boolean"
      +        },
      +        "params": {
      +          "additionalProperties": {
      +            "type": [
      +              "number",
      +              "string"
      +            ]
      +          },
      +          "type": "object"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "lifecycle": {
      +      "additionalProperties": false,
      +      "description": "On-sale, presale, event week, low inventory: Fires when an on-sale or presale is announced, event week begins, or listed inventory runs low. On by default. params: event_week_days 1 to 30  days out (default 7); low_inventory_percent 1 to 50 % (default 10).",
      +      "properties": {
      +        "enabled": {
      +          "type": "boolean"
      +        },
      +        "params": {
      +          "additionalProperties": {
      +            "type": [
      +              "number",
      +              "string"
      +            ]
      +          },
      +          "type": "object"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "pct_move": {
      +      "additionalProperties": false,
      +      "description": "Price % move: The price changes by more than this percentage. Off by default. params: metric lowest | median (default lowest); window 1d | 7d (default 1d); threshold 5 to 100 % (default 15).",
      +      "properties": {
      +        "enabled": {
      +          "type": "boolean"
      +        },
      +        "params": {
      +          "additionalProperties": {
      +            "type": [
      +              "number",
      +              "string"
      +            ]
      +          },
      +          "type": "object"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "price_z": {
      +      "additionalProperties": false,
      +      "description": "Unusual price move: Fires when the 7-day price move is at least 2× this event's own normal swing, in either direction. On by default. params: threshold 1 to 5 (default 2).",
      +      "properties": {
      +        "enabled": {
      +          "type": "boolean"
      +        },
      +        "params": {
      +          "additionalProperties": {
      +            "type": [
      +              "number",
      +              "string"
      +            ]
      +          },
      +          "type": "object"
      +        }
      +      },
      +      "type": "object"
      +    },
      +    "weather": {
      +      "additionalProperties": false,
      +      "description": "Weather: Fires when the forecast for the event turns bad, and again when it clears. On by default.",
      +      "properties": {
      +        "enabled": {
      +          "type": "boolean"
      +        },
      +        "params": {
      +          "additionalProperties": {
      +            "type": [
      +              "number",
      +              "string"
      +            ]
      +          },
      +          "type": "object"
      +        }
      +      },
      +      "type": "object"
      +    }
      +  },
      +  "type": "object"
      +}
  2. Changed1 schema field changed
    • changedInput schema / properties / predicate / description
      Previous value: -"{} = always-true, combined with max_firings_per_eval to get a \"top-N of the universe\" alert. Predicate DSL (recursive JSON): a leaf is {col, op, val}; composites are {all:[...]} (AND) or {any:[...]} (OR). Columns are prefixed: \"ea.\" = event_analytics, \"e.\" = events, \"pa.\" = performer_analytics, \"p.\" = performers (p.name, the act the row is about), \"v.\" = venues (v.venue_name, the venue's name; v.city, v.state, v.country_code, v.capacity). Ops: =, !=, >, >=, <, <=, between (val=[lo,hi]), in (val=[...]), contains (case-insensitive substring on a TEXT column; val is a plain string), not_contains (removes the rows whose TEXT column holds val as a case-insensitive substring; a row with no value stays; % and _ in val match themselves, while contains reads them as wildcards). Example: {\"all\":[{\"col\":\"ea.price_self_z_7d_xs_z_subcat_tte\",\"op\":\">=\",\"val\":2},{\"col\":\"ea.days_to_event\",\"op\":\"between\",\"val\":[7,60]}]}. NAMED ACTS / TEAMS / PERFORMERS, use p.name. When the user names the act the events are BY (a musician like 'Taylor Swift', a team like 'Lakers', a comedian, a touring show), filter the performer column: {col:'p.name', op:'contains', val:'Taylor Swift'}. p.name is the act the row is KEYED on. e.event_name is the TITLE, which reads 'A at B' for a sports event and so also returns the opponent's home games, and for a concert also returns parking and support billings. A performer or team ask NEVER goes to e.event_name. Keep writing 'contains' for an act name. When what was typed IS a whole act name in the catalog, the server rewrites that leaf to op '=' and says so; anything else stays a substring. REMOVING ROWS BY A WORD. 'NOT Little', 'not the Lakers', 'without Taylor', 'excluding Hamilton' remove every row whose title contains the word: {col:'e.event_name', op:'not_contains', val:'Little'}. Never write '!=' for a word: '!=' compares the WHOLE value, so e.event_name != 'Manilow' removes nothing. A MISSPELLED superlative is still a superlative. 'htotest', 'hotest', 'bigest movers', 'chepest', 'lowset price' read as the word they intend and take the ordering that word takes. A ranking word is NEVER a name: never put it in a 'contains' leaf on e.event_name or p.name, and never answer with sort null because the spelling was odd. ECONOMIC FLOOR. The server already ANDs ea.listings_current >= 25 AND ea.median_price_current >= 40 into every screen. Do NOT add a listings-depth floor of your own. A column whose name ends in d1 or 1d is a ONE-DAY CHANGE, not yesterday's value. 'Inventory dropping' or 'listings falling' is a SEVEN-DAY change or an absorption column, never a one-day ratio. A stale row, or an event that is not active, is NEVER a move: its numbers describe the last day it was priced. Gate a movement ask on ea.last_price_snapshot_date with a relative date. The economic floor CAN be turned off at the call site (apply_floor=false, or apply_economic_floor=false on a rule), only when you explicitly want the raw universe. A freshness gate is NOT applied by default, so supply it yourself: {\"col\":\"ea.last_price_snapshot_date\",\"op\":\">=\",\"val\":{\"days_ago\":1}} means \"priced within the last day\" and compiles to CURRENT_DATE - 1, re-evaluated every tick, where a literal date string silently rots. The {\"days_ago\": N} value form is valid on any date/timestamp column. e.event_id, e.venue_id and e.performer_id take the ids rows carry (ev..., vn..., pf...). Authoritative validation runs in SQL; an invalid predicate returns a clear error."New value: +"{} = always-true, combined with max_firings_per_eval to get a \"top-N of the universe\" alert. Predicate DSL (recursive JSON): a leaf is {col, op, val}; composites are {all:[...]} (AND) or {any:[...]} (OR). Columns are prefixed: \"ea.\" = event_analytics, \"e.\" = events, \"pa.\" = performer_analytics, \"p.\" = performers (p.name, the act the row is about), \"v.\" = venues (v.venue_name, the venue's name; v.city, v.state, v.country_code, v.capacity). Ops: =, !=, >, >=, <, <=, between (val=[lo,hi]), in (val=[...]), contains (case-insensitive substring on a TEXT column; val is a plain string), not_contains (removes the rows whose TEXT column holds val as a case-insensitive substring; a row with no value stays; % and _ in val match themselves, while contains reads them as wildcards). Example: {\"all\":[{\"col\":\"ea.price_self_z_7d_xs_z_subcat_tte\",\"op\":\">=\",\"val\":2},{\"col\":\"ea.days_to_event\",\"op\":\"between\",\"val\":[7,60]}]}. NAMED ACTS / TEAMS / PERFORMERS, use p.name. When the user names the act the events are BY (a musician like 'Taylor Swift', a team like 'Lakers', a comedian, a touring show), filter the performer column: {col:'p.name', op:'contains', val:'Taylor Swift'}. p.name is the act the row is KEYED on. e.event_name is the TITLE, which reads 'A at B' for a sports event and so also returns the opponent's home games, and for a concert also returns parking and support billings. A performer or team ask NEVER goes to e.event_name. Keep writing 'contains' for an act name. When what was typed IS a whole act name in the catalog, the server rewrites that leaf to op '=' and says so; anything else stays a substring. REMOVING ROWS BY A WORD. 'NOT Little', 'not the Lakers', 'without Taylor', 'excluding Hamilton' remove every row whose title contains the word: {col:'e.event_name', op:'not_contains', val:'Little'}. Never write '!=' for a word: '!=' compares the WHOLE value, so e.event_name != 'Manilow' removes nothing. A MISSPELLED superlative is still a superlative. 'htotest', 'hotest', 'bigest movers', 'chepest', 'lowset price' read as the word they intend and take the ordering that word takes. A ranking word is NEVER a name: never put it in a 'contains' leaf on e.event_name or p.name, and never answer with sort null because the spelling was odd. ECONOMIC FLOOR. The server already ANDs ea.listings_current >= 25 AND ea.median_price_current >= 40 into every screen. Do NOT add a listings-depth floor of your own. A column whose name ends in d1 or 1d is a ONE-DAY CHANGE, not yesterday's value. 'Inventory dropping' or 'listings falling' is a SEVEN-DAY change or an absorption column, never a one-day ratio. A stale row, or an event that is not active, is NEVER a move: its numbers describe the last day it was priced. Gate a movement ask on ea.last_price_snapshot_date with a relative date. The economic floor CAN be turned off at the call site (apply_floor=false, or apply_economic_floor=false on a rule), only when you explicitly want the raw universe. A freshness gate is NOT applied by default, so supply it yourself: {\"col\":\"ea.last_price_snapshot_date\",\"op\":\">=\",\"val\":{\"days_ago\":1}} means \"priced within the last day\" and compiles to CURRENT_DATE - 1, re-evaluated every tick, where a literal date string silently rots. The {\"days_ago\": N} value form is valid on any date/timestamp column. A weekend is {\"col\":\"e.local_date\",\"op\":\"between\",\"val\":{\"weekend\":\"this\",\"tz\":\"America/New_York\"}} (\"next\" for the one after): the coming Friday to Sunday in tz, from today on a Friday to Sunday, resolved on every run. e.event_id, e.venue_id and e.performer_id take the ids rows carry (ev..., vn..., pf...). Authoritative validation runs in SQL; an invalid predicate returns a clear error."
  3. Changed1 schema field changed
    • changedInput schema / properties / predicate / description
      Previous value: -"Predicate DSL object (see tool description). {} = always-true, combined with max_firings_per_eval to get a \"top-N of the universe\" alert."New value: +"{} = always-true, combined with max_firings_per_eval to get a \"top-N of the universe\" alert. Predicate DSL (recursive JSON): a leaf is {col, op, val}; composites are {all:[...]} (AND) or {any:[...]} (OR). Columns are prefixed: \"ea.\" = event_analytics, \"e.\" = events, \"pa.\" = performer_analytics, \"p.\" = performers (p.name, the act the row is about), \"v.\" = venues (v.venue_name, the venue's name; v.city, v.state, v.country_code, v.capacity). Ops: =, !=, >, >=, <, <=, between (val=[lo,hi]), in (val=[...]), contains (case-insensitive substring on a TEXT column; val is a plain string), not_contains (removes the rows whose TEXT column holds val as a case-insensitive substring; a row with no value stays; % and _ in val match themselves, while contains reads them as wildcards). Example: {\"all\":[{\"col\":\"ea.price_self_z_7d_xs_z_subcat_tte\",\"op\":\">=\",\"val\":2},{\"col\":\"ea.days_to_event\",\"op\":\"between\",\"val\":[7,60]}]}. NAMED ACTS / TEAMS / PERFORMERS, use p.name. When the user names the act the events are BY (a musician like 'Taylor Swift', a team like 'Lakers', a comedian, a touring show), filter the performer column: {col:'p.name', op:'contains', val:'Taylor Swift'}. p.name is the act the row is KEYED on. e.event_name is the TITLE, which reads 'A at B' for a sports event and so also returns the opponent's home games, and for a concert also returns parking and support billings. A performer or team ask NEVER goes to e.event_name. Keep writing 'contains' for an act name. When what was typed IS a whole act name in the catalog, the server rewrites that leaf to op '=' and says so; anything else stays a substring. REMOVING ROWS BY A WORD. 'NOT Little', 'not the Lakers', 'without Taylor', 'excluding Hamilton' remove every row whose title contains the word: {col:'e.event_name', op:'not_contains', val:'Little'}. Never write '!=' for a word: '!=' compares the WHOLE value, so e.event_name != 'Manilow' removes nothing. A MISSPELLED superlative is still a superlative. 'htotest', 'hotest', 'bigest movers', 'chepest', 'lowset price' read as the word they intend and take the ordering that word takes. A ranking word is NEVER a name: never put it in a 'contains' leaf on e.event_name or p.name, and never answer with sort null because the spelling was odd. ECONOMIC FLOOR. The server already ANDs ea.listings_current >= 25 AND ea.median_price_current >= 40 into every screen. Do NOT add a listings-depth floor of your own. A column whose name ends in d1 or 1d is a ONE-DAY CHANGE, not yesterday's value. 'Inventory dropping' or 'listings falling' is a SEVEN-DAY change or an absorption column, never a one-day ratio. A stale row, or an event that is not active, is NEVER a move: its numbers describe the last day it was priced. Gate a movement ask on ea.last_price_snapshot_date with a relative date. The economic floor CAN be turned off at the call site (apply_floor=false, or apply_economic_floor=false on a rule), only when you explicitly want the raw universe. A freshness gate is NOT applied by default, so supply it yourself: {\"col\":\"ea.last_price_snapshot_date\",\"op\":\">=\",\"val\":{\"days_ago\":1}} means \"priced within the last day\" and compiles to CURRENT_DATE - 1, re-evaluated every tick, where a literal date string silently rots. The {\"days_ago\": N} value form is valid on any date/timestamp column. e.event_id, e.venue_id and e.performer_id take the ids rows carry (ev..., vn..., pf...). Authoritative validation runs in SQL; an invalid predicate returns a clear error."
  4. Changed2 schema fields changed
    • changedInput schema / properties / channels / description
      Previous value: -"Delivery channels, at least one. \"email\" mails the Matches to the account's address. The other value routes them to the destinations attached to this View instead, which is how a Slack or Discord channel receives them: create one with create_destination, then attach it with set_view_target. A View may carry both."New value: +"Delivery channels, at least one. \"email\" mails the Matches to the account's address. The other value routes them to the destinations attached to this View instead, which is how a Slack or Discord channel receives them: add one in the Ticker web app under Settings, then attach it with set_view_target. A View may carry both."
    • changedInput schema / properties / delivery_target_id / description
      Previous value: -"Optionally attach an alert destination (an id from list_destinations or create_destination) so this alert's Matches are delivered there the instant they fire, in addition to email. Omit for email-only."New value: +"Optionally attach an alert destination (an id from list_destinations; new destinations are added in the Ticker web app under Settings) so this alert's Matches are delivered there the instant they fire, in addition to email. Omit for email-only."
  5. Changed1 schema field changed
    • addedInput schema / properties / digest
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "The View's Digest: each Issue is the View's events with Movers, New and Gone against the previous Issue. Only the fields you pass change. Turning it on past the plan's Digest count is refused with the plan that carries more.",
      +  "properties": {
      +    "columns": {
      +      "description": "Which get-in the Digest page opens on: primary or secondary.",
      +      "enum": [
      +        "primary",
      +        "secondary"
      +      ],
      +      "type": "string"
      +    },
      +    "destination_ids": {
      +      "description": "Destinations (ids from list_destinations) that also receive each Issue. [] clears them.",
      +      "items": {
      +        "format": "uuid",
      +        "type": "string"
      +      },
      +      "maxItems": 50,
      +      "type": "array"
      +    },
      +    "enabled": {
      +      "description": "Turn the Digest on or off.",
      +      "type": "boolean"
      +    },
      +    "extra_columns": {
      +      "description": "Extra columns: absorption adds Absorbed 7d to the Issue page, email and files. [] removes it.",
      +      "items": {
      +        "enum": [
      +          "absorption"
      +        ],
      +        "type": "string"
      +      },
      +      "type": "array"
      +    },
      +    "formats": {
      +      "description": "The files each Issue links: csv, xlsx, pdf, md.",
      +      "items": {
      +        "enum": [
      +          "csv",
      +          "xlsx",
      +          "pdf",
      +          "md"
      +        ],
      +        "type": "string"
      +      },
      +      "minItems": 1,
      +      "type": "array"
      +    },
      +    "hour": {
      +      "description": "The hour (0 to 23) in the account's timezone when the Issue is built.",
      +      "maximum": 23,
      +      "minimum": 0,
      +      "type": "integer"
      +    },
      +    "sections": {
      +      "description": "Sections each Issue shows: movers, new, gone (default all three). The rest of the table always shows.",
      +      "items": {
      +        "enum": [
      +          "movers",
      +          "new",
      +          "gone"
      +        ],
      +        "type": "string"
      +      },
      +      "minItems": 1,
      +      "type": "array"
      +    },
      +    "table_columns": {
      +      "description": "Screener columns each Issue's table shows, in order: column names from list_screen_columns (e.g. ea.lowest_aip_price_current). Each must be a column the plan unlocks. [] restores the default table.",
      +      "items": {
      +        "maxLength": 120,
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "maxItems": 255,
      +      "type": "array"
      +    }
      +  },
      +  "type": "object"
      +}
  6. Changed2 schema fields changed
    • changedInput schema / properties / notification_mode / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "instant",
      -      "digest",
      -      "muted"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "instant",
      +      "batched",
      +      "muted",
      +      "digest"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / notification_mode / description
      Previous value: -"Per-alert EMAIL delivery mode: 'instant' (email each match), 'digest' (the Matches wait and go out together in one email, at the pace notification_cadence sets: `hourly` or `daily`), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. Alert destinations are unaffected: they always deliver instantly."New value: +"Per-alert EMAIL delivery mode: 'instant' (email each match), 'batched' (the Matches wait and go out together in one email, at the pace notification_cadence sets: `hourly` or `daily`), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. 'digest' is the old name of 'batched', accepted until 2026-11-30 and stored as 'batched'. Alert destinations are unaffected: they always deliver instantly."
  7. Changed2 schema fields changed
    • changedInput schema / properties / notification_cadence / description
      Previous value: -"How often this alert's Matches may leave as EMAIL: 'immediate' (each match), 'hourly', 'daily' (batched), or 'off' (Matches recorded but never emailed). Only paces EMAIL; an attached alert destination always delivers the instant a Match fires, regardless of this."New value: +"How often this alert's Matches may leave as EMAIL: `immediate` (each match), `hourly`, `daily` (batched), or `off` (Matches recorded but never emailed). Only paces EMAIL; an attached alert destination always delivers the instant a Match fires, regardless of this."
    • changedInput schema / properties / notification_mode / description
      Previous value: -"Per-alert EMAIL delivery mode: 'instant' (email each match), 'digest' (the Matches wait and go out together in an hourly email or a daily email, at the pace notification_cadence sets), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. Alert destinations are unaffected: they always deliver instantly."New value: +"Per-alert EMAIL delivery mode: 'instant' (email each match), 'digest' (the Matches wait and go out together in one email, at the pace notification_cadence sets: `hourly` or `daily`), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. Alert destinations are unaffected: they always deliver instantly."
  8. Changed3 schema fields changed
    • changedInput schema / properties / notification_cadence / description
      Previous value: -"How often this alert's Matches may leave as EMAIL: 'immediate' (each match), 'hourly', 'daily' (batched), or 'off' (Matches recorded but never emailed). Only paces EMAIL — an attached alert destination always delivers the instant a Match fires, regardless of this."New value: +"How often this alert's Matches may leave as EMAIL: 'immediate' (each match), 'hourly', 'daily' (batched), or 'off' (Matches recorded but never emailed). Only paces EMAIL; an attached alert destination always delivers the instant a Match fires, regardless of this."
    • changedInput schema / properties / notification_mode / description
      Previous value: -"Per-alert EMAIL delivery mode: 'instant' (email each match), 'digest' (the Matches wait and go out together in an hourly email or a daily email, at the pace notification_cadence sets), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. Alert destinations are unaffected — they always deliver instantly."New value: +"Per-alert EMAIL delivery mode: 'instant' (email each match), 'digest' (the Matches wait and go out together in an hourly email or a daily email, at the pace notification_cadence sets), or 'muted' (Matches recorded, never emailed). 'instant' and 'muted' override notification_cadence. Alert destinations are unaffected: they always deliver instantly."
    • changedInput schema / properties / tags / description
      Previous value: -"Free-text organization labels for this View (max 5, deduplicated). Purely for grouping/filtering in the app — tags never change what the View matches or where alerts deliver."New value: +"Free-text organization labels for this View (max 5, deduplicated). Purely for grouping/filtering in the app; tags never change what the View matches or where alerts deliver."
  9. First observed

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish the mutation/safety profile (readOnlyHint=false, destructiveHint=false, openWorldHint=true), so the bar is lower. The description adds genuine behavioral context: what constitutes a Match, that delivery happens by email or to a destination, and that a Digest is optional. It omits plan-limit refusals (Digest count) and that predicate validation is server-side, but the core create-and-deliver behavior is disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with zero filler. The purpose and the resource definition are front-loaded, and the routing guidance follows immediately, so every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a high-complexity, 12-parameter create tool with nested objects and no output schema, the description is thin on its own, but the exceptionally rich schema (predicate DSL, digest, triggers) carries the parameter burden and the description covers purpose and routing. The main residual gap is that, with no output schema, it does not say what a successful create returns (e.g. the new View id).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 83% (>80%), so the schema already documents the 12 parameters in depth. The description only gestures at the channels/digest parameters ('sends it by email or to a destination, with an optional Digest') without adding syntax beyond the schema. Baseline 3 is correct.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Creates a View') and defines the resource in domain terms: a saved predicate that records a Match when an event enters it, with email/destination delivery and an optional Digest. It also distinguishes itself from siblings by naming screen_events (test the predicate) and update_view (change an existing View).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use alternatives: 'Try the predicate with screen_events first; use update_view to change a View that exists.' This both routes away from the wrong tool (update_view for existing Views) and prescribes a safe pre-flight step, leaving nothing to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources