Skip to main content
Glama

Costory: Your Finops MCP

create_dashboard

Create a dashboard with one or more widgets. New dashboards are creator-only (you get Admin). To share, call set_object_permissions after create — do not send PRIVATE/PUBLIC or teamId. Call get_skill with skillId: "dashboards" first — see skill for context-first workflow and inheritance rules. Put shared settings in dashboardContext (period required when chart widgets are present: prefer datePreset when possible, otherwise startDate/endDate; for a forecast chart use CURRENT_YEAR / CURRENT_QUARTER / CURRENT_MONTH — same Forecast group as Explore, not YTD; text-only dashboards may omit period; plus metricId, common groupBy, currency, optional conditionsCel). Chart widgets inherit by default and should only specify overrides. Cost may omit metricId, currency, and groupBy. Usage requires its own metricId (from suggest_usage_metrics, not a cost column) and has no currency; omit groupBy to inherit. Budget groupBy is explicit (the budget VD bqName) and does not inherit dashboardContext.groupBy. Both inherit conditionsCel. Hide formula inputs with visible: false. Do not repeat from/to or datePreset when they match dashboardContext. The legacy context alias is temporarily accepted but deprecated; never send both. Text widgets use { type: "text", title, textContent } — no queries or period. Comparison widgets add compare: omit its from/to to compare against the preceding period automatically (preset-aware), and set compare.chartType to WATERFALL (default), TABLE, or KPI_BREAKDOWN. Widgets auto-pack into aligned grid rows; set per-widget w/h to override default sizing, or x/y together to pin a widget at an exact grid position. Optional tags: existing IDs from list_tags and/or { name, color? } for new tags; color defaults to #6366F1; missing tags are created. Omit and [] both leave the dashboard untagged. Returns a URL — you MUST include it in your response. EXAMPLE: "AWS overview dashboard" → see skill dashboards Workflow A.

Input Schema

NameRequiredDescriptionDefault
nameYesDashboard title.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagsNoPass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1). Omit and [] both leave the dashboard untagged.
contextNoDeprecated alias for `dashboardContext`; supported temporarily for backward compatibility. Do not send both fields.
widgetsNoList of widgets — chart widgets (queries, aggBy) or text widgets (`type: "text"`, `textContent`). Chart `queries` match the `query` tool `queries` shape — prefer sparse cost series and inherit from `dashboardContext`. Call get_skill skillId: "dashboards" first. Widgets are auto-packed into aligned grid rows; set optional `w`/`h` to override default sizing, or `x`/`y` together to pin a widget at an exact position. Example: [{"type":"text","title":"Notes","textContent":"Dashboard notes"}].
descriptionNoOptional longer description (default empty).
dashboardContextNoDashboard-level shared context. Period (datePreset or startDate/endDate) is required when the dashboard includes chart widgets; text-only dashboards may omit it. Put metricId, common groupBy, currency, and shared filters here — chart widgets omit those fields to inherit. `conditionsCel` is inherited by cost and usage series by default (`extendDashboardConditions` defaults to true). Call get_skill skillId: "dashboards" first.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / widgets / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      -    "properties": {
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "textContent": {
      -        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      -        "type": "string"
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "text",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "textContent",
      -      "title"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "aggBy": {
      -        "default": "Month",
      -        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      -        "enum": [
      -          "Hour",
      -          "Day",
      -          "Week",
      -          "Month",
      -          "Period"
      -        ],
      -        "type": "string"
      -      },
      -      "compare": {
      -        "additionalProperties": false,
      -        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      -        "properties": {
      -          "chartType": {
      -            "default": "WATERFALL",
      -            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      -            "enum": [
      -              "WATERFALL",
      -              "TABLE",
      -              "KPI_BREAKDOWN"
      -            ],
      -            "type": "string"
      -          },
      -          "enabled": {
      -            "default": true,
      -            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          },
      -          "to": {
      -            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "datePreset": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "TRAILING_90_DAYS",
      -              "TRAILING_30_DAYS",
      -              "TRAILING_45_DAYS",
      -              "TRAILING_7_DAYS",
      -              "TRAILING_3_DAYS",
      -              "TRAILING_1_DAYS",
      -              "TRAILING_14_WEEKS",
      -              "MTD",
      -              "QTD",
      -              "YTD",
      -              "CURRENT_MONTH",
      -              "CURRENT_QUARTER",
      -              "CURRENT_YEAR",
      -              "LAST_WEEK",
      -              "LAST_MONTH",
      -              "LAST_6_MONTHS",
      -              "LAST_12_MONTHS",
      -              "LAST_4_YEARS",
      -              "LAST_3_MONTHS",
      -              "LAST_INVOICE_MONTH"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      -      },
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "displayOptions": {
      -        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision, pivot {rows, columns}. get_skill dashboards.",
      -        "properties": {
      -          "hideEmptyRows": {
      -            "description": "Hide rows with abs displayed sum < 0.01",
      -            "type": "boolean"
      -          },
      -          "pivot": {
      -            "additionalProperties": false,
      -            "description": "TABLE-only. Place groupBy, query, time on rows/columns. Outer first. get_skill dashboards.",
      -            "properties": {
      -              "columns": {
      -                "description": "Non-empty. Outer first. Same axes as rows.",
      -                "items": {
      -                  "enum": [
      -                    "groupBy",
      -                    "query",
      -                    "time"
      -                  ],
      -                  "type": "string"
      -                },
      -                "minItems": 1,
      -                "type": "array"
      -              },
      -              "rows": {
      -                "description": "Non-empty. Outer first. Each of groupBy, query, time at most once across rows+columns.",
      -                "items": {
      -                  "enum": [
      -                    "groupBy",
      -                    "query",
      -                    "time"
      -                  ],
      -                  "type": "string"
      -                },
      -                "minItems": 1,
      -                "type": "array"
      -              }
      -            },
      -            "required": [
      -              "rows",
      -              "columns"
      -            ],
      -            "type": "object"
      -          },
      -          "precision": {
      -            "description": "Fraction digits 0–6",
      -            "maximum": 6,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "showTotal": {
      -            "description": "Show Total column",
      -            "type": "boolean"
      -          },
      -          "sort": {
      -            "properties": {
      -              "by": {
      -                "description": "total | cost | groupBy | query letter (a)",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "direction": {
      -                "default": "DESC",
      -                "description": "ASC | DESC (default DESC)",
      -                "enum": [
      -                  "ASC",
      -                  "DESC"
      -                ],
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "by"
      -            ],
      -            "type": "object"
      -          },
      -          "topN": {
      -            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "extendDashboardConditions": {
      -        "default": true,
      -        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` into cost and usage series `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "limit": {
      -        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      -        "maximum": 1000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "queries": {
      -        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. Cost may omit metricId, currency, and groupBy to inherit dashboardContext. Usage requires metricId (a usage id, not a cost column) and has no currency; omit groupBy to inherit. Cost and usage inherit conditionsCel unless extendDashboardConditions is false. `visible: false` hides a series. Call get_skill skillId: \"dashboards\" for examples.",
      -        "items": {
      -          "additionalProperties": {},
      -          "propertyNames": {
      -            "type": "string"
      -          },
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "scopeId": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "to": {
      -        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "chart",
      -        "default": "chart",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "title"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      +    "properties": {
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "textContent": {
      +        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "text",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "textContent",
      +      "title"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "aggBy": {
      +        "default": "Month",
      +        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      +        "enum": [
      +          "Hour",
      +          "Day",
      +          "Week",
      +          "Month",
      +          "Period"
      +        ],
      +        "type": "string"
      +      },
      +      "compare": {
      +        "additionalProperties": false,
      +        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      +        "properties": {
      +          "chartType": {
      +            "default": "WATERFALL",
      +            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      +            "enum": [
      +              "WATERFALL",
      +              "TABLE",
      +              "KPI_BREAKDOWN"
      +            ],
      +            "type": "string"
      +          },
      +          "enabled": {
      +            "default": true,
      +            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      +            "type": "boolean"
      +          },
      +          "from": {
      +            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "datePreset": {
      +        "anyOf": [
      +          {
      +            "enum": [
      +              "TRAILING_90_DAYS",
      +              "TRAILING_30_DAYS",
      +              "TRAILING_45_DAYS",
      +              "TRAILING_7_DAYS",
      +              "TRAILING_3_DAYS",
      +              "TRAILING_1_DAYS",
      +              "TRAILING_14_WEEKS",
      +              "MTD",
      +              "QTD",
      +              "YTD",
      +              "CURRENT_MONTH",
      +              "CURRENT_QUARTER",
      +              "CURRENT_YEAR",
      +              "LAST_WEEK",
      +              "LAST_MONTH",
      +              "LAST_6_MONTHS",
      +              "LAST_12_MONTHS",
      +              "LAST_4_YEARS",
      +              "LAST_3_MONTHS",
      +              "LAST_INVOICE_MONTH"
      +            ],
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      +      },
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "displayOptions": {
      +        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision, pivot {rows, columns}. get_skill dashboards.",
      +        "properties": {
      +          "hideEmptyRows": {
      +            "description": "Hide rows with abs displayed sum < 0.01",
      +            "type": "boolean"
      +          },
      +          "pivot": {
      +            "additionalProperties": false,
      +            "description": "TABLE-only. Place groupBy, query, time on rows/columns. Outer first. get_skill dashboards.",
      +            "properties": {
      +              "columns": {
      +                "description": "Non-empty. Outer first. Same axes as rows.",
      +                "items": {
      +                  "enum": [
      +                    "groupBy",
      +                    "query",
      +                    "time"
      +                  ],
      +                  "type": "string"
      +                },
      +                "minItems": 1,
      +                "type": "array"
      +              },
      +              "rows": {
      +                "description": "Non-empty. Outer first. Each of groupBy, query, time at most once across rows+columns.",
      +                "items": {
      +                  "enum": [
      +                    "groupBy",
      +                    "query",
      +                    "time"
      +                  ],
      +                  "type": "string"
      +                },
      +                "minItems": 1,
      +                "type": "array"
      +              }
      +            },
      +            "required": [
      +              "rows",
      +              "columns"
      +            ],
      +            "type": "object"
      +          },
      +          "precision": {
      +            "description": "Fraction digits 0–6",
      +            "maximum": 6,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "showTotal": {
      +            "description": "Show Total column",
      +            "type": "boolean"
      +          },
      +          "sort": {
      +            "properties": {
      +              "by": {
      +                "description": "total | cost | groupBy | query letter (a)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "direction": {
      +                "default": "DESC",
      +                "description": "ASC | DESC (default DESC)",
      +                "enum": [
      +                  "ASC",
      +                  "DESC"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "by"
      +            ],
      +            "type": "object"
      +          },
      +          "topN": {
      +            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "extendDashboardConditions": {
      +        "default": true,
      +        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` into cost and usage series `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      +        "type": "boolean"
      +      },
      +      "from": {
      +        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "limit": {
      +        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      +        "maximum": 1000,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "queries": {
      +        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. Cost may omit metricId, currency, and groupBy to inherit dashboardContext. Usage requires metricId (a usage id, not a cost column) and has no currency; omit groupBy to inherit. Budget groupBy is explicit (the budget virtual dimension bqName from get); it does not inherit dashboardContext.groupBy — omit for the total. Cost and usage inherit conditionsCel unless extendDashboardConditions is false. `visible: false` hides a series. Call get_skill skillId: \"dashboards\" for examples.",
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "scopeId": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "to": {
      +        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "chart",
      +        "default": "chart",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "title"
      +    ],
      +    "type": "object"
      +  }
      +]
  2. Changed4 schema fields changed
    • changedInput schema / properties / context / properties / conditionsCel / description
      Previous value: -"Dashboard-wide CEL filter. AND-merged into every cost widget that does not set `extendDashboardConditions: false` (default is inherit). Omit or empty string for no dashboard-level filter."New value: +"Dashboard-wide CEL filter. AND-merged into every cost and usage widget that does not set `extendDashboardConditions: false` (default is inherit). Omit or empty string for no dashboard-level filter."
    • changedInput schema / properties / dashboardContext / description
      Previous value: -"Dashboard-level shared context. Period (datePreset or startDate/endDate) is required when the dashboard includes chart widgets; text-only dashboards may omit it. Put metricId, common groupBy, currency, and shared filters here — chart widgets omit those fields to inherit. `conditionsCel` is inherited by default (`extendDashboardConditions` defaults to true). Call get_skill skillId: \"dashboards\" first."New value: +"Dashboard-level shared context. Period (datePreset or startDate/endDate) is required when the dashboard includes chart widgets; text-only dashboards may omit it. Put metricId, common groupBy, currency, and shared filters here — chart widgets omit those fields to inherit. `conditionsCel` is inherited by cost and usage series by default (`extendDashboardConditions` defaults to true). Call get_skill skillId: \"dashboards\" first."
    • changedInput schema / properties / dashboardContext / properties / conditionsCel / description
      Previous value: -"Dashboard-wide CEL filter. AND-merged into every cost widget that does not set `extendDashboardConditions: false` (default is inherit). Omit or empty string for no dashboard-level filter."New value: +"Dashboard-wide CEL filter. AND-merged into every cost and usage widget that does not set `extendDashboardConditions: false` (default is inherit). Omit or empty string for no dashboard-level filter."
    • changedInput schema / properties / widgets / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      -    "properties": {
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "textContent": {
      -        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      -        "type": "string"
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "text",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "textContent",
      -      "title"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "aggBy": {
      -        "default": "Month",
      -        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      -        "enum": [
      -          "Hour",
      -          "Day",
      -          "Week",
      -          "Month",
      -          "Period"
      -        ],
      -        "type": "string"
      -      },
      -      "compare": {
      -        "additionalProperties": false,
      -        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      -        "properties": {
      -          "chartType": {
      -            "default": "WATERFALL",
      -            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      -            "enum": [
      -              "WATERFALL",
      -              "TABLE",
      -              "KPI_BREAKDOWN"
      -            ],
      -            "type": "string"
      -          },
      -          "enabled": {
      -            "default": true,
      -            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          },
      -          "to": {
      -            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "datePreset": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "TRAILING_90_DAYS",
      -              "TRAILING_30_DAYS",
      -              "TRAILING_45_DAYS",
      -              "TRAILING_7_DAYS",
      -              "TRAILING_3_DAYS",
      -              "TRAILING_1_DAYS",
      -              "TRAILING_14_WEEKS",
      -              "MTD",
      -              "QTD",
      -              "YTD",
      -              "CURRENT_MONTH",
      -              "CURRENT_QUARTER",
      -              "CURRENT_YEAR",
      -              "LAST_WEEK",
      -              "LAST_MONTH",
      -              "LAST_6_MONTHS",
      -              "LAST_12_MONTHS",
      -              "LAST_4_YEARS",
      -              "LAST_3_MONTHS",
      -              "LAST_INVOICE_MONTH"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      -      },
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "displayOptions": {
      -        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      -        "properties": {
      -          "hideEmptyRows": {
      -            "description": "Hide rows with abs displayed sum < 0.01",
      -            "type": "boolean"
      -          },
      -          "precision": {
      -            "description": "Fraction digits 0–6",
      -            "maximum": 6,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "showTotal": {
      -            "description": "Show Total column",
      -            "type": "boolean"
      -          },
      -          "sort": {
      -            "properties": {
      -              "by": {
      -                "description": "total | cost | groupBy | query letter (a)",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "direction": {
      -                "default": "DESC",
      -                "description": "ASC | DESC (default DESC)",
      -                "enum": [
      -                  "ASC",
      -                  "DESC"
      -                ],
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "by"
      -            ],
      -            "type": "object"
      -          },
      -          "topN": {
      -            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "extendDashboardConditions": {
      -        "default": true,
      -        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "limit": {
      -        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE widget, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      -        "maximum": 1000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "queries": {
      -        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      -        "items": {
      -          "additionalProperties": {},
      -          "propertyNames": {
      -            "type": "string"
      -          },
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "scopeId": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "to": {
      -        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "chart",
      -        "default": "chart",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "title"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      +    "properties": {
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "textContent": {
      +        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "text",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "textContent",
      +      "title"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "aggBy": {
      +        "default": "Month",
      +        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      +        "enum": [
      +          "Hour",
      +          "Day",
      +          "Week",
      +          "Month",
      +          "Period"
      +        ],
      +        "type": "string"
      +      },
      +      "compare": {
      +        "additionalProperties": false,
      +        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      +        "properties": {
      +          "chartType": {
      +            "default": "WATERFALL",
      +            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      +            "enum": [
      +              "WATERFALL",
      +              "TABLE",
      +              "KPI_BREAKDOWN"
      +            ],
      +            "type": "string"
      +          },
      +          "enabled": {
      +            "default": true,
      +            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      +            "type": "boolean"
      +          },
      +          "from": {
      +            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "datePreset": {
      +        "anyOf": [
      +          {
      +            "enum": [
      +              "TRAILING_90_DAYS",
      +              "TRAILING_30_DAYS",
      +              "TRAILING_45_DAYS",
      +              "TRAILING_7_DAYS",
      +              "TRAILING_3_DAYS",
      +              "TRAILING_1_DAYS",
      +              "TRAILING_14_WEEKS",
      +              "MTD",
      +              "QTD",
      +              "YTD",
      +              "CURRENT_MONTH",
      +              "CURRENT_QUARTER",
      +              "CURRENT_YEAR",
      +              "LAST_WEEK",
      +              "LAST_MONTH",
      +              "LAST_6_MONTHS",
      +              "LAST_12_MONTHS",
      +              "LAST_4_YEARS",
      +              "LAST_3_MONTHS",
      +              "LAST_INVOICE_MONTH"
      +            ],
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      +      },
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "displayOptions": {
      +        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision, pivot {rows, columns}. get_skill dashboards.",
      +        "properties": {
      +          "hideEmptyRows": {
      +            "description": "Hide rows with abs displayed sum < 0.01",
      +            "type": "boolean"
      +          },
      +          "pivot": {
      +            "additionalProperties": false,
      +            "description": "TABLE-only. Place groupBy, query, time on rows/columns. Outer first. get_skill dashboards.",
      +            "properties": {
      +              "columns": {
      +                "description": "Non-empty. Outer first. Same axes as rows.",
      +                "items": {
      +                  "enum": [
      +                    "groupBy",
      +                    "query",
      +                    "time"
      +                  ],
      +                  "type": "string"
      +                },
      +                "minItems": 1,
      +                "type": "array"
      +              },
      +              "rows": {
      +                "description": "Non-empty. Outer first. Each of groupBy, query, time at most once across rows+columns.",
      +                "items": {
      +                  "enum": [
      +                    "groupBy",
      +                    "query",
      +                    "time"
      +                  ],
      +                  "type": "string"
      +                },
      +                "minItems": 1,
      +                "type": "array"
      +              }
      +            },
      +            "required": [
      +              "rows",
      +              "columns"
      +            ],
      +            "type": "object"
      +          },
      +          "precision": {
      +            "description": "Fraction digits 0–6",
      +            "maximum": 6,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "showTotal": {
      +            "description": "Show Total column",
      +            "type": "boolean"
      +          },
      +          "sort": {
      +            "properties": {
      +              "by": {
      +                "description": "total | cost | groupBy | query letter (a)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "direction": {
      +                "default": "DESC",
      +                "description": "ASC | DESC (default DESC)",
      +                "enum": [
      +                  "ASC",
      +                  "DESC"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "by"
      +            ],
      +            "type": "object"
      +          },
      +          "topN": {
      +            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "extendDashboardConditions": {
      +        "default": true,
      +        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` into cost and usage series `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      +        "type": "boolean"
      +      },
      +      "from": {
      +        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "limit": {
      +        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      +        "maximum": 1000,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "queries": {
      +        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. Cost may omit metricId, currency, and groupBy to inherit dashboardContext. Usage requires metricId (a usage id, not a cost column) and has no currency; omit groupBy to inherit. Cost and usage inherit conditionsCel unless extendDashboardConditions is false. `visible: false` hides a series. Call get_skill skillId: \"dashboards\" for examples.",
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "scopeId": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "to": {
      +        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "chart",
      +        "default": "chart",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "title"
      +    ],
      +    "type": "object"
      +  }
      +]
  3. Changed2 schema fields changed
    • changedInput schema / properties / context / properties / datePreset / description
      Previous value: -"Default date preset inherited when a widget omits date fields. Prefer this over startDate/endDate whenever an available preset matches the requested range."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate when a preset matches the requested range."
    • changedInput schema / properties / dashboardContext / properties / datePreset / description
      Previous value: -"Default date preset inherited when a widget omits date fields. Prefer this over startDate/endDate whenever an available preset matches the requested range."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate when a preset matches the requested range."
  4. Changed2 schema fields changed
    • changedInput schema / properties / context / properties / currency / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "USD",
      -      "EUR",
      -      "GBP",
      -      "CNY"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "USD",
      +      "EUR",
      +      "GBP",
      +      "CNY",
      +      "KRW"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / dashboardContext / properties / currency / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "USD",
      -      "EUR",
      -      "GBP",
      -      "CNY"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "USD",
      +      "EUR",
      +      "GBP",
      +      "CNY",
      +      "KRW"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
  5. Changed1 schema field changed
    • addedInput schema / properties / tags
      Added value: +{
      +  "description": "Pass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1). Omit and [] both leave the dashboard untagged.",
      +  "items": {
      +    "anyOf": [
      +      {
      +        "description": "Existing tag ID",
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      {
      +        "additionalProperties": false,
      +        "properties": {
      +          "color": {
      +            "default": "#6366F1",
      +            "description": "Hex color for the new tag (defaults to #6366F1)",
      +            "minLength": 1,
      +            "type": "string"
      +          },
      +          "name": {
      +            "minLength": 1,
      +            "type": "string"
      +          }
      +        },
      +        "required": [
      +          "name"
      +        ],
      +        "type": "object"
      +      }
      +    ]
      +  },
      +  "type": "array"
      +}
  6. Changed3 schema fields changed
    • changedInput schema / properties / context / properties / datePreset / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "TRAILING_90_DAYS",
      -      "TRAILING_30_DAYS",
      -      "TRAILING_45_DAYS",
      -      "TRAILING_7_DAYS",
      -      "TRAILING_3_DAYS",
      -      "TRAILING_14_WEEKS",
      -      "MTD",
      -      "QTD",
      -      "YTD",
      -      "CURRENT_MONTH",
      -      "CURRENT_QUARTER",
      -      "CURRENT_YEAR",
      -      "LAST_WEEK",
      -      "LAST_MONTH",
      -      "LAST_6_MONTHS",
      -      "LAST_12_MONTHS",
      -      "LAST_4_YEARS",
      -      "LAST_3_MONTHS",
      -      "LAST_INVOICE_MONTH"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "TRAILING_90_DAYS",
      +      "TRAILING_30_DAYS",
      +      "TRAILING_45_DAYS",
      +      "TRAILING_7_DAYS",
      +      "TRAILING_3_DAYS",
      +      "TRAILING_1_DAYS",
      +      "TRAILING_14_WEEKS",
      +      "MTD",
      +      "QTD",
      +      "YTD",
      +      "CURRENT_MONTH",
      +      "CURRENT_QUARTER",
      +      "CURRENT_YEAR",
      +      "LAST_WEEK",
      +      "LAST_MONTH",
      +      "LAST_6_MONTHS",
      +      "LAST_12_MONTHS",
      +      "LAST_4_YEARS",
      +      "LAST_3_MONTHS",
      +      "LAST_INVOICE_MONTH"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / dashboardContext / properties / datePreset / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "TRAILING_90_DAYS",
      -      "TRAILING_30_DAYS",
      -      "TRAILING_45_DAYS",
      -      "TRAILING_7_DAYS",
      -      "TRAILING_3_DAYS",
      -      "TRAILING_14_WEEKS",
      -      "MTD",
      -      "QTD",
      -      "YTD",
      -      "CURRENT_MONTH",
      -      "CURRENT_QUARTER",
      -      "CURRENT_YEAR",
      -      "LAST_WEEK",
      -      "LAST_MONTH",
      -      "LAST_6_MONTHS",
      -      "LAST_12_MONTHS",
      -      "LAST_4_YEARS",
      -      "LAST_3_MONTHS",
      -      "LAST_INVOICE_MONTH"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "TRAILING_90_DAYS",
      +      "TRAILING_30_DAYS",
      +      "TRAILING_45_DAYS",
      +      "TRAILING_7_DAYS",
      +      "TRAILING_3_DAYS",
      +      "TRAILING_1_DAYS",
      +      "TRAILING_14_WEEKS",
      +      "MTD",
      +      "QTD",
      +      "YTD",
      +      "CURRENT_MONTH",
      +      "CURRENT_QUARTER",
      +      "CURRENT_YEAR",
      +      "LAST_WEEK",
      +      "LAST_MONTH",
      +      "LAST_6_MONTHS",
      +      "LAST_12_MONTHS",
      +      "LAST_4_YEARS",
      +      "LAST_3_MONTHS",
      +      "LAST_INVOICE_MONTH"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / widgets / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      -    "properties": {
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "textContent": {
      -        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      -        "type": "string"
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "text",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "textContent",
      -      "title"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "aggBy": {
      -        "default": "Month",
      -        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      -        "enum": [
      -          "Hour",
      -          "Day",
      -          "Week",
      -          "Month",
      -          "Period"
      -        ],
      -        "type": "string"
      -      },
      -      "compare": {
      -        "additionalProperties": false,
      -        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      -        "properties": {
      -          "chartType": {
      -            "default": "WATERFALL",
      -            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      -            "enum": [
      -              "WATERFALL",
      -              "TABLE",
      -              "KPI_BREAKDOWN"
      -            ],
      -            "type": "string"
      -          },
      -          "enabled": {
      -            "default": true,
      -            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          },
      -          "to": {
      -            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "datePreset": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "TRAILING_90_DAYS",
      -              "TRAILING_30_DAYS",
      -              "TRAILING_45_DAYS",
      -              "TRAILING_7_DAYS",
      -              "TRAILING_3_DAYS",
      -              "TRAILING_14_WEEKS",
      -              "MTD",
      -              "QTD",
      -              "YTD",
      -              "CURRENT_MONTH",
      -              "CURRENT_QUARTER",
      -              "CURRENT_YEAR",
      -              "LAST_WEEK",
      -              "LAST_MONTH",
      -              "LAST_6_MONTHS",
      -              "LAST_12_MONTHS",
      -              "LAST_4_YEARS",
      -              "LAST_3_MONTHS",
      -              "LAST_INVOICE_MONTH"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      -      },
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "displayOptions": {
      -        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      -        "properties": {
      -          "hideEmptyRows": {
      -            "description": "Hide rows with abs displayed sum < 0.01",
      -            "type": "boolean"
      -          },
      -          "precision": {
      -            "description": "Fraction digits 0–6",
      -            "maximum": 6,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "showTotal": {
      -            "description": "Show Total column",
      -            "type": "boolean"
      -          },
      -          "sort": {
      -            "properties": {
      -              "by": {
      -                "description": "total | cost | groupBy | query letter (a)",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "direction": {
      -                "default": "DESC",
      -                "description": "ASC | DESC (default DESC)",
      -                "enum": [
      -                  "ASC",
      -                  "DESC"
      -                ],
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "by"
      -            ],
      -            "type": "object"
      -          },
      -          "topN": {
      -            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "extendDashboardConditions": {
      -        "default": true,
      -        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "limit": {
      -        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE widget, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      -        "maximum": 1000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "queries": {
      -        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      -        "items": {
      -          "additionalProperties": {},
      -          "propertyNames": {
      -            "type": "string"
      -          },
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "scopeId": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "to": {
      -        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "chart",
      -        "default": "chart",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "title"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      +    "properties": {
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "textContent": {
      +        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "text",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "textContent",
      +      "title"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "aggBy": {
      +        "default": "Month",
      +        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      +        "enum": [
      +          "Hour",
      +          "Day",
      +          "Week",
      +          "Month",
      +          "Period"
      +        ],
      +        "type": "string"
      +      },
      +      "compare": {
      +        "additionalProperties": false,
      +        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      +        "properties": {
      +          "chartType": {
      +            "default": "WATERFALL",
      +            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      +            "enum": [
      +              "WATERFALL",
      +              "TABLE",
      +              "KPI_BREAKDOWN"
      +            ],
      +            "type": "string"
      +          },
      +          "enabled": {
      +            "default": true,
      +            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      +            "type": "boolean"
      +          },
      +          "from": {
      +            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "datePreset": {
      +        "anyOf": [
      +          {
      +            "enum": [
      +              "TRAILING_90_DAYS",
      +              "TRAILING_30_DAYS",
      +              "TRAILING_45_DAYS",
      +              "TRAILING_7_DAYS",
      +              "TRAILING_3_DAYS",
      +              "TRAILING_1_DAYS",
      +              "TRAILING_14_WEEKS",
      +              "MTD",
      +              "QTD",
      +              "YTD",
      +              "CURRENT_MONTH",
      +              "CURRENT_QUARTER",
      +              "CURRENT_YEAR",
      +              "LAST_WEEK",
      +              "LAST_MONTH",
      +              "LAST_6_MONTHS",
      +              "LAST_12_MONTHS",
      +              "LAST_4_YEARS",
      +              "LAST_3_MONTHS",
      +              "LAST_INVOICE_MONTH"
      +            ],
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      +      },
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "displayOptions": {
      +        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      +        "properties": {
      +          "hideEmptyRows": {
      +            "description": "Hide rows with abs displayed sum < 0.01",
      +            "type": "boolean"
      +          },
      +          "precision": {
      +            "description": "Fraction digits 0–6",
      +            "maximum": 6,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "showTotal": {
      +            "description": "Show Total column",
      +            "type": "boolean"
      +          },
      +          "sort": {
      +            "properties": {
      +              "by": {
      +                "description": "total | cost | groupBy | query letter (a)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "direction": {
      +                "default": "DESC",
      +                "description": "ASC | DESC (default DESC)",
      +                "enum": [
      +                  "ASC",
      +                  "DESC"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "by"
      +            ],
      +            "type": "object"
      +          },
      +          "topN": {
      +            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "extendDashboardConditions": {
      +        "default": true,
      +        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      +        "type": "boolean"
      +      },
      +      "from": {
      +        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "limit": {
      +        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE widget, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      +        "maximum": 1000,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "queries": {
      +        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "scopeId": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "to": {
      +        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "chart",
      +        "default": "chart",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "title"
      +    ],
      +    "type": "object"
      +  }
      +]
  7. Changed2 schema fields changed
    • removedInput schema / properties / teamId
      Removed value: -{
      -  "anyOf": [
      -    {
      -      "type": "string"
      -    },
      -    {
      -      "type": "null"
      -    }
      -  ],
      -  "description": "Optional owning team id. Independent of visibility; omit or null for no team."
      -}
    • removedInput schema / properties / visibility
      Removed value: -{
      -  "default": "PRIVATE",
      -  "description": "PRIVATE (default), PUBLIC, or TEMPLATE. Set `teamId` to share with a team — there is no TEAM visibility value.",
      -  "enum": [
      -    "PRIVATE",
      -    "PUBLIC",
      -    "TEMPLATE"
      -  ],
      -  "type": "string"
      -}
  8. Changed3 schema fields changed
    • changedInput schema / properties / context / properties / datePreset / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "TRAILING_90_DAYS",
      -      "TRAILING_30_DAYS",
      -      "TRAILING_45_DAYS",
      -      "TRAILING_7_DAYS",
      -      "TRAILING_3_DAYS",
      -      "TRAILING_14_WEEKS",
      -      "MTD",
      -      "QTD",
      -      "YTD",
      -      "LAST_WEEK",
      -      "LAST_MONTH",
      -      "LAST_6_MONTHS",
      -      "LAST_12_MONTHS",
      -      "LAST_4_YEARS",
      -      "LAST_3_MONTHS",
      -      "LAST_INVOICE_MONTH"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "TRAILING_90_DAYS",
      +      "TRAILING_30_DAYS",
      +      "TRAILING_45_DAYS",
      +      "TRAILING_7_DAYS",
      +      "TRAILING_3_DAYS",
      +      "TRAILING_14_WEEKS",
      +      "MTD",
      +      "QTD",
      +      "YTD",
      +      "CURRENT_MONTH",
      +      "CURRENT_QUARTER",
      +      "CURRENT_YEAR",
      +      "LAST_WEEK",
      +      "LAST_MONTH",
      +      "LAST_6_MONTHS",
      +      "LAST_12_MONTHS",
      +      "LAST_4_YEARS",
      +      "LAST_3_MONTHS",
      +      "LAST_INVOICE_MONTH"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / dashboardContext / properties / datePreset / anyOf
      Previous value: -[
      -  {
      -    "enum": [
      -      "TRAILING_90_DAYS",
      -      "TRAILING_30_DAYS",
      -      "TRAILING_45_DAYS",
      -      "TRAILING_7_DAYS",
      -      "TRAILING_3_DAYS",
      -      "TRAILING_14_WEEKS",
      -      "MTD",
      -      "QTD",
      -      "YTD",
      -      "LAST_WEEK",
      -      "LAST_MONTH",
      -      "LAST_6_MONTHS",
      -      "LAST_12_MONTHS",
      -      "LAST_4_YEARS",
      -      "LAST_3_MONTHS",
      -      "LAST_INVOICE_MONTH"
      -    ],
      -    "type": "string"
      -  },
      -  {
      -    "type": "null"
      -  }
      -]New value: +[
      +  {
      +    "enum": [
      +      "TRAILING_90_DAYS",
      +      "TRAILING_30_DAYS",
      +      "TRAILING_45_DAYS",
      +      "TRAILING_7_DAYS",
      +      "TRAILING_3_DAYS",
      +      "TRAILING_14_WEEKS",
      +      "MTD",
      +      "QTD",
      +      "YTD",
      +      "CURRENT_MONTH",
      +      "CURRENT_QUARTER",
      +      "CURRENT_YEAR",
      +      "LAST_WEEK",
      +      "LAST_MONTH",
      +      "LAST_6_MONTHS",
      +      "LAST_12_MONTHS",
      +      "LAST_4_YEARS",
      +      "LAST_3_MONTHS",
      +      "LAST_INVOICE_MONTH"
      +    ],
      +    "type": "string"
      +  },
      +  {
      +    "type": "null"
      +  }
      +]
    • changedInput schema / properties / widgets / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      -    "properties": {
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "textContent": {
      -        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      -        "type": "string"
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "text",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "textContent",
      -      "title"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "aggBy": {
      -        "default": "Month",
      -        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      -        "enum": [
      -          "Hour",
      -          "Day",
      -          "Week",
      -          "Month",
      -          "Period"
      -        ],
      -        "type": "string"
      -      },
      -      "compare": {
      -        "additionalProperties": false,
      -        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      -        "properties": {
      -          "chartType": {
      -            "default": "WATERFALL",
      -            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      -            "enum": [
      -              "WATERFALL",
      -              "TABLE",
      -              "KPI_BREAKDOWN"
      -            ],
      -            "type": "string"
      -          },
      -          "enabled": {
      -            "default": true,
      -            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          },
      -          "to": {
      -            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "datePreset": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "TRAILING_90_DAYS",
      -              "TRAILING_30_DAYS",
      -              "TRAILING_45_DAYS",
      -              "TRAILING_7_DAYS",
      -              "TRAILING_3_DAYS",
      -              "TRAILING_14_WEEKS",
      -              "MTD",
      -              "QTD",
      -              "YTD",
      -              "LAST_WEEK",
      -              "LAST_MONTH",
      -              "LAST_6_MONTHS",
      -              "LAST_12_MONTHS",
      -              "LAST_4_YEARS",
      -              "LAST_3_MONTHS",
      -              "LAST_INVOICE_MONTH"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      -      },
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "displayOptions": {
      -        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      -        "properties": {
      -          "hideEmptyRows": {
      -            "description": "Hide rows with abs displayed sum < 0.01",
      -            "type": "boolean"
      -          },
      -          "precision": {
      -            "description": "Fraction digits 0–6",
      -            "maximum": 6,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "showTotal": {
      -            "description": "Show Total column",
      -            "type": "boolean"
      -          },
      -          "sort": {
      -            "properties": {
      -              "by": {
      -                "description": "total | cost | groupBy | query letter (a)",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "direction": {
      -                "default": "DESC",
      -                "description": "ASC | DESC (default DESC)",
      -                "enum": [
      -                  "ASC",
      -                  "DESC"
      -                ],
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "by"
      -            ],
      -            "type": "object"
      -          },
      -          "topN": {
      -            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "extendDashboardConditions": {
      -        "default": true,
      -        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "limit": {
      -        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE widget, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      -        "maximum": 1000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "queries": {
      -        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      -        "items": {
      -          "additionalProperties": {},
      -          "propertyNames": {
      -            "type": "string"
      -          },
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "scopeId": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "to": {
      -        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "chart",
      -        "default": "chart",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "title"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      +    "properties": {
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "textContent": {
      +        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "text",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "textContent",
      +      "title"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "aggBy": {
      +        "default": "Month",
      +        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      +        "enum": [
      +          "Hour",
      +          "Day",
      +          "Week",
      +          "Month",
      +          "Period"
      +        ],
      +        "type": "string"
      +      },
      +      "compare": {
      +        "additionalProperties": false,
      +        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      +        "properties": {
      +          "chartType": {
      +            "default": "WATERFALL",
      +            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      +            "enum": [
      +              "WATERFALL",
      +              "TABLE",
      +              "KPI_BREAKDOWN"
      +            ],
      +            "type": "string"
      +          },
      +          "enabled": {
      +            "default": true,
      +            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      +            "type": "boolean"
      +          },
      +          "from": {
      +            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "datePreset": {
      +        "anyOf": [
      +          {
      +            "enum": [
      +              "TRAILING_90_DAYS",
      +              "TRAILING_30_DAYS",
      +              "TRAILING_45_DAYS",
      +              "TRAILING_7_DAYS",
      +              "TRAILING_3_DAYS",
      +              "TRAILING_14_WEEKS",
      +              "MTD",
      +              "QTD",
      +              "YTD",
      +              "CURRENT_MONTH",
      +              "CURRENT_QUARTER",
      +              "CURRENT_YEAR",
      +              "LAST_WEEK",
      +              "LAST_MONTH",
      +              "LAST_6_MONTHS",
      +              "LAST_12_MONTHS",
      +              "LAST_4_YEARS",
      +              "LAST_3_MONTHS",
      +              "LAST_INVOICE_MONTH"
      +            ],
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      +      },
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "displayOptions": {
      +        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      +        "properties": {
      +          "hideEmptyRows": {
      +            "description": "Hide rows with abs displayed sum < 0.01",
      +            "type": "boolean"
      +          },
      +          "precision": {
      +            "description": "Fraction digits 0–6",
      +            "maximum": 6,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "showTotal": {
      +            "description": "Show Total column",
      +            "type": "boolean"
      +          },
      +          "sort": {
      +            "properties": {
      +              "by": {
      +                "description": "total | cost | groupBy | query letter (a)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "direction": {
      +                "default": "DESC",
      +                "description": "ASC | DESC (default DESC)",
      +                "enum": [
      +                  "ASC",
      +                  "DESC"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "by"
      +            ],
      +            "type": "object"
      +          },
      +          "topN": {
      +            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "extendDashboardConditions": {
      +        "default": true,
      +        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      +        "type": "boolean"
      +      },
      +      "from": {
      +        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "limit": {
      +        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE widget, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      +        "maximum": 1000,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "queries": {
      +        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "scopeId": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "to": {
      +        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "chart",
      +        "default": "chart",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "title"
      +    ],
      +    "type": "object"
      +  }
      +]
  9. Changed1 schema field changed
    • changedInput schema / properties / widgets / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      -    "properties": {
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "textContent": {
      -        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      -        "type": "string"
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "text",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "textContent",
      -      "title"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "aggBy": {
      -        "default": "Month",
      -        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      -        "enum": [
      -          "Hour",
      -          "Day",
      -          "Week",
      -          "Month",
      -          "Period"
      -        ],
      -        "type": "string"
      -      },
      -      "compare": {
      -        "additionalProperties": false,
      -        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      -        "properties": {
      -          "chartType": {
      -            "default": "WATERFALL",
      -            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      -            "enum": [
      -              "WATERFALL",
      -              "TABLE",
      -              "KPI_BREAKDOWN"
      -            ],
      -            "type": "string"
      -          },
      -          "enabled": {
      -            "default": true,
      -            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          },
      -          "to": {
      -            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "datePreset": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "TRAILING_90_DAYS",
      -              "TRAILING_30_DAYS",
      -              "TRAILING_45_DAYS",
      -              "TRAILING_7_DAYS",
      -              "TRAILING_3_DAYS",
      -              "TRAILING_14_WEEKS",
      -              "MTD",
      -              "QTD",
      -              "YTD",
      -              "LAST_WEEK",
      -              "LAST_MONTH",
      -              "LAST_6_MONTHS",
      -              "LAST_12_MONTHS",
      -              "LAST_4_YEARS",
      -              "LAST_3_MONTHS",
      -              "LAST_INVOICE_MONTH"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      -      },
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "displayOptions": {
      -        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      -        "properties": {
      -          "hideEmptyRows": {
      -            "description": "Hide rows with abs displayed sum < 0.01",
      -            "type": "boolean"
      -          },
      -          "precision": {
      -            "description": "Fraction digits 0–6",
      -            "maximum": 6,
      -            "minimum": 0,
      -            "type": "integer"
      -          },
      -          "showTotal": {
      -            "description": "Show Total column",
      -            "type": "boolean"
      -          },
      -          "sort": {
      -            "properties": {
      -              "by": {
      -                "description": "total | cost | groupBy | query letter (a)",
      -                "minLength": 1,
      -                "type": "string"
      -              },
      -              "direction": {
      -                "default": "DESC",
      -                "description": "ASC | DESC (default DESC)",
      -                "enum": [
      -                  "ASC",
      -                  "DESC"
      -                ],
      -                "type": "string"
      -              }
      -            },
      -            "required": [
      -              "by"
      -            ],
      -            "type": "object"
      -          },
      -          "topN": {
      -            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      -            "maximum": 100,
      -            "minimum": 1,
      -            "type": "integer"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "extendDashboardConditions": {
      -        "default": true,
      -        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "limit": {
      -        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups.",
      -        "maximum": 1000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "queries": {
      -        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      -        "items": {
      -          "additionalProperties": {},
      -          "propertyNames": {
      -            "type": "string"
      -          },
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "scopeId": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "to": {
      -        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "chart",
      -        "default": "chart",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "title"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      +    "properties": {
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "textContent": {
      +        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "text",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "textContent",
      +      "title"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "aggBy": {
      +        "default": "Month",
      +        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      +        "enum": [
      +          "Hour",
      +          "Day",
      +          "Week",
      +          "Month",
      +          "Period"
      +        ],
      +        "type": "string"
      +      },
      +      "compare": {
      +        "additionalProperties": false,
      +        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      +        "properties": {
      +          "chartType": {
      +            "default": "WATERFALL",
      +            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      +            "enum": [
      +              "WATERFALL",
      +              "TABLE",
      +              "KPI_BREAKDOWN"
      +            ],
      +            "type": "string"
      +          },
      +          "enabled": {
      +            "default": true,
      +            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      +            "type": "boolean"
      +          },
      +          "from": {
      +            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "datePreset": {
      +        "anyOf": [
      +          {
      +            "enum": [
      +              "TRAILING_90_DAYS",
      +              "TRAILING_30_DAYS",
      +              "TRAILING_45_DAYS",
      +              "TRAILING_7_DAYS",
      +              "TRAILING_3_DAYS",
      +              "TRAILING_14_WEEKS",
      +              "MTD",
      +              "QTD",
      +              "YTD",
      +              "LAST_WEEK",
      +              "LAST_MONTH",
      +              "LAST_6_MONTHS",
      +              "LAST_12_MONTHS",
      +              "LAST_4_YEARS",
      +              "LAST_3_MONTHS",
      +              "LAST_INVOICE_MONTH"
      +            ],
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      +      },
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "displayOptions": {
      +        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      +        "properties": {
      +          "hideEmptyRows": {
      +            "description": "Hide rows with abs displayed sum < 0.01",
      +            "type": "boolean"
      +          },
      +          "precision": {
      +            "description": "Fraction digits 0–6",
      +            "maximum": 6,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "showTotal": {
      +            "description": "Show Total column",
      +            "type": "boolean"
      +          },
      +          "sort": {
      +            "properties": {
      +              "by": {
      +                "description": "total | cost | groupBy | query letter (a)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "direction": {
      +                "default": "DESC",
      +                "description": "ASC | DESC (default DESC)",
      +                "enum": [
      +                  "ASC",
      +                  "DESC"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "by"
      +            ],
      +            "type": "object"
      +          },
      +          "topN": {
      +            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "extendDashboardConditions": {
      +        "default": true,
      +        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      +        "type": "boolean"
      +      },
      +      "from": {
      +        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "limit": {
      +        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups. On a non-comparison TABLE widget, use displayOptions.topN for the row cap and omit this — the two are mutually exclusive there.",
      +        "maximum": 1000,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "queries": {
      +        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "scopeId": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "to": {
      +        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "chart",
      +        "default": "chart",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "title"
      +    ],
      +    "type": "object"
      +  }
      +]
  10. Changed1 schema field changed
    • changedInput schema / properties / widgets / items / oneOf
      Previous value: -[
      -  {
      -    "additionalProperties": false,
      -    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      -    "properties": {
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "textContent": {
      -        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      -        "type": "string"
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "text",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "type",
      -      "textContent",
      -      "title"
      -    ],
      -    "type": "object"
      -  },
      -  {
      -    "additionalProperties": false,
      -    "properties": {
      -      "aggBy": {
      -        "default": "Month",
      -        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      -        "enum": [
      -          "Hour",
      -          "Day",
      -          "Week",
      -          "Month",
      -          "Period"
      -        ],
      -        "type": "string"
      -      },
      -      "compare": {
      -        "additionalProperties": false,
      -        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      -        "properties": {
      -          "chartType": {
      -            "default": "WATERFALL",
      -            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      -            "enum": [
      -              "WATERFALL",
      -              "TABLE",
      -              "KPI_BREAKDOWN"
      -            ],
      -            "type": "string"
      -          },
      -          "enabled": {
      -            "default": true,
      -            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      -            "type": "boolean"
      -          },
      -          "from": {
      -            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          },
      -          "to": {
      -            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      -            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -            "type": "string"
      -          }
      -        },
      -        "type": "object"
      -      },
      -      "datePreset": {
      -        "anyOf": [
      -          {
      -            "enum": [
      -              "TRAILING_90_DAYS",
      -              "TRAILING_30_DAYS",
      -              "TRAILING_45_DAYS",
      -              "TRAILING_7_DAYS",
      -              "TRAILING_3_DAYS",
      -              "TRAILING_14_WEEKS",
      -              "MTD",
      -              "QTD",
      -              "YTD",
      -              "LAST_WEEK",
      -              "LAST_MONTH",
      -              "LAST_6_MONTHS",
      -              "LAST_12_MONTHS",
      -              "LAST_4_YEARS",
      -              "LAST_3_MONTHS",
      -              "LAST_INVOICE_MONTH"
      -            ],
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      -      },
      -      "description": {
      -        "default": "",
      -        "type": "string"
      -      },
      -      "extendDashboardConditions": {
      -        "default": true,
      -        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      -        "type": "boolean"
      -      },
      -      "from": {
      -        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "h": {
      -        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 9007199254740991,
      -        "type": "integer"
      -      },
      -      "limit": {
      -        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups.",
      -        "maximum": 1000,
      -        "minimum": 1,
      -        "type": "integer"
      -      },
      -      "queries": {
      -        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      -        "items": {
      -          "additionalProperties": {},
      -          "propertyNames": {
      -            "type": "string"
      -          },
      -          "type": "object"
      -        },
      -        "type": "array"
      -      },
      -      "scopeId": {
      -        "anyOf": [
      -          {
      -            "type": "string"
      -          },
      -          {
      -            "type": "null"
      -          }
      -        ],
      -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      -      },
      -      "title": {
      -        "type": "string"
      -      },
      -      "to": {
      -        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      -        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      -        "type": "string"
      -      },
      -      "type": {
      -        "const": "chart",
      -        "default": "chart",
      -        "type": "string"
      -      },
      -      "w": {
      -        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      -        "exclusiveMinimum": 0,
      -        "maximum": 12,
      -        "type": "integer"
      -      },
      -      "x": {
      -        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      -        "maximum": 11,
      -        "minimum": 0,
      -        "type": "integer"
      -      },
      -      "y": {
      -        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      -        "maximum": 9007199254740991,
      -        "minimum": 0,
      -        "type": "integer"
      -      }
      -    },
      -    "required": [
      -      "title"
      -    ],
      -    "type": "object"
      -  }
      -]New value: +[
      +  {
      +    "additionalProperties": false,
      +    "description": "Text block widget (notes, headings, commentary). No queries or period — does not inherit dashboard metric/groupBy.",
      +    "properties": {
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "textContent": {
      +        "description": "Markdown or plain text body. Stored as `{ type: \"text\", textContent }` — same as the UI text widget.",
      +        "type": "string"
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "text",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "type",
      +      "textContent",
      +      "title"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "additionalProperties": false,
      +    "properties": {
      +      "aggBy": {
      +        "default": "Month",
      +        "description": "Time grain for the series: Hour, Day, Week, Month, or Period (default Month).",
      +        "enum": [
      +          "Hour",
      +          "Day",
      +          "Week",
      +          "Month",
      +          "Period"
      +        ],
      +        "type": "string"
      +      },
      +      "compare": {
      +        "additionalProperties": false,
      +        "description": "Add a comparison period to show cost evolution side-by-side. Omit `from`/`to` to compare against the preceding period automatically; set `chartType` to choose how it renders.",
      +        "properties": {
      +          "chartType": {
      +            "default": "WATERFALL",
      +            "description": "How the comparison renders: WATERFALL (default, contribution to change), TABLE (before/after rows), or KPI_BREAKDOWN (per-group KPI cards). Note KPI_BREAKDOWN and TABLE widgets cannot be exported as PNG via get_widget_png.",
      +            "enum": [
      +              "WATERFALL",
      +              "TABLE",
      +              "KPI_BREAKDOWN"
      +            ],
      +            "type": "string"
      +          },
      +          "enabled": {
      +            "default": true,
      +            "description": "Defaults to true — supplying `compare` at all turns the comparison on. Pass false to keep the block while disabling it (useful when echoing back a payload from `get`).",
      +            "type": "boolean"
      +          },
      +          "from": {
      +            "description": "Comparison period start date. Omit (together with `to`) to compare against the preceding period, derived from the main period.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          },
      +          "to": {
      +            "description": "Comparison period end date. Required together with `from`; omit both to auto-derive.",
      +            "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +            "type": "string"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "datePreset": {
      +        "anyOf": [
      +          {
      +            "enum": [
      +              "TRAILING_90_DAYS",
      +              "TRAILING_30_DAYS",
      +              "TRAILING_45_DAYS",
      +              "TRAILING_7_DAYS",
      +              "TRAILING_3_DAYS",
      +              "TRAILING_14_WEEKS",
      +              "MTD",
      +              "QTD",
      +              "YTD",
      +              "LAST_WEEK",
      +              "LAST_MONTH",
      +              "LAST_6_MONTHS",
      +              "LAST_12_MONTHS",
      +              "LAST_4_YEARS",
      +              "LAST_3_MONTHS",
      +              "LAST_INVOICE_MONTH"
      +            ],
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Widget-level date preset override. Omit to inherit dashboardContext.datePreset or startDate/endDate; use only when this widget differs from the dashboard period."
      +      },
      +      "description": {
      +        "default": "",
      +        "type": "string"
      +      },
      +      "displayOptions": {
      +        "description": "TABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision. get_skill dashboards.",
      +        "properties": {
      +          "hideEmptyRows": {
      +            "description": "Hide rows with abs displayed sum < 0.01",
      +            "type": "boolean"
      +          },
      +          "precision": {
      +            "description": "Fraction digits 0–6",
      +            "maximum": 6,
      +            "minimum": 0,
      +            "type": "integer"
      +          },
      +          "showTotal": {
      +            "description": "Show Total column",
      +            "type": "boolean"
      +          },
      +          "sort": {
      +            "properties": {
      +              "by": {
      +                "description": "total | cost | groupBy | query letter (a)",
      +                "minLength": 1,
      +                "type": "string"
      +              },
      +              "direction": {
      +                "default": "DESC",
      +                "description": "ASC | DESC (default DESC)",
      +                "enum": [
      +                  "ASC",
      +                  "DESC"
      +                ],
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "by"
      +            ],
      +            "type": "object"
      +          },
      +          "topN": {
      +            "description": "Ranked rows 1–100 after hide-empty + sort. Omit limit.",
      +            "maximum": 100,
      +            "minimum": 1,
      +            "type": "integer"
      +          }
      +        },
      +        "type": "object"
      +      },
      +      "extendDashboardConditions": {
      +        "default": true,
      +        "description": "Whether this widget AND-merges the dashboard's `context.conditionsCel` with its own `filterCel`. Defaults to true — omit to inherit the dashboard filter. Set false only when the widget must ignore dashboard-wide conditions.",
      +        "type": "boolean"
      +      },
      +      "from": {
      +        "description": "Widget-level date override (inclusive), e.g. '2025-01-01'. Omit when the widget uses the dashboard context period.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "h": {
      +        "description": "Grid height in rows. When provided, the widget keeps this exact height instead of the auto-computed default. Obtain the value from the `h` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 9007199254740991,
      +        "type": "integer"
      +      },
      +      "limit": {
      +        "description": "Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups.",
      +        "maximum": 1000,
      +        "minimum": 1,
      +        "type": "integer"
      +      },
      +      "queries": {
      +        "description": "Same series objects as the `query` tool `queries` array (cost / metric / usage / externalMetric / formula / budget). Each requires `type` (never omit) and a `name` (prefer short ids like a/b/c); put human labels in `alias`. On dashboard chart widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `dashboardContext`. Call get_skill skillId: \"dashboards\" for examples.",
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "scopeId": {
      +        "anyOf": [
      +          {
      +            "type": "string"
      +          },
      +          {
      +            "type": "null"
      +          }
      +        ],
      +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
      +      },
      +      "title": {
      +        "type": "string"
      +      },
      +      "to": {
      +        "description": "Widget-level end date override (inclusive). Required together with `from` only when overriding the dashboard period; omit when inheriting context.",
      +        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      +        "type": "string"
      +      },
      +      "type": {
      +        "const": "chart",
      +        "default": "chart",
      +        "type": "string"
      +      },
      +      "w": {
      +        "description": "Grid width in columns (1–12). When provided, the widget keeps this exact width instead of the auto-computed default. Obtain the value from the `w` field returned by `get`.",
      +        "exclusiveMinimum": 0,
      +        "maximum": 12,
      +        "type": "integer"
      +      },
      +      "x": {
      +        "description": "Grid column index (0-based, 0 = left edge, max 11). When provided together with `y` (on a create_dashboard widget or an update_dashboard `add`) the widget is placed at the exact position instead of being auto-packed. Use `x`/`y` from `get` to copy a widget at its original position, or set manually (e.g. top-left: x=0 y=0, top-right of a half-width widget: x=6 y=0). Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing. When `w` is also set, `x + w` must be <= 12.",
      +        "maximum": 11,
      +        "minimum": 0,
      +        "type": "integer"
      +      },
      +      "y": {
      +        "description": "Grid row index (0-based, 0 = top). Rows grow downward; combine with `x` to pin a widget to a specific spot. Both `x` and `y` must be supplied together — if only one is given the position falls back to auto-packing.",
      +        "maximum": 9007199254740991,
      +        "minimum": 0,
      +        "type": "integer"
      +      }
      +    },
      +    "required": [
      +      "title"
      +    ],
      +    "type": "object"
      +  }
      +]
  11. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only cover the safety profile (readOnly=false, destructive=false, openWorld=false); the description adds substantial behavior beyond that: creator-only ownership/Admin grant, sharing flow, the deprecated `context` alias, auto-creation of missing tags, grid auto-packing, inheritance defaults, and the required URL return value.

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

Conciseness4/5

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

A long dense block, but every sentence carries a concrete rule and the core purpose is front-loaded in the first clause. The single-paragraph format is harder to scan than bullets would be for the volume of rules, but little is wasted.

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

Completeness5/5

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

For a complex nested tool with no output schema, the description covers the return value ('Returns a URL — you MUST include it in your response'), the widget model, inheritance semantics, and a worked example pointing to the skill. Nothing essential to correct invocation is missing.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already documents every parameter (baseline 3). The description still adds practical semantics not obvious from the schema: never send both context and dashboardContext, don't repeat matching date fields, hide formula inputs with visible:false, and budget groupBy explicitly does not inherit.

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?

Opens with a specific verb+resource ('Create a dashboard with one or more widgets') and immediately distinguishes itself from update_dashboard through sequencing guidance ('call set_object_permissions after create'). An agent can identify the tool's role without opening the schema.

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?

Explicit when-to-use rules throughout: call get_skill skillId 'dashboards' first, use set_object_permissions to share, prefer datePreset over dates, omit from/to when matching dashboardContext, use suggest_usage_metrics for usage metricId. Names concrete alternatives and conditions.

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