Skip to main content
Glama

Costory: Your Finops MCP

Server Details

Costory is the FinOps agent your team builds on. Claude plus a single provider's MCP works for one person and one cloud. It breaks when you add more providers, more people, and more tools to maintain.

  • Multiple providers: AWS, GCP, Azure, LLM APIs and data clouds normalized and allocated to teams and features in one model, including allocation from telemetry (Kubernetes, Datadog, dbt).

  • Multiple users: one hosted setup with OAuth, per-user access and enterprise SSO, instead of local credentials and prompts per person.

  • Maintained for you: tools, skills and connectors kept up to date by Costory, so reorgs and new services don't break your agent.

Your agent finds savings, explains every change in spend and issues recommendations that your coding agent can implement. It works in Claude, Cursor and any MCP client, plus Slack. Customers include Alan, Deezer, Delivery Hero, Voodoo and Pennylane.

Pricing: Starter from $300/month, flat: unlimited users and data sources, and a fair use that 80% of customers never outgrow. Nothing is ever cut off, and agents connected through the MCP use no AI credits. 30-day free trial.

Ownership verified
Status
Healthy
Uptime
99.0% over 69 days
OAuth
Works in Glama
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A4/5.0

Scored across 54 tools

Disambiguation4/5

Most tools have sharply distinct purposes, and the descriptions aggressively cross-reference siblings (preview_* vs create_*, draft lifecycle steps, search vs list_*). The weak spots are the polymorphic bare names — `get` covers six resource types, and `archive_object` vs the deprecated `archive_report` alias do the same job — plus `query`/`get_dashboard_widget_data`/`get_report_execution_widget` all return series data, which an agent could occasionally pick wrong.

Naming Consistency3/5

The dominant pattern is snake_case verb_noun (create_report, list_tags, preview_alert, update_virtual_dimension_draft), which is good. But several tools break it: bare `get`, `query`, `search`, the noun-only `virtual_dimension_overlap_matrix`, and synonym drift across verbs (find_cost_change_factors vs suggest_groupby vs list_*). Readable, but not a single predictable convention.

Tool Count2/5

54 tools is well past the point where a caller can hold the surface in mind, and it is inflated further by a deprecated alias (archive_report) and overlapping discovery tools. The domain is genuinely broad (costs, budgets, VDs, dashboards, reports, alerts, labels, docs, skills), so many tools earn their place, but this should have been consolidated or split into sub-servers.

Completeness4/5

Coverage is unusually deep: query/search/discovery, full CRUD-plus-preview-plus-publish lifecycles for reports, dashboards, alerts, events and virtual dimensions, plus permissions, tags, executions, and docs. The notable gap is budgets — they can be fetched, queried, and shared, but there is no create_budget/update_budget, so an agent cannot complete a budget workflow end to end.

Available Tools

54 tools
archive_objectA
Destructive
Inspect

Archive (soft-delete / hide) one saved Costory object so it no longer appears in lists or Explorer. This is the archive/remove tool — it does not create or edit objects. Use it when the user wants to archive, remove, or delete a report, cost alert, event, virtual dimension, or dashboard. Pass resourceKind and resourceId. report sets archivedAt (soft delete; no MCP restore). cost alert sets archivedAt (soft delete). event sets archivedAt (soft delete). virtual dimension sets deletedAt (soft delete). dashboard permanently deletes the dashboard row. A virtual-dimension draft stays on discard_virtual_dimension_draft. A tag stays on delete_tag. No bulk. Do not use this to hard-delete an alert. A budget alert is not its own kind: pass resourceKind costAlert and alertType budget or cost. alertType is the type field from list_alerts, and it is only valid when resourceKind is costAlert.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
alertTypeNo
resourceIdYes
resourceKindYes

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare destructiveHint=true/readOnlyHint=false generically; the description adds per-kind semantics that matter operationally – report/alert/event/virtualDimension perform soft deletes via archivedAt/deletedAt while dashboard 'permanently deletes the dashboard row'. It also discloses that no MCP restore exists, which is exactly the kind of irreversibility detail annotations cannot express.

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?

Front-loaded with the core definition and routing before the kind-specific lines. The line-by-line enumeration of archivedAt/deletedAt is slightly repetitive but each line carries distinct per-kind behavior, so it earns its space.

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 no-output-schema, 4-parameter object with a tricky dependent parameter (alertType), the description covers purpose, routing to alternatives, per-kind side effects, and the alertType coupling – everything an agent needs to call it correctly.

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 low (25%), so the description must compensate and largely does: it defines alertType as 'the type field from list_alerts' and constrains it to resourceKind=costAlert, and notes a budget alert isn't its own kind. resourceId itself gets no added meaning, so it falls just short of full compensation.

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

Purpose5/5

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

States a specific verb and resource ('Archive (soft-delete / hide) one saved Costory object') and immediately demarcates scope ('it does not create or edit objects'). The specific resourceKinds enumerated make it trivially distinguishable from siblings like archive_report and delete_tag.

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 ('archive, remove, or delete a report, cost alert, event, virtual dimension, or dashboard'), explicit exclusions ('Do not use this to hard-delete an alert', 'No bulk'), and named alternatives for the two lookalike cases (discard_virtual_dimension_draft, delete_tag). Nothing is left to inference.

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

archive_reportA
Destructive
Inspect

Use archive_object. Deprecated on 1 October 2026. Archive a report (soft delete; no MCP restore).

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
reportIdYesReport id to archive.

TDQS

A3.9/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true, readOnlyHint=false, and openWorldHint=false. The description adds genuinely non-redundant context: the deletion is a soft delete and there is no restore path via MCP, which materially changes how an agent should weigh the call.

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?

Three short, waste-free clauses covering redirect, deprecation date, and semantics. Slightly awkward ordering, since the redirect precedes the statement of what the tool does, but nothing is padded.

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

Completeness4/5

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

For a two-parameter mutation with full schema coverage, safety annotations, and no output schema, the description covers the essentials plus the undo limitation. Only missing nicety is explicit permission requirements for archiving a report.

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

Parameters3/5

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

Schema description coverage is 100% and both parameters (reportId, slug) are documented in-schema, including the auto-detect caveat for slug. The description adds no parameter-level detail, so the baseline of 3 applies.

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

Purpose4/5

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

States a specific verb and resource ('Archive a report') and names the replacement sibling archive_object, so the agent can distinguish it from the other 50+ tools. It is not a tautology, but the purpose sentence is pushed to third position behind the redirect and deprecation notice.

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

Usage Guidelines4/5

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

Explicitly routes the agent to archive_object and gives a concrete temporal condition ('Deprecated on 1 October 2026'), which effectively says when not to use this tool. No other exclusions or prerequisites are stated, but the alternative is unambiguous.

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

create_alertAInspect

Create a cost alert that monitors one or more queries and notifies when a condition fires. New alerts are creator-only (you get Admin). To share, call set_object_permissions with resourceKind "costAlert". Accepts the same query config as query (prefer datePreset over hand-computed from/to). scopeId is the same id as list_teams. It is stored on the alert and is not merged into the query filters. Omit it for no scope. The firing rule is a single condition boolean expression over the query names, e.g. a > 1000, rollingSum(a, 7, DAY) > 50000, or (a - timeShift(a, 1, DAY)) / timeShift(a, 1, DAY) > 0.2. Window math (rollingSum/weekToDateSum/monthToDateSum/timeShift) is evaluated daily in BigQuery, so you do NOT pick an evaluation period — instead set dedup to control re-notification frequency (CALENDAR once per WEEK/MONTH, or ROLLING once every N days). The period (datePreset or from/to) defines the preview/look-back window for the underlying queries. Use list_available_destinations for SLACK/TEAMS channel IDs. Optional tagIds: 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 alert untagged. Returns a URL that you MUST include in your response so the user can view/edit the alert. EXAMPLE: "Alert me on Slack if our production AWS spend exceeds $50k over any 7 days, at most once a week" → { name: "Prod AWS weekly alert", queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", filterCel: "cos_provider in ["AWS"] && cos_environment in ["prod"]" }], datePreset: "TRAILING_90_DAYS", condition: "rollingSum(a, 7, DAY) > 50000", dedup: { kind: "CALENDAR", calendarUnit: "WEEK" }, notificationChannel: "SLACK", slackChannelId: "C01ABC" }

NameRequiredDescriptionDefault
toNoExplicit window end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.
fromNoExplicit window start (YYYY-MM-DD). Use with to instead of datePreset.
nameYesDisplay name for the alert.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
aggByNoTime grain for the series: Hour, Day, Week, Month, or Period (default Month).Month
dedupYesDeduplication config controlling how often a still-firing group notifies. The window is per groupBy value; delivery stays one message listing newly eligible groups. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days.
limitNoMax groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups.
emailsNoEmail addresses (required if EMAIL)
tagIdsNo`list_tags` id or `{ name, color? }` (created if missing, default #6366F1). Omit and [] leave it untagged.
compareNoAdd 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.
queriesNoSame 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`.
scopeIdNoTeam scope id (list_teams). Stored on the alert, not merged into query filters. Omit for no scope.
conditionYesAlerts v3 firing rule: a single boolean expression over the query names (`name` field of each query). Supports arithmetic (+ - * /), comparisons (> >= < <= == !=), logical and/or/not, parentheses, and these window functions: rollingSum(a, N, UNIT) (trailing sum over the last N units, UNIT ∈ DAY|WEEK|MONTH, inclusive of today), weekToDateSum(a) (Monday-to-date), monthToDateSum(a) (1st-of-month-to-date), and timeShift(a, N, UNIT) (value shifted back N units; may wrap a window function). Examples: `a > 1000`, `rollingSum(a, 7, DAY) > 1000`, `(a - timeShift(a, 1, DAY)) / timeShift(a, 1, DAY) > 0.2`, `a > 10000 or rollingSum(a, 7, DAY) > 50000`.
datePresetNoOfficial date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to.
slackChannelIdNoSlack target id (required if SLACK): a channel id (C…) to post to a channel, or a Slack user id (U…) to deliver a direct message to that user. Use list_available_destinations to discover both channels and the signed-in user's DM.
teamsChannelIdNoTeams channel ID (required if TEAMS)
notificationChannelYesNotification channel

TDQS

A4.6/5.0
Behavior5/5

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

Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, openWorldHint=true), and the description adds substantial non-obvious behavior: new alerts are creator-only with implied Admin, tag side-effects (create-if-missing, default color), the scopeId-stored-but-not-merged quirk, daily BigQuery evaluation of window math, and the mandated URL in the response.

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?

Front-loaded purpose followed by dense, mostly non-redundant guidance plus a concrete end-to-end example. It is long but proportionate to a 17-parameter nested tool; a few passages (dedup, condition) restate schema text, which keeps it from a 5.

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 17-param tool with nested objects and no output schema, the description covers cross-parameter relationships, side effects, and even the return value (the URL to surface). Nothing an agent needs to call it correctly appears 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 baseline is 3. The description goes beyond the schema by giving worked condition expressions, explaining the dedup re-notification model relative to the evaluation window, and clarifying that scopeId is stored rather than merged into filters and that tagIds of `[]` vs omitted are equivalent.

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+scope: 'Create a cost alert that monitors one or more queries and notifies when a condition fires.' An agent can distinguish this from update_alert, list_alerts, and preview_alert without opening any schema.

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

Usage Guidelines4/5

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

Explicitly routes to siblings for sub-steps: set_object_permissions to share, list_available_destinations for SLACK/TEAMS IDs, list_tags for tag IDs, and the `query` tool config format. It clarifies the datePreset-vs-from/to preference and when to omit scopeId. It stops short of an explicit when-to-use-this-vs-update_alert/preview_alert statement, so a 4 rather than 5.

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

create_dashboardAInspect

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.

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.

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.

create_eventAInspect

Create a new event to annotate a cost change. Use this when the user wants to document why costs changed — e.g. a deployment, migration, pricing update, or business decision. Events are displayed on cost charts as annotations so the team can correlate cost movements with real-world changes. STRONGLY RECOMMENDED: provide a "widget" definition describing the chart this event explains — this creates a visual annotation tied directly to the relevant cost movement. Omit widget only for purely informational org-wide events. Optionally attach tags (string labels such as "migration" or "scaling") to the event — call list_tags to discover existing tag values in the org before inventing new ones. Optionally attach metadata key-value pairs (e.g. link to a PR, owner, external reference) — source is a column set by the server and should not be sent inside metadata. widget.scopeId is stored on the event (same id as list_teams). Omit it for no scope. null is the same as omit on create. EXAMPLE: "Log the Kubernetes migration we did last Tuesday" → { name: "Kubernetes cluster migration", date: "2026-03-18", description: "Migrated from k8s v1.27 to v1.30, caused temporary node scaling cost spike", tags: ["migration"], metadata: { link: "https://github.com/acme/infra/pull/42", owner: "platform-team" }, widget: { title: "K8s node cost", queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", filterCel: "cos_service_name in ["AmazonEC2"]" }], from: "2026-03-10", to: "2026-03-25", aggBy: "Day" } }

NameRequiredDescriptionDefault
dateYesEvent date (YYYY-MM-DD)
nameYesEvent name (min 5 characters)
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagsNoTags to attach to the event (e.g. 'migration', 'scaling'). Use list_tags to discover existing tag values.
labelsNoDeprecated alias for tags. Ignored when tags is sent.
widgetNoAnnotation chart for the event. Same shape as the `query` tool (`queries`, `datePreset` or `from`/`to`, `aggBy`, `compare`, `limit`, `scopeId`) plus `title` and optional `description`. Providing a widget creates a visual annotation so the team can see which cost movement the event documents. On create: STRONGLY RECOMMENDED; omit only for truly org-wide events with no cost chart. On update: omit to leave the chart unchanged. If sent, widget is a full replacement (title, queries, and datePreset or from/to required; scopeId alone is invalid). Pass widgetEventId when the event has multiple charts.
categoryNoDeprecated. If sent, merged into tags then discarded.
metadataNoOptional key-value metadata (e.g. link, owner, event). source is always set to api.
descriptionYesWhat happened and why it affects costs

TDQS

A4.5/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=false, openWorldHint=false, and destructiveHint=false, but the description adds substantial behavioral context: events appear as chart annotations, widget definitions create visual annotations, widget is a full replacement on update, source is server-set, deprecated aliases are ignored, and list_tags should be used before creating tags. No annotation contradiction.

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?

The description is long but well-structured and front-loads the purpose and primary usage guidance before parameter details and the example. The example is useful for a nested widget object, though some widget and metadata guidance is repeated from the schema.

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

Completeness4/5

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

For a complex create tool with nine parameters, nested widget objects, and no output schema, the description is thorough about creation semantics, annotation behavior, tag discovery, metadata handling, and example usage. It does not describe the return value, error behavior, or permission requirements, but those gaps are relatively minor given the schema coverage.

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 description coverage is 100%, so the baseline is 3. The description goes beyond the schema by emphasizing that widget is STRONGLY RECOMMENDED, explaining when to omit it, noting that null is equivalent to omit for scopeId on create, and providing a complete example invocation. Some of this overlaps with schema descriptions, but it meaningfully improves parameter understanding.

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

Purpose5/5

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

States a specific verb and resource: 'Create a new event to annotate a cost change.' It explains the event's role as a chart annotation, which distinguishes this create/annotation tool from list_events and update_event without opening either schema.

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

Usage Guidelines4/5

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

Gives clear when-to-use context ('when the user wants to document why costs changed') and instructions for the widget parameter, including when to omit it. It also points to list_tags before inventing new tag values. It does not explicitly say when to use update_event instead for existing events, so it falls short of full alternative routing.

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

create_reportAInspect

Create a report with shared reportContext and one or more widgets plus destinations. New reports 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: "reports" first — see skill for context-first workflow and DIGEST preview iteration. Put shared settings in reportContext (period required when query widgets are present: prefer datePreset; plus metricId, common groupBy, currency, optional conditionsCel / scopeId). Query widgets inherit by default and should only specify overrides — do not repeat from/to, datePreset, groupBy, metricId, or currency when they match reportContext. The legacy context alias is temporarily accepted but deprecated; never send both. Schedule modes: • NOW — create an on-demand report and immediately deliver it to every destination. DANGER ZONE: this sends real messages now. Summarize scope, schedule, and every destination, then ask the user to confirm before calling. • UNSCHEDULED — save an on-demand draft without delivery. • SCHEDULED — create a recurring report (DAILY / WEEKDAYS / WEEKLY / MONTHLY). DANGER ZONE: this authorizes future channel delivery. Summarize the recurring schedule and every destination, then ask the user to confirm before calling. Optional tagIds: 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 report untagged. Widget types: DASHBOARD_PDF, GRAPH_SNAPSHOT, TOP_FLOP, TEXT, and DIGEST. A DASHBOARD_PDF widget renders an existing dashboard as a PDF — pass { type: "DASHBOARD_PDF", dashboardId: "<id from search>" } (dashboardId required). TEXT widgets use { type: "TEXT", contentMarkdown } (not dashboard textContent). DIGEST hierarchy: reportContext.groupBy (root, preferred) + ordered additionalGroupBy (deeper levels); also supports thresholds. Per-widget override: set DIGEST useDashboardGroupBy: false to ignore reportContext.groupBy for that widget — the first additionalGroupBy item (or queries[0].groupBy) becomes the root; false requires at least one dimension. DIGEST accepts a per-widget queries[0].filterCel (CEL) — AND-combined with reportContext.conditionsCel by default (extendDashboardConditions defaults true), applied to both the comparison periods, and named by the AI summary. Use it for focused digests (e.g. Kubernetes only: cos_cluster_name != null) next to an unfiltered org-wide digest in the same report. DIGEST AI (opt-in, slower): display ("tree" default | "table" | "summary" for LLM executive narrative) and enableAiInvestigation (boolean, default false — per-node deep analysis, independent of display). DIGEST aggBy is Month or Week — never Period (Period is TOP_FLOP). Preview and create use the same reportContext + widget shape. For WEEKLY schedules, schedule.weekday is required (0 = Sunday … 6 = Saturday). Destinations: SLACK/TEAMS take channelId; EMAIL takes email (a single address, the literal ALL_ACTIVE_USERS to reach every active user, or destinations.email.self from list_available_destinations for "email me"). Returns report URL and nextRunAt; NOW also returns execution URLs and per-destination status. EXAMPLE monthly DIGEST: { schedule: { mode: "UNSCHEDULED" }, reportContext: { datePreset: "LAST_MONTH", groupBy: "cos_environment", metricId: "cost", currency: "USD" }, widgets: [{ type: "DIGEST", queries: [{ type: "cost", name: "a" }], aggBy: "Month", additionalGroupBy: ["cos_sub_account_id", "cos_service_name"], minAbsoluteDiff: 100, minRelativeDiff: 5, topLargestAbsoluteChange: 20, display: "summary", enableAiInvestigation: false }, { type: "DIGEST", title: "Kubernetes", queries: [{ type: "cost", name: "a", filterCel: "cos_cluster_name != null" }], aggBy: "Week" }], destinations: [{ destinationType: "SLACK", channelId: "C…" }] } EXAMPLE namespace-rooted DIGEST (overrides reportContext.groupBy for this widget only): { schedule: { mode: "UNSCHEDULED" }, reportContext: { datePreset: "LAST_MONTH", groupBy: "cos_environment", metricId: "cost", currency: "USD" }, widgets: [{ type: "DIGEST", title: "Kubernetes", useDashboardGroupBy: false, queries: [{ type: "cost", name: "a" }], aggBy: "Month", additionalGroupBy: ["cos_namespace_reallocated", "cos_workload_name"] }], destinations: [{ destinationType: "SLACK", channelId: "C…" }] } EXAMPLE GRAPH_SNAPSHOT + TOP_FLOP: { schedule: { mode: "SCHEDULED", period: "WEEKLY", weekday: 1, firstRunAt: "2026-08-04T10:00:00.000Z" }, reportContext: { metricId: "cost", currency: "USD", groupBy: "cos_service_name", datePreset: "LAST_WEEK" }, widgets: [{ type: "GRAPH_SNAPSHOT", title: "Cost by service — trailing weeks", queries: [{ type: "cost", name: "a", chartType: "LINE" }], datePreset: "TRAILING_14_WEEKS", aggBy: "Week" }, { type: "TOP_FLOP", title: "Last week movers by service", queries: [{ type: "cost", name: "a" }], aggBy: "Period", topN: 5, flopN: 5 }], destinations: [{ destinationType: "SLACK", channelId: "C…" }] }

NameRequiredDescriptionDefault
nameNoOptional; empty or omitted → server generates a name from content.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagIdsNoPass 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 report untagged.
contextNoDeprecated alias for `reportContext`; supported temporarily for backward compatibility. Do not send both fields.
widgetsYesOne or more report widgets (DIGEST / GRAPH_SNAPSHOT / TOP_FLOP / TEXT / DASHBOARD_PDF). Call get_skill skillId: "reports" for examples.
scheduleYesDelivery mode: NOW (sends immediately), UNSCHEDULED (draft), or SCHEDULED (recurring; WEEKLY requires `weekday`).
descriptionNoOptional longer description (default empty).
destinationsYesDelivery targets: `{ destinationType, channelId }` or `{ destinationType: "EMAIL", email }`. Resolve channels via `list_available_destinations`.
reportContextNoReport-level shared context. Put period (prefer datePreset), metricId, common groupBy, currency, optional conditionsCel / scopeId here — query widgets omit those fields to inherit. Call get_skill skillId: "reports" first.

TDQS

A4.9/5.0
Behavior5/5

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

The annotations say only that this writes (readOnlyHint false) to an open world without being destructive. The description adds what the annotations cannot: the report is creator-only immediately after creation, the NOW and SCHEDULED modes are flagged DANGER ZONE and demand a summarised confirmation before calling, the legacy `context` alias is deprecated, and the return payload is spelled out (URL and nextRunAt, plus execution URLs and per-destination status for NOW).

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?

The purpose and the safety warnings are front-loaded, and almost every sentence covers a distinct rule. It is long, however, and three full JSON examples plus repeated restatements of the DIGEST hierarchy and the deprecation notice cost some density.

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 9-parameter tool with polymorphic widgets, schedules and destinations and no output schema, the description supplies the confirmation requirements, the inheritance rules, the destination formats, the WEEKLY weekday constraint and worked examples. An agent would not need anything else in order to call this correctly.

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

Parameters5/5

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

Schema coverage is already 100%, so the baseline is 3, but the description carries inheritance semantics the schema only states piecemeal: widgets inherit from `reportContext` and should only carry overrides, and the description ties the period requirement to the presence of query widgets. It also resolves per-widget ambiguities, such as `useDashboardGroupBy: false` making the first `additionalGroupBy` item the root and requiring at least one dimension, and the DIGEST `aggBy` restriction to Week or Month.

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?

It opens with a specific verb and resource: 'Create a report with shared `reportContext` and one or more `widgets` plus destinations.' That is enough for an agent to distinguish this from update_report, preview_report_widget or run_report_now without opening a 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?

It names the alternatives and the conditions that select them throughout: call get_skill skillId 'reports' first, use set_object_permissions after create rather than sending PRIVATE/PUBLIC, resolve tags via list_tags, resolve channels via list_available_destinations. The NOW/UNSCHEDULED/SCHEDULED modes are each given an explicit use case.

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

create_virtual_dimension_draftAInspect

Create a new virtual dimension draft without publishing. virtualDimensionId in inputs equals id from list/get/search. Call get_skill with skillId: "virtual-dimensions" first — see skill for allocation shapes, CEL rules, and full workflow. For a new telemetry allocation, discover a live integration metric via list_metrics with includeExternal: true and a specific search term, then persist inline externalMetric { provider, integrationId, metricName, aggregator, groupByFields }. For BigQuery/S3, also set dateColumn and metricColumn from the returned schema (first DATE / first NUMERIC) and gapFillingMethod (default FORWARD_FILL). Catalog-complete providers (Tsuga, Datadog, CloudWatch, Amplitude, Google Cloud Monitoring) do not need those fields. Do not set datasource on new reallocations. bqName (BigQuery/CEL query field, e.g. Environment → virtual_environment) is set once from name at create and is immutable. Ordered rules use conditionCel + allocation — do not send rule id (generated on save) or values (derived). Do not include catch-all/leftover in rules — leftoverRule is auto-added. Rejects invalid payloads — nothing persisted unless validation passes. On success: virtualDimensionId, bqName, name, description, tags, values, rules with generated ids, leftoverRule, draftValidation: { ok: true }, draftPersisted: true. Use preview_virtual_dimension_draft next. Use returned bqName for groupBy/filterCel in query after publish. Does not publish or refresh BigQuery. Clerk MCP only. EXAMPLE: "Draft an Environment VDIM with a prod rule" → { name: "Environment", tagNames: ["finops"], rules: [{ name: "Production", conditionCel: "cos_environment in ["prod"]", allocation: { allocationType: "dimensionValue", dimensionValue: "prod" } }] }

NameRequiredDescriptionDefault
nameYesName for the new virtual dimension
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
rulesNoOrdered rules with conditionCel and allocation
tagNamesNoTag names to attach (created if missing)
descriptionNoOptional longer description (default empty).

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only indicate readOnlyHint false / destructiveHint false, so the description carries the burden and delivers extensively: 'Rejects invalid payloads — nothing persisted unless validation passes', success includes 'draftPersisted: true' and 'draftValidation: { ok: true }', rule ids are 'generated on save', leftoverRule is 'auto-added', and 'bqName … is immutable'. Side effects and validation behavior are fully disclosed.

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?

The prose is front-loaded with the core purpose, then organized into lifecycle guidance, allocation details, constraints, response shape, and an example before the schema. However, it is extremely dense and contains redundancy — the BigQuery/S3 dateColumn/metricColumn/gapFillingMethod requirement is stated twice ('For BigQuery/S3, also set…' and 'For BigQuery/S3, dateColumn, metricColumn, and gapFillingMethod are required…').

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?

Despite having no separate output schema, the description enumerates the full success response ('virtualDimensionId, bqName, name, description, tags, values, rules with generated ids, leftoverRule, draftValidation: { ok: true }, draftPersisted: true'), covers failure behavior, advanced allocation semantics, required prerequisite skill, following tool, and a worked example — complete for a tool with this much nested logic and many relevant siblings.

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

Parameters5/5

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

While the schema already covers all 5 parameters, the description adds substantial meaning beyond it: 'virtualDimensionId in inputs equals id from list/get/search', 'bqName … is set once from name at create', rules must not send 'id (generated on save) or values (derived)', the four allocation types are spelled out, and BigQuery/S3 requirements (dateColumn/metricColumn from list_metrics schema, default gapFillingMethod FORWARD_FILL) go far beyond the bare property definitions.

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?

Opening phrase 'Create a new virtual dimension draft without publishing' names a specific verb, resource, and lifecycle state, distinguishing it from the sibling publish_virtual_dimension_draft. The embedded EXAMPLE ('Draft an Environment VDIM with a prod rule') makes the intent unmistakable.

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?

Explicitly instructs prerequisites ('Call get_skill with skillId: "virtual-dimensions" first'), next steps ('Use preview_virtual_dimension_draft next'), and exclusions ('Do not set datasource on new reallocations', 'Do not include catch-all/leftover in rules', 'Does not publish or refresh BigQuery'). It also explains the relationship to query after publish ('Use returned bqName for groupBy/filterCel in query after publish').

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

delete_tagA
Destructive
Inspect

Delete an unused tag from the organization. Only tags with zero tagged resources can be deleted — call list_tags first to check usage counts. Returns an error if the tag is still in use. EXAMPLE: "Delete the obsolete 'v1' tag" (after list_tags confirmed 0 uses) → { tagId: "tag_old" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagIdYesID of the tag to delete

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already mark the operation as destructive (destructiveHint=true). The description adds valuable behavioral context beyond the annotations by specifying the zero-usage requirement, the error condition, and the need to check list_tags first. This clarifies the operational constraints without contradicting the annotations.

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?

The description is concise, with the main purpose in the first sentence and additional context in a second sentence. The example is helpful but slightly redundant, though it does not inflate the text excessively. Overall it is well-structured and front-loaded.

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

Completeness4/5

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

For a destructive delete operation with only two parameters and no output schema, the description covers the essential conditions, error behavior, and prerequisite. It does not mention authentication or success response details, but these are less critical given the annotations and the tool's simplicity.

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

Parameters3/5

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

The input schema covers both parameters (slug and tagId) with clear descriptions, achieving 100% schema description coverage. The description includes an example that illustrates tagId usage but does not add semantic meaning beyond what the schema provides, so the baseline score of 3 is appropriate.

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?

The description uses a specific verb ('Delete') and resource ('tag') with organizational scope, clearly distinguishing this tool from sibling tools like list_tags or update_dashboard. It explicitly states the purpose and the key constraint of deleting only unused tags.

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?

The description gives explicit usage guidance: call list_tags first to check usage counts, and notes that an error occurs if the tag is still in use. This tells the agent when to use the tool and what prerequisite steps are needed, effectively differentiating it from non-delete alternatives.

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

discard_virtual_dimension_draftA
Destructive
Inspect

Discard the pending draft for an existing virtual dimension without publishing. virtualDimensionId in inputs equals id from list/get/search. Use when a draft is corrupt/unreadable or you want to abandon in-progress edits. On success returns draftDiscarded: true. Returns an error when no pending draft exists. Does not delete published virtual dimensions. Clerk MCP only. EXAMPLE: "Discard corrupt Environment VDIM draft" → { virtualDimensionId: "<virtualDimensionId from list/get>" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
virtualDimensionIdYesVirtual dimension id (stable public identifier)

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true, but the description adds valuable context: it does not delete published virtual dimensions, returns 'draftDiscarded: true' on success, and errors when no draft exists. This clarifies the exact scope of destruction and the outcome, exceeding what annotations alone provide.

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?

The description is well-structured and front-loaded with the main purpose. It includes necessary details (return value, error case, non-destructive scope, example) without fluff. It is slightly longer than the bare minimum but every sentence adds value, making it appropriately sized for a tool with multiple behavioral caveats.

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

Completeness4/5

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

Given the tool's moderate complexity, the description covers the key aspects: what it does, when to use it, parameter mapping, success/error behavior, and scope. There is no output schema, but the return value is mentioned. The description is sufficient for an agent to invoke the tool correctly.

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?

The schema already provides descriptions for both parameters at 100% coverage, but the description adds crucial mapping: 'virtualDimensionId in inputs equals id from list/get/search.' The example also demonstrates how to fill the parameter, which is helpful beyond the schema's minLength constraint.

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?

The description clearly states the action: 'Discard the pending draft for an existing virtual dimension without publishing.' The verb 'discard' and specific resource 'pending draft' are unambiguous, and 'without publishing' distinguishes it from the publish tool. This completely separates it from sibling tools like create/update/publish.

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

Usage Guidelines4/5

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

The description provides explicit when-to-use guidance: 'Use when a draft is corrupt/unreadable or you want to abandon in-progress edits.' It also notes the error condition when no draft exists. However, it doesn't explicitly compare with update_virtual_dimension_draft or other alternatives, though the 'without publishing' phrase implies a contrast.

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

find_cost_change_factorsA
Read-only
Inspect

Find which dimension values drove a cost change between two periods. This is a before/after analysis — compare is required ({} auto-derives the previous window, same as query). Prefer suggest_groupby / search / get_context first, then pass 2–4 columns (max 8). Do not invent columns. filterCel omitted or "" is unfiltered (not AWS-only). nestingEdges: a child's spend sits inside the parent — do not sum a contributor with its ancestors or descendants; independent contributors may be summed. Prefer omitting aggregationMethod (SUM). EXAMPLES: • "Why did last month's EC2 cost change?" → { datePreset: "LAST_MONTH", compare: {}, filterCel: "cos_service_name in ["AmazonEC2"]", columns: ["cos_region", "cos_usage_type"] } • "What drove the RDS jump in May?" → { from: "2026-05-01", to: "2026-05-31", compare: { from: "2026-04-01", to: "2026-04-30" }, filterCel: "cos_provider in ["AWS"] && cos_service_name in ["AmazonRDS"]", columns: ["cos_sub_account_id", { column: "cos_charge_description", contains: "IOPS" }] }

NameRequiredDescriptionDefault
toNoCurrent period end (YYYY-MM-DD), inclusive. Omit when using datePreset.
fromNoCurrent period start (YYYY-MM-DD). Omit when using datePreset.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
columnsYes2–4 dimensions to investigate (max 8). Prefer suggest_groupby / search / get_context names (e.g. "cos_service_name"), or { column, contains } for a single-token substring (e.g. { column: "cos_charge_description", contains: "GPU" }). Do not invent columns.
compareYesPrevious period. `{}` auto-derives from the current window (same helper as query). `{ from, to }` pins it.
filterCelNoOptional CEL scope. Omit or "" for unfiltered (Billy where_clause TRUE). That is not an AWS-only filter even though columns_where_clause falls back to ["cos_provider"].
datePresetNo
aggregationMethodNoPrefer omitting this (SUM). AVG is rarely right for cost.

TDQS

A5/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true, so the safety profile is known Stephen. The description adds substantial behavioral detail beyond annotations: compare is required, `{}` auto-derives the previous window, filterCel omitted or "" is unfiltered (not AWS-only), and nestingEdges warns against summing hierarchical contributors. This addresses a subtle and likely accidental misuse (double-counting) that the schema would not reveal. No contradiction with annotations.

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

Conciseness5/5

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

The description is dense but every sentence serves a distinct purpose: purpose, prerequisite, constraint, a behavioral warning, a default preference, and two examples. There is no redundancy or filler. The structure naturally front-loads the core purpose and then progressively adds nuance, making it easy for an agent to scan.

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?

With 8 parameters Prix, no output schema, and a non-trivial analysis workflow, the description covers everything an agent needs to invoke it correctly: required fields, ordering of discovery calls, column selection rules, filter semantics, aggregation defaults, and sample invocations. It even includes a hierarchical aggregation caveat that would otherwise be an easy to make error. The only thing missing is an explicit return format, but given the complexity handled and the annotations covering safety, this is complete enough.

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

Parameters5/5

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

Schema coverage is ~88%, but the description goes beyond the schema to explain critical semantics: compare's `{}` shorthand, filterCel's unfiltered default, aggregationMethod's preference to omit, and the recommended 2–4 column range (with max 8). The examples demonstrate the exact structure for columns, including the { column, contains } object form. This is high-value practical context that the schema alone does not provide.

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?

The opening sentence states a specific verb and resource: 'Find which dimension values drove a cost change between two periods.' This clearly distinguishes the tool from siblings like query (raw data) or suggest_groupby (suggest dimensions), and it explicitly frames the tool as a before/after analysis. The name and description are aligned, and the purpose is immediately actionable.

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?

The description gives explicit usage direction: 'Prefer suggest_groupby / search / get_context first, then pass 2–4 columns (max 8).' It tells the agent the prerequisite discovery tools Series and the recommended column count. It also provides a clear exclusion ('Do not invent columns') and clarifies filterCel semantics. The two concrete examples further illustrate both datePreset and from/to usage, leaving little ambiguity about when to call this tool.

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

getA
Read-only
Inspect

Fetch a V2 dashboard, budget, cost alert, report, virtual dimension, or BigQuery job by ID. Response includes a type discriminator (dashboard | budget | costAlert | report | virtualDimension | bigquery_job) — branch on it.

BigQuery jobs: pass id <project>:<location>.<job_id> (auto-detected from that shape, or set type: "bigquery_job"). Location is case-insensitive (EU and eu are the same). Loaded with the free Jobs API (jobs.get) — user_email, referenced tables, slot/bytes metrics, query_text, and performance_insights — plus stages and children when it is a script parent. Each stage has its name, slotMs, shuffle bytes, and the SQL clause (FROM / JOIN / WHERE / GROUP BY) that places it in query_text. Stages are sorted by slotMs descending. Timing histograms and column lists are omitted. The first fetch is cached in Postgres (a finished job never changes); the second call is a cache hit. Use it to investigate a BigQuery cost line's underlying query.

Dashboard / budget / cost alert / report / virtual dimension lookups:

Budgets: pass the parent budget id (from search) or a budget version id; response includes budgetVersionId for query, plus costMetricId, currency, virtualDimension (id, name, bqName, values), excludedValues, lines, includedVirtualDimensionValues, filterCelRestrictToIncludedLines, and filterCelExcludeExcludedVirtualDimensionValues for aligning query cost with budget. howToQueryAlignedCost gives concrete example payloads.

Cost alerts: pass the alert id (from search or list_alerts); response includes alert configuration plus firingHistory (every stored firing day and group values that fired). The payload includes scopeId, the saved team scope. The returned queries are the stored internal shape — read-only, and they do not contain that scope filter. To change the series with update_alert, write a fresh queries array with filterCel exactly as for create_alert; do not echo these back.

Reports: config in words plus run-health (status, nextRunDate, lastRunHealth, widgets array, recent per-destination delivery with executionIds). Read-only. To inspect a specific delivery's content, call get_report_execution (then get_report_execution_widget for drill-down).

Virtual dimensions: id / virtualDimensionId (same), hasPendingDraft, immutable bqName (BigQuery/CEL field for groupBy/filterCel — never derive from display name); published and optional draft (name, description, tags, computeStatus, values, rules, leftoverRule; draft may include draftValidation); dependencies. values is derived — output only. leftoverRule is separate from rules — do not put it in the rules array or pass it to update. For updates, copy rules from draft if pending else published, project each rule to { id, name, conditionCel, allocation } (omit position, isLeftovers, and any leftover/catch-all rule), and pass that full rules array to update_virtual_dimension_draft. Call get_skill with skillId: "virtual-dimensions" for allocation shapes and workflow.

Dashboards: call get_skill with skillId: "dashboards" before create/update. Chart widgets include x/y/w/h and resolved queryConfig; text widgets have type: "text" and textContent. After fetch, use get_dashboard_widget_data / get_dashboard_widget_image, or update_dashboard to mutate.

Use "search" (or list tools) first to discover IDs. EXAMPLE: "Open the Kubernetes dashboard" (after search returned its ID) → { id: "clx9abc123" }

NameRequiredDescriptionDefault
idYesID of a V2 dashboard, budget, cost alert, report, virtual dimension, or BigQuery job (from search / list tools). For budgets, pass parent budget id or budget version id. For BigQuery jobs, pass `<project>:<location>.<job_id>` — location is case-insensitive. Response includes a `type` discriminator: dashboard | budget | costAlert | report | virtualDimension | bigquery_job.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
typeNoRestrict the lookup to one resource type. Omit to try every type; a BigQuery job id is also auto-detected from its `<project>:<location>.<job_id>` shape.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations declare a safe read (readOnlyHint=true, destructiveHint=false, openWorldHint=false), and the description adds substantial behavior beyond that: Postgres caching with a guaranteed second-call cache hit for BigQuery jobs, what is deliberately omitted (timing histograms, column lists), that returned `queries` are a read-only internal shape lacking the scope filter and must not be echoed back, and that `values` on virtual dimensions is derived/output-only. This is unusually rich disclosure for a read tool.

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?

Front-loaded with the discriminator and ID-discovery guidance, then cleanly partitioned by resource type, so an agent can jump to the relevant paragraph. It is nevertheless very long and enumerates return payload fields (costMetricId, filterCelRestrictToIncludedLines, etc.) that read as spec-dump; with no output schema most of that detail earns its place, but the volume is close to the limit of what a selector can absorb.

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?

No output schema exists, so the description carries the full burden of return-value semantics, and it does: per-type payload contents, the `type` discriminator, BigQuery stage/children behavior, and the alert `queries` shape. For a six-way polymorphic getter sitting among dozens of get_/search/list siblings, nothing an agent needs to invoke or interpret this correctly 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 description coverage is 100%, so the baseline is 3 and much here (BigQuery id shape, budget parent/version id, the type enum) is already in the schema. The description still adds operating meaning: BigQuery ids are auto-detected from their shape and location is case-insensitive, omitting `type` tries every type, and slug auto-detection fails for multi-org accounts. That is above the baseline, though not a full compensation case.

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 list ('Fetch a V2 dashboard, budget, cost alert, report, virtual dimension, or BigQuery job by ID') and immediately explains the `type` discriminator used to branch. Despite the generic name 'get', an agent can distinguish this polymorphic fetcher from get_report_execution, get_dashboard_widget_data, and the search/list siblings without opening any 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?

Explicitly routes the agent: 'Use "search" (or list tools) first to discover IDs', plus named hand-offs to get_report_execution for delivery content, get_dashboard_widget_data/get_dashboard_widget_image after a dashboard fetch, get_skill with skillId 'dashboards'/'virtual-dimensions' before mutations, and update_alert for alert rewrites. Both the when-to-use and the when-to-use-something-else conditions are stated.

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

get_contextA
Read-only
Inspect

Get workspace context: popular groupBy dimensions, recent dashboards, and connected external-metric integrations (e.g. Tsuga, BigQuery, Datadog, CloudWatch, Google Cloud Monitoring). Call this FIRST at the start of every conversation. Each dimension has name (CEL/groupBy field: cos_* native or virtual_* bqName) and label (pretty display name) — use label only in user-facing text; use name for filterCel/groupBy (never the label). To discover CEL field names and dimension values for filterCel/groupBy, use search instead — pass type: ["dimensions"] with an empty query to list all dimensions, or a keyword (e.g. "account", "environment") to narrow results. For billing keys that are not dimensions yet, call list_dimension_candidates; import or normalize them with publish_label_dimensions (operations merge onto existing labels — do not resend the full list; preview dryRun: true, then call once with dryRun: false and confirm: true; about 10 minutes to show in Explorer). When externalMetricIntegrations is non-empty, call list_metrics with includeExternal: true and a specific search term to browse matching live integration metrics. For new virtual-dimension telemetry (split-by-usage-metric) reallocations, use that same includeExternal search and persist an inline externalMetric (do not set datasource). For BigQuery or S3, pick dateColumn / metricColumn from the returned schema (DATE / NUMERIC) and set gapFillingMethod (default FORWARD_FILL). Custom virtual dimensions: use immutable bqName from list/get VDIM tools as groupBy / filterCel (not display name). Poll computeStatus until COMPLETED after publish. EXAMPLE: "What cloud cost data do you have available?" → {}

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already establish readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds genuinely useful behavioral context beyond that — the name-vs-label distinction, the 10-minute propagation delay for published dimensions, the dryRun/confirm publish flow, and polling computeStatus until COMPLETED. Much of this, however, describes side effects of other tools rather than this read call, so it is context rather than disclosure about get_context itself.

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

Conciseness2/5

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

The purpose and the 'call first' directive are correctly front-loaded, but the body sprawls into operating instructions for at least five other tools (search, list_dimension_candidates, publish_label_dimensions, list_metrics, virtual-dimension publishing) plus column/gap-filling guidance. Those sentences do not earn their place in this tool's definition and bury the actual contract.

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

Completeness4/5

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

There is no output schema, so the description must describe returns — and it does, naming dimensions with name/label, recent dashboards, externalMetricIntegrations, and a per-integration schema with DATE/NUMERIC columns. For a single-optional-param read tool the core is complete, though the parameter's auto-detection behavior is left entirely to the schema.

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

Parameters3/5

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

There is one optional parameter (slug) with 100% schema description coverage, so the schema already carries the meaning, including the multi-org failure mode. The description adds nothing about slug, which is acceptable under the baseline-3 rule but earns no uplift.

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

Purpose5/5

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

States a specific verb and resource with concrete scope: 'Get workspace context: popular groupBy dimensions, recent dashboards, and connected external-metric integrations (e.g. Tsuga, BigQuery, Datadog, CloudWatch).' An agent can immediately distinguish this from siblings like search, list_metrics, or list_dimension_candidates because the description names those as separate destinations.

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?

Explicitly says 'Call this FIRST at the start of every conversation,' which is an unambiguous trigger. It also routes the agent onward with conditions: use search with type:["dimensions"] for CEL field discovery, list_dimension_candidates for unmodeled billing keys, and list_metrics with includeExternal:true when externalMetricIntegrations is non-empty.

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

get_dashboard_widget_dataA
Read-only
Inspect

Run a saved widget by id and return its cost data — no need to re-specify the query config. Loads the widget's stored request, applies the dashboard's conditionsCel to cost and usage series unless extendDashboardConditions is false on the widget or on that series, and returns the same series/timeSeries or comparison breakdown as the query tool (hidden series with visible: false are omitted from display). Use after get to get data for a specific widgetId. EXAMPLE: "Show me data for the EC2 widget" (after get returned widgetId "wid_123") → { dashboardId: "clx9abc", widgetId: "wid_123" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
widgetIdYesWidget id (from get or get_context widgets list).
dashboardIdYesDashboardV2 id.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already cover read-only, non-destructive behavior. The description adds meaningful context beyond annotations: conditionsCel application logic, the extendDashboardConditions override, and that hidden series with visible: false are omitted from display.

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?

Front-loads the core action and scope, followed by behavioral detail and an example. Dense but appropriate for the tool's nuance; every sentence earns its place.

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

Completeness4/5

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

Covers purpose, preconditions, the conditionsCel behavior, and a concrete example. No output schema exists, so it notes what is returned (series/timeSeries or comparison breakdown). Complete enough for correct invocation.

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

Parameters3/5

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

Schema coverage is 100%, so the baseline is 3. The description references widgetId and dashboardId in the example, but adds no semantics beyond what the schema descriptions already provide for slug, widgetId, and dashboardId.

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

Purpose5/5

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

States a specific verb+resource: 'Run a saved widget by id and return its cost data.' Clearly distinguishes itself from the query tool and the sibling get by explaining that no query config re-specification is needed.

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

Usage Guidelines4/5

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

Explicitly says 'Use after get to get data for a specific widgetId,' and provides an example workflow. It does not name alternatives or exclusions (e.g., when to use query directly instead), so not a full 5.

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

get_dashboard_widget_imageAInspect

Render a saved widget as a PNG chart, upload to GCS, and optionally return the binary image inline. Use when the user wants to see a visual snapshot or embed an image in a chat reply. Applies the same dashboard conditionsCel merge as get_dashboard_widget_data. Returns imageUrl (GCS PNG). By default also returns the PNG bytes as a base64 image block (set includeBinaryImage: false to skip binary if the payload is too large). No separate share URL — the widget already lives on the dashboard; link to the dashboard if the user wants the live chart. Does NOT work for text or table-only widgets (returns UNSUPPORTED_WIDGET). EXAMPLE: "Share my EC2 cost widget as an image" (after get returned widgetId "wid_123") → { dashboardId: "clx9abc", widgetId: "wid_123" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
widgetIdYesWidget id (from get).
dashboardIdYesDashboardV2 id.
includeBinaryImageNoIf true (default), the response includes a base64-encoded PNG image block in addition to the share/image URLs. Set to false to receive URLs only (smaller payload for clients that don't display inline images).

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the annotations, the description discloses the GCS upload side effect, the default inclusion of base64 PNG bytes, the option to skip binary for large payloads, the condition merge behavior, and the UNSUPPORTED_WIDGET failure case. This is rich behavioral context that annotations alone don't provide. The readOnlyHint=false annotation aligns with the stated upload side effect, showing no contradiction.

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

Conciseness5/5

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

The description is appropriately sized for the tool's complexity. Every sentence contributes meaningful information: purpose, when to use, condition merge, return format, binary option, no-share-URL note, unsupported types, and a working example. Despite its length, it remains structured and front-loaded, with the core action stated first.

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?

With no output schema, the description compensates by stating the return values (imageUrl, base64 image block). It also covers failure modes, parameter interplay, and usage context. The example provides a complete scenario from widgetId to call, making the tool's behavior fully understandable for an agent.

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 baseline is 3. The description adds value by explaining the purpose of includeBinaryImage (skip binary for large payloads), clarifying widgetId comes from a get call, and providing a concrete example with parameter values. However, the schema already thoroughly documents each parameter, so the description doesn't need to compensate heavily.

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?

The description opens with a specific verb and resource: 'Render a saved widget as a PNG chart, upload to GCS, and optionally return the binary image inline.' It clearly distinguishes from sibling tools like get_dashboard_widget_data by focusing on the visual image output rather than data.

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?

Explicitly states when to use: 'Use when the user wants to see a visual snapshot or embed an image in a chat reply.' It also provides an exclusion ('Does NOT work for text or table-only widgets') and suggests an alternative (link to the dashboard for the live chart), making the usage guidance very actionable.

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

get_documentation_pageA
Read-only
Inspect

Retrieve the full content of a specific Costory documentation page by its public docs URL or page path. Use this after search_documentation returns results. Response starts with Url: https://docs.costory.io/.... When citing this page in chat, use that exact Url: as the markdown href — do not convert to a relative app path. EXAMPLE: "Show me the full page about cost explorer" → { page: "https://docs.costory.io/features/cost-explorer" }

NameRequiredDescriptionDefault
pageYesDocumentation page URL or path from search results (e.g. 'https://docs.costory.io/get-started/welcome' or 'features/cost-explorer')

TDQS

A4.9/5.0
Behavior5/5

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

Despite readOnlyHint=true in annotations, the description adds valuable behavioral context: the response format ('Response starts with `Url: ...`') and a specific citation instruction using that exact URL as markdown href. This goes beyond the annotation safety profile.

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

Conciseness5/5

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

The description is two concise sentences plus a formatted example. Every sentence earns its place: first states the purpose, second gives usage sequence and response details, then a labeled example. No redundancy.

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 simple read tool with one parameter and no output schema, the description covers all necessary aspects: what it does, when to use it, what the response looks like, and how to handle the response correctly. The example completes the context.

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 parameter is fully documented. The description reinforces meaning with a concrete example ('Show me the full page about cost explorer' → { page: ... }), adding usage context beyond the schema but not new parameter semantics.

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?

The description specifies a clear verb ('Retrieve'), resource ('full content of a specific Costory documentation page'), and input method ('by its public docs URL or page path'). It distinguishes itself from sibling tool search_documentation by explicitly stating this is the follow-up retrieval step.

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?

Provides explicit usage context: 'Use this after search_documentation returns results.' This clearly indicates when to use the tool in relation to its sibling. The example also demonstrates a natural-language-to-parameter mapping.

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

get_object_permissionsA
Read-only
Inspect

List direct Reader/Editor/Admin grants on a dashboard, report, budget, or cost alert. One tool for all four kinds — pass resourceKind plus the object id from search / get / create. Returns grants (person, team, organization, or organization admins), the caller's effective role, and capabilities (canView / canEdit / canManage). canManage is true only for Admin. Budget alerts use resourceKind "budget" and the parent budget id. Templates have no ordinary grants. Read-only. EXAMPLES: • "Who can open the AWS dashboard?" → { resourceKind: "dashboard", resourceId: "clx9aws" } • "What access do I have on this report?" → { resourceKind: "report", resourceId: "clx9rpt" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
resourceIdYesObject id from search, get, or create.
resourceKindYesdashboard, report, budget, or costAlert. Budget alerts use the parent budget.

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces this with 'Read-only.' It adds meaningful behavioral context beyond annotations: the special case for budget alerts (use parent budget id), the fact that templates have no ordinary grants, and the semantic detail that canManage is true only for Admin. It does not describe pagination or error behavior, but for a read-only listing tool this is a minor gap.

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

Conciseness5/5

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

The description is compact and front-loaded: the core purpose appears in the first sentence, followed by return-value summary, special cases, and examples. Every sentence earns its place, and the examples are illustrative without being verbose.

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

Completeness4/5

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

For a read-only tool with full schema coverage and safety annotations, the description covers the essential invocation details: resource kinds, id provenance, return contents, and edge cases (budget alerts, templates). It lacks an output schema and does not describe pagination or error conditions, but those are not critical for a permissions-listing tool with this level of guidance.

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 description coverage is 100%, so the schema already documents all three parameters. The description adds value by explaining the relationship between resourceKind and resourceId ('pass resourceKind plus the object id from search / get / create'), clarifying the budget-alert special case, and providing concrete example values. It slightly exceeds the baseline 3 by enriching the enum semantics with usage context.

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?

The description states a specific verb ('List') and resource ('direct Reader/Editor/Admin grants on a dashboard, report, budget, or cost alert'), and explicitly distinguishes itself from the sibling set by covering all four resource kinds in one tool. It also clarifies what it returns (grants, caller's effective role, capabilities), making the tool's purpose unmistakable.

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?

The description gives explicit when-to-use guidance: 'One tool for all four kinds — pass resourceKind plus the object id from search / get / create.' It also provides exclusions ('Templates have no ordinary grants') and two concrete examples mapping natural-language questions to parameter values. This is strong routing guidance relative to siblings like set_object_permissions and get.

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

get_report_executionA
Read-only
Inspect

Get a condensed execution summary: status, destination, per-widget summaries, URLs. Omits raw time-series and full DIGEST trees. Widgets with drillDown can be expanded via get_report_execution_widget. For DIGEST, tell the user tree and node investigations are available. EXAMPLE: { executionId: "clx…" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
executionIdYesReport execution id.

TDQS

A4.7/5.0
Behavior5/5

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

Beyond the readOnlyHint/destructiveHint annotations, the description discloses the condensed behavior, the omission of raw time-series and full DIGEST trees, and the ability to expand widget drillDowns. This is exactly the kind of behavioral context that annotations alone do not provide.

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

Conciseness5/5

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

The description is compact and front-loaded, using three sentences plus a short example. Each sentence adds necessary information: what the tool returns, what it omits, and which sibling to use for more detail.

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?

Even without an output schema, the description enumerates the key returned fields (status, destination, per-widget summaries, URLs) and explicitly lists what is not included. This is sufficient for an agent to contract on a read-only summary call.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The description includes a concrete example with executionId, but it does not add significant meaning beyond what the schema already provides for either parameter.

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?

The description begins with a specific verb-resource pair ('Get a condensed execution summary') and lists concrete contents (status, destination, per-widget summaries, URLs). It also distinguishes itself from get_report_execution_widget by explicitly pointing to that sibling for expanded widget details.

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?

It clearly states what the tool omits (raw time-series, full DIGEST trees) and names get_report_execution_widget as the alternative for drillDown widgets. It also instructs the agent to mention DIGEST tree/node investigations are available, which is practical guidance for when to use this tool vs. other investigation paths.

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

get_report_execution_widgetA
Read-only
Inspect

Fetch an advanced view for one widget from get_report_execution. Pass widgetId and a view from its drillDown list. DIGEST tree returns the full formatted tree. Read-only; never starts new investigations. EXAMPLE: { executionId: "clx…", widgetId: "clx…", view: "tree" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
viewYes`series`, `tree`, or `investigations`.
widgetIdYesWidget id within that execution.
executionIdYesReport execution id.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description reinforces this with 'Read-only; never starts new investigations', adding the specific safeguard against triggering investigations. It also explains behavior for the `tree` view ('returns the full formatted tree'), which is context beyond the schema. Slightly more could be said about error cases or response format, but the annotation coverage lowers the burden.

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

Conciseness5/5

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

The description is two sentences plus an example, with zero filler. It front-loads the core purpose first, then provides invocation detail, and closes with a concrete example. Every sentence contributes information.

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

Completeness4/5

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

Given the tool has no output schema, the description covers the main usage flow and highlights a key behavior (full tree). The annotations cover safety. However, it does not describe what each enum value (`series`, `investigations`) returns or what happens if the provided view is not in the drillDown list. Still, the tool is relatively simple and the example helps fill gaps.

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 baseline is 3. The description adds meaningful value by explaining that `widgetId` and `view` come from a drillDown list and by specifying that the `tree` view returns a full formatted tree. This goes beyond the schema's bare enum descriptions. The example also shows real-world usage. No param-specific info is missing that would require a higher score.

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?

The description uses a specific verb ('Fetch') and clearly identifies the resource ('advanced view for one widget from get_report_execution'). It also distinguishes this from the sibling `get_report_execution` by focusing on drill-down views per widget. The example and mention of 'DIGEST tree' further clarify scope.

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

Usage Guidelines4/5

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

The description instructs the agent to 'Pass widgetId and a view from its drillDown list', giving explicit invocation guidance and a concrete example. It also notes the read-only nature, which prevents misuse. However, it does not explicitly contrast with alternatives like `preview_report_widget` or state when this is preferable to `get_report_execution`.

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

get_skillA
Read-only
Inspect

Load a workflow guide or any markdown file from the Costory skills GitHub repo. Returns markdown — call BEFORE starting the task, AFTER get_context. For build tasks, load a mechanics skill ("virtual-dimensions", "dashboards", "reports", "query"). When a curated recipe fits the user's outcome, call with skillId: "recipes", then load the matching card via its repo-relative .md path. Pass either: (1) a catalog skillId from list_skills (e.g. "virtual-dimensions", "dashboards", "reports", "query", "recipes"), or (2) a repo-relative .md path (e.g. a recipe card or skill reference under plugins/costory/skills/…). Paths must be relative, end in .md, and cannot traverse (..). Call this instead of guessing the tool sequence. EXAMPLES: • "Match outcome to a recipe card" → { skillId: "recipes" } • "Build an AWS overview dashboard" → { skillId: "dashboards" } • "Generate a report of monthly changes" → { skillId: "reports" } • "Create a custom cost axis" → { skillId: "virtual-dimensions" } • "Load the marketplace spend recipe" → { skillId: "plugins/costory/skills/recipes/marketplace-spend.md" } • "Load the dashboards interesting-overview reference" → { skillId: "plugins/costory/skills/dashboards/references/how-to-generate-interesting-dashboards.md" }

NameRequiredDescriptionDefault
skillIdYesCatalog skillId from list_skills (e.g. "dashboards", "reports", "recipes", "virtual-dimensions") OR a repo-relative .md path in the skills GitHub repo (e.g. "plugins/costory/skills/recipes/explain-period-change.md").

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already mark the tool as read-only and non-destructive. The description adds valuable behavioral context beyond the annotations: it returns markdown, must be called after get_context, and enforces path constraints ('relative, end in .md, and cannot traverse (..)'). It doesn't detail error behavior or auth requirements, but the safety profile is already covered by annotations.

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?

The description is well-structured, starting with purpose and timing, then offering examples. The numbered input options and bulleted examples improve scannability. It is somewhat repetitive (the same skill IDs appear in the prose and examples), but the extra length is justified by the tool's need to disambiguate between two input modes.

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

Completeness4/5

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

The description covers the core contextual needs: what the tool loads, the return format (markdown), sequencing relative to get_context, the two accepted input forms, and path constraints. For a read-only, single-parameter tool with no output schema, this is largely sufficient. It stops short of explaining failure modes or listing all possible skill IDs, but those are discoverable via list_skills.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds substantial meaning beyond the schema: it maps user intents to concrete skillId values, provides representative examples for both catalog IDs and repo-relative paths, and introduces path validation rules not present in the schema. This exceeds the baseline expected for fully covered schemas.

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?

The description clearly states the tool's action: 'Load a workflow guide or any markdown file from the Costory skills GitHub repo' and notes it 'Returns markdown.' It distinguishes itself from siblings by specifying its timing ('call BEFORE starting the task, AFTER get_context') and by saying 'Call this instead of guessing the tool sequence.'

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

Usage Guidelines4/5

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

It gives explicit guidance on when to use the tool: before starting a task, after get_context, and for build tasks it recommends specific mechanics skills. It also explains the recipe workflow and the two valid input forms. However, it doesn't explicitly state when not to use the tool versus alternatives like get_documentation_page, so it falls short of full exclusionary guidance.

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

list_alertsA
Read-only
Inspect

List all cost alerts and budget alerts for an organization with their current status. Cost alerts return their firing condition expression and dedup config (legacy alerts that predate conditions return their structured thresholds instead). Only call this when the user explicitly asks about their current cost monitors or alerts.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
typeNoFilter by alert typeall

TDQS

A4.2/5.0
Behavior4/5

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

The description adds valuable behavioral details beyond the readOnlyHint annotation: it explains that cost alerts return a firing condition expression and dedup config, while legacy alerts return thresholds. This clarifies response shape and handling of legacy data.

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

Conciseness5/5

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

Two concise sentences front-load the core purpose and then add necessary detail on return formats and usage constraint. No wasted words.

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

Completeness4/5

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

With no output schema, the description adequately conveys what the tool returns and differentiates legacy vs. current alerts. It could mention pagination or statuses, but the core context is well covered for a read-only list operation.

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

Parameters3/5

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

Schema coverage is 100% with both parameters (slug and type) already described in the schema. The description does not add further parameter semantics beyond what the schema provides, so baseline 3 is appropriate.

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?

The description clearly states the tool lists all cost and budget alerts for an organization with their current status, using a specific verb and resource. This distinguishes it from sibling tools like create_alert and preview_alert.

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

Usage Guidelines4/5

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

The description explicitly says 'Only call this when the user explicitly asks about their current cost monitors or alerts,' providing strong when-to-use guidance. It does not name alternatives explicitly, but the purpose is distinct from creating or previewing alerts.

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

list_available_destinationsAInspect

List every destination the organization can deliver reports or alerts to. Returns an object keyed by provider — destinations.slack.channels[] (channelId, name), destinations.teams.channels[] (channelId, name, teamName), and destinations.email (free-form; no list to enumerate). Each provider also carries a "connected" boolean so you can tell the user when an integration isn't set up. Call this before create_report or create_alert to resolve channelId values. For email, destinations.email.self (when present) is the signed-in user's own address — use it for "email me" instead of asking; destinations.email also accepts the literal ALL_ACTIVE_USERS to reach every active user. For any other explicit recipient, ask the user for the address. EXAMPLE: "Send me a weekly digest to #infra-costs" → { } (then pick channels[].channelId where name === "infra-costs")

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).

TDQS

A4.5/5.0
Behavior4/5

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

Annotations declare readOnlyHint=false, openWorldHint=true, destructiveHint=false. The description adds valuable behavioral context: it explains the return structure (object keyed by provider), the 'connected' boolean for telling users about unset integrations, and the special ALL_ACTIVE_USERS literal. It doesn't contradict annotations. It could mention that the tool may fail if the user belongs to multiple orgs and slug is omitted, but that's covered in the parameter description. The description goes beyond annotations by explaining the shape and semantics of the response.

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?

The description is well-structured and front-loaded with the core purpose. It includes a concrete example that illustrates the expected usage pattern. It's a bit long but every sentence earns its place: the return structure, the connected boolean, the email special cases, and the example all add necessary information. The example is particularly helpful for an agent to understand how to map user requests to channelId values.

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

Completeness4/5

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

For a list tool with one optional parameter and no output schema, the description is quite complete. It explains the return shape, the special email cases, and the relationship to sibling tools. It doesn't describe pagination or rate limits, but for a destination-listing tool that's likely not a concern. The description covers what an agent needs to know to call it correctly and interpret the response.

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 description coverage is 100%, so the schema already documents the slug parameter. The description adds context by explaining when slug matters (omit to auto-detect, fails if multiple orgs) and how it relates to the tool's behavior. It doesn't repeat the schema but adds a small amount of value. Baseline 3 is exceeded slightly because the description clarifies the failure mode and the auto-detection behavior.

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?

The description clearly states the tool's purpose: listing every destination the organization can deliver reports or alerts to. It specifies the resource (destinations) and the verb (list), and distinguishes it from sibling tools like create_report and create_alert by explicitly saying to call it before those to resolve channelId values. The example further clarifies the intended use.

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?

The description provides explicit when-to-use guidance: 'Call this before create_report or create_alert to resolve channelId values.' It also gives specific instructions for handling email recipients, including using destinations.email.self for 'email me' and asking the user for any other explicit recipient. This is clear, actionable guidance that an agent can follow without ambiguity.

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

list_dimension_candidatesA
Read-only
Inspect

List native billing label keys that can be imported as label dimensions (not virtual dimensions). Returns compact rows: key, ingested, imported, providers, numberValues, totalCostKeyPresent, proportionKeyPresent, costPercentageChange, topValues (top 8, Others omitted). Default drops keys already used in a published label (includeImported: true to keep them). Filter with query (substring on key / top values / providers), minCostPresent, sort (cost_desc default | cost_asc | coverage_desc | name_asc), limit (default 25, cap 50), offset. No suggestion engine — pick merges and value maps from topValues yourself. To add or change labels, call publish_label_dimensions once with an operations array (add / update / delete by id). The server merges them onto all existing label dimensions — do not resend the full list. Publishing takes about 10 minutes to show up in Explorer. Preview with dryRun: true (default), then call once with dryRun: false and confirm: true. Before rename or delete, call list_label_dimension_usages. EXAMPLE: "Which env-like billing keys are not dimensions yet?" → { query: "env" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
sortNoSort order (default cost_desc).cost_desc
limitNoMax rows to return (default 25, cap 50).
queryNoSubstring filter on key, top values, or providers.
offsetNoNumber of rows to skip.
minCostPresentNoMinimum totalCostKeyPresent.
includeImportedNoWhen false (default), drop keys already used in a published label.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnlyHint/openWorldHint/destructiveHint, and the description adds substantial context on top: default behavior drops already-published keys, the result row shape including 'topValues (top 8, Others omitted)', and the ~10-minute propagation delay before changes appear in Explorer. These are non-obvious operational traits not derivable from the schema.

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?

Front-loads purpose and return shape, then packs workflow guidance into tight sentences, ending with a concrete example call. It is dense and slightly redundant with schema defaults (limit, offset, default sort), which costs a point but the density is information-bearing rather than padding.

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?

Despite having no output schema, the description enumerates the returned columns and the topValues truncation rule, covers filtering/sorting/paging, and describes the full publish loop with preview and confirmation semantics. An agent can invoke this correctly and understand its downstream workflow without further context.

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 baseline is 3, but the description goes further by naming the sort enum values and explaining why includeImported matters (keeping keys already used in a published label) rather than merely restating the type. Some entries (limit cap 50, offset) duplicate the schema, which holds it below a 5.

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 precise verb+resource ('List native billing label keys that can be imported as label dimensions') and immediately disambiguates scope with '(not virtual dimensions)', separating it from list_virtual_dimensions and list_label_dimensions. It also enumerates the returned row fields, so the agent knows exactly what it gets.

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?

Explicitly routes to siblings and states the workflow: use publish_label_dimensions to add/change, call list_label_dimension_usages before rename/delete, and notes there is 'No suggestion engine — pick merges and value maps from topValues yourself.' It also gives the dryRun-then-commit sequence, which is exactly the guidance an agent needs.

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

list_eventsA
Read-only
Inspect

List events (deployments, business changes, provider updates) for an organization within a date range. Use this to correlate cost changes with real-world events. After query you may optionally call this to check if any events happened around that time. Returns events sorted by date descending, including metadata (e.g. link, owner, source) and widgetEvents (annotation chart ids/titles — use widgetEventId with update_event when an event has multiple charts). The payload includes scopeId. EXAMPLES: • "Did anything happen around that cost spike in mid-March?" → { from: "2026-03-10", to: "2026-03-20" } • "Show me all deployments in March" → { from: "2026-03-01", to: "2026-03-31", tags: ["deployment"] }

NameRequiredDescriptionDefault
toYesEnd date (YYYY-MM-DD)
fromYesStart date (YYYY-MM-DD)
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagsNoFilter by tag values

TDQS

A4/5.0
Behavior4/5

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

Annotations already cover the read-only safety profile, but the description adds real value by disclosing the return shape (sorted date-descending, metadata like link/owner/source, widgetEvents and scopeId). With no output schema this is the only place that return behavior is described, though pagination/limits are still unaddressed.

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?

Purpose is front-loaded and the examples are genuinely useful. The sentence 'After query you may optionally call this to check if any events happened around that time' is somewhat meandering and slightly redundant, but overall the text is efficient.

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

Completeness4/5

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

For a four-parameter read tool with no output schema, the description covers purpose, filtering, and return contents adequately. Minor gaps remain around pagination or result limits, but nothing essential for 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 baseline is 3, but the examples add meaning by showing how from/to bracket a spike window and how tags filter (e.g. ['deployment']), clarifying intended usage beyond the field descriptions.

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

Purpose4/5

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

States a specific verb (List) plus resource (events), clarifies the event types (deployments, business changes, provider updates), and scopes to an organization within a date range. It does not explicitly distinguish itself from sibling list/create/update tools, but the verb+resource combination is unambiguous.

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

Usage Guidelines4/5

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

'Use this to correlate cost changes with real-world events' gives a clear use context, and the two examples show concrete invocations. It does not, however, name when-not to use it or route to alternatives like search or find_cost_change_factors, so exclusions are missing.

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

list_label_dimensionsA
Read-only
Inspect

List all published engineered label dimensions (merge + value map). Compact rows only: id, name, sourceKeys, maps. No pagination — orgs do not have enough labels to page. Edits go through publish_label_dimensions operations by id (merge; do not resend this array). Pass an operations array (add / update / delete by id). The server merges them onto all existing label dimensions — do not resend the full list. Publishing takes about 10 minutes to show up in Explorer. Preview with dryRun: true (default), then call once with dryRun: false and confirm: true. Before rename or delete, call list_label_dimension_usages. Not virtual dimensions — those use list_virtual_dimensions. EXAMPLE: "Show published label dimensions" → {}

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).

TDQS

A4.3/5.0
Behavior4/5

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

With readOnlyHint/destructiveHint/openWorldHint already declaring the safety profile, the description still adds real value: it specifies the return payload ('Compact rows only: id, name, sourceKeys, maps') in the absence of an output schema, and states pagination behavior ('No pagination — orgs do not have enough labels to page'). The remaining text about dryRun/confirm and the ~10 minute Explorer delay describes the publish workflow rather than this tool, so it is context rather than this tool's own behavior.

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

Conciseness3/5

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

Purpose and scope are front-loaded in the first sentence, but roughly half the text is instructions for a different tool (publish_label_dimensions dryRun/confirm flow, merge semantics, 'do not resend the full list'). That material is useful workflow context yet dilutes a listing tool's description.

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?

Covers what an agent needs to call this correctly: the returned fields (substituting for a missing output schema), the absence of pagination, and the correct sibling tools for filtered/related operations. No material gap remains.

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

Parameters3/5

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

Schema description coverage is 100% and there is a single optional slug parameter already fully documented in the schema ('Omit to auto-detect from your account (fails if you belong to multiple orgs)'). The description adds no additional parameter semantics, which is the expected baseline when the schema carries the burden.

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

Purpose5/5

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

States a specific verb and resource ('List all published engineered label dimensions') and immediately defines the returned concept ('merge + value map'). It also names the sibling it is not ('Not virtual dimensions — those use list_virtual_dimensions'), so an agent can disambiguate from list_virtual_dimensions and list_label_dimension_usages without opening either 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 routing: use list_label_dimension_usages before rename or delete, use publish_label_dimensions operations for edits, use list_virtual_dimensions for virtual dimensions. The read-only scope of this tool is clearly bounded against the mutation path.

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

list_label_dimension_usagesA
Read-only
Inspect

List stored objects that reference a label dimension column (dashboards, reports, alerts, events, virtual dimensions, budgets) before rename or delete. Pass id (from list_label_dimensions) and/or name; id wins when both are set. Native cos_* names work with name alone. Hits are JSON/CEL scans of groupBy, filterCel, conditionsCel, and conditionCel — not live BigQuery. Empty usages is success (safe to delete from a reference point of view). Capped at 100 hits (truncated: true when more). EXAMPLE: "Where is environment used?" → { id: "label_…" }

NameRequiredDescriptionDefault
idNoEngineered label id from list_label_dimensions.
nameNoColumn name (LabelDimension.name). At least one of id / name is required; id wins when both are set.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare this is a safe read, but the description adds material behavioral facts: hits are static JSON/CEL scans of specific fields rather than live BigQuery, an empty result is success/safe-to-delete, and results are capped at 100 with a truncated flag.

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?

Purpose and scoping are front-loaded, and every clause carries information (semantics, caveats, cap). It is dense with em-dash asides rather than wasteful, though slightly packed for a single paragraph.

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?

No output schema exists, yet the description pre-empts the questions an agent would have about results: what empty means, what is scanned, and the truncation behavior. Nothing needed to call it correctly or interpret the response 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% and the schema already documents the id-wins rule, but the description adds non-schema meaning: 'Native cos_* names work with name alone,' clarifying the name parameter's accepted domain.

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

Purpose5/5

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

States a specific verb and resource ('List stored objects that reference a label dimension column') and enumerates the object types, so an agent distinguishes it from list_label_dimensions (which returns dimensions, not usages) without opening either 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?

Explicitly frames the use case ('before rename or delete') and names the complementary tool to source ids from ('Pass id (from list_label_dimensions)'). The condition that selects the parameter path is spelled out, leaving nothing to inference.

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

list_metricsA
Read-only
Inspect

List saved Costory business metrics and, optionally, matching live external metrics from connected integrations (e.g. Tsuga, BigQuery, Datadog, CloudWatch, Google Cloud Monitoring). Saved metrics return id/name/type for { type: "metric", metricId: "..." } in query. Set includeExternal: true with a specific search term to return externalMetrics with provider, integrationId, integrationName, metricName, unit, capabilities, and attributes. That catalog is enough to build { type: "externalMetric", provider, integrationId, metricName, aggregator, groupByFields, conditions } for Tsuga, Datadog (attributes are tag keys; metricName is the Datadog metric name), CloudWatch (metricName is Namespace/MetricName such as AWS/EC2/CPUUtilization; attributes are dimension names), Google Cloud Monitoring (provider "cloudmonitoring"; metricName is the metric type such as compute.googleapis.com/instance/cpu/utilization; attributes are fully-qualified group-by fields such as metric.label.state or resource.label.project_id, and conditions is an optional Monitoring filter), or Amplitude. For BigQuery or S3, the same hit also includes schema (typed columns: DATE / NUMERIC / STRING). Pick dateColumn from the first DATE field, metricColumn from the first NUMERIC field, and groupByFields from STRING fields (also listed in attributes). gapFillingMethod is not in the catalog — default FORWARD_FILL unless the user specifies ZERO, LINEAR_INTERPOLATION, or SPREAD. Those three fields are required on both query and a new virtual-dimension telemetry allocation. Do not call includeExternal without search; external catalogs can be large, and the tool will ask for a search term instead of listing everything. externalLimit (default 50, max 50) caps matching external results. New virtual-dimension telemetry reallocations use includeExternal + an inline externalMetric (same fields as a query series, plus exactly one groupByFields entry as the series key). Pass datasourceId only to inspect a leftover saved usage-metric datasource's groupByDimensions — not for new reallocations. Then call query (type: "metric", metricId, groupBy) to inspect the values for that leftover datasource. The datasourceId is the same metricsDatasource id this tool returns as a saved-metric id (strip any ::metricName suffix). Does not return values (use query). EXAMPLES: • "What business metrics do we have?" → {} • "Find Tsuga metrics about requests" → { includeExternal: true, search: "request" } • "Find BigQuery tables about revenue" → { includeExternal: true, search: "revenue" } • "Find Datadog metrics about CPU" → { includeExternal: true, search: "cpu" } • "Find CloudWatch metrics about CPU" → { includeExternal: true, search: "CPUUtilization" } • "Find GCP Monitoring metrics about CPU" → { includeExternal: true, search: "cpu/utilization" } (Cloud Monitoring search matches the metric type, not its display name) • "What live metrics can I reallocate shared cost by?" → { includeExternal: true, search: "cpu" } • "What can I split a leftover saved-metric datasource by?" → { datasourceId: "clx…" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
searchNoOptional filter on saved metric names. Required when includeExternal is true because external metric catalogs can be large.
datasourceIdNoSpecial list mode (not a query field): return groupBy dimensions for ONE leftover saved usage-metric datasource. New telemetry reallocations use includeExternal + inline externalMetric instead. Pass the metricsDatasource id from metrics[].id (strip any `::metricName` suffix). Then call query with type:"metric", metricId:<same id>, groupBy:<dimension>. Do not confuse with query metricId — that is the identity field on the query tool; this filter only returns dimensions. When set, search / includeExternal are ignored.
externalLimitNoMax matching external metrics to return when includeExternal is true and search is provided (capped at 50).
includeExternalNoWhen true and search is provided, include matching live integration-backed external metrics in externalMetrics.

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already cover read-only and non-destructive behavior, so the description does not need to re-establish safety. It adds useful behavioral context: external catalogs can be large and will ask for a search term, externalLimit is capped at 50, gapFillingMethod defaults to FORWARD_FILL, and the tool returns metadata only, not actual values.

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?

The description is long but dense, and nearly every sentence carries provider-specific behavior an agent needs. It front-loads the core purpose, then details edge cases and ends with examples. It is not as compact as the best definitions, but it contains little filler and uses examples to illustrate the main parameter modes.

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?

There is no output schema, so the description carries the full burden of explaining return shapes, and it does: saved metric id/name/type, externalMetrics fields, BigQuery/S3 schema, datasourceId special mode, gapFilling default, and required fields for query or reallocations. For a tool with this many provider-specific modes, the coverage is comprehensive.

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

Parameters5/5

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

Even though schema coverage is 100%, the description substantially enriches the parameters: search is required when includeExternal is true, datasourceId has a special list mode with exact id-suffix handling, includeExternal selects a specific return shape, and externalLimit has documented defaults and caps. It also explains how returned fields map to downstream query and externalMetric construction.

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?

The description opens with a specific verb and resource: list saved Costory business metrics and optionally matching live external metrics. It clearly separates this tool from query by stating it does not return values, which helps an agent pick it correctly among the sibling tools.

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?

The description gives explicit usage rules: use includeExternal only with a search term, pass datasourceId only for inspecting leftover datasource groupByDimensions, and call query afterwards to inspect values. The examples map natural-language requests to concrete parameter objects, which is strong when-to-use guidance.

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

list_organizationsA
Read-only
Inspect

List organizations you have access to. Use this to discover available orgs or when a user needs to choose between multiple organizations. Note: slug is now optional on all tools and will auto-detect from your account.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so safety is covered. The description adds useful context about slug auto-detection and scoping results to accessible orgs, going beyond the annotations.

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

Conciseness5/5

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

Three concise sentences with front-loaded purpose. The usage note and slug clarification are valuable with no redundant content.

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

Completeness4/5

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

For a simple zero-parameter list tool with no output schema, the description covers purpose, usage, and a relevant behavioral note. It lacks explicit return format, but this is manageable for such a straightforward operation.

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?

There are zero parameters, so baseline is 4. The description adds no parameter-specific info, but none is needed.

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?

The description clearly states 'List organizations you have access to' with a specific verb and resource. It distinguishes itself from other list tools by focusing on organizations and adding context about discovering orgs.

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

Usage Guidelines4/5

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

Explicitly states when to use: 'to discover available orgs or when a user needs to choose between multiple organizations.' It does not mention alternatives or when-not, but the guidance is clear and contextually relevant.

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

list_reportsA
Read-only
Inspect

List compact report summaries for the organization: id, name, kind (SCHEDULED / ONE_TIME), status, nextRunDate, destination counts, and lastRunHealth. Includes on-demand reports. Optional filters: kind (SCHEDULED / ONE_TIME), teamId (reports scoped to one team), and includeArchived (default false). Read-only. EXAMPLE: { kind: "SCHEDULED" }

NameRequiredDescriptionDefault
kindNoFilter by cadence: SCHEDULED or ONE_TIME.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
teamIdNoFilter by owning team id.
includeArchivedNoInclude archived reports (default false).

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false; the description goes beyond by specifying the returned fields (id, name, kind, status, nextRunDate, destination counts, lastRunHealth), confirming on-demand reports are included, and documenting the includeArchived default. It does not address pagination or permission requirements, but given the strong annotations this is sufficient.

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

Conciseness5/5

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

The description is compact and front-loaded with the essential purpose, followed by a field list, filters, a short read-only note, and an example. Every sentence contributes; there is no filler.

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

Completeness4/5

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

For a list operation with no required parameters and no output schema, the description covers the return fields and filters. It does not mention pagination or potential size limits, but the tool's simplicity and the provided field list make it complete enough for an agent to use correctly.

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?

The input schema has 100% coverage with descriptions for all four parameters, so the baseline is 3. The description adds a concrete usage example ({ kind: 'SCHEDULED' }) and restates filter semantics, which slightly enhances the parameter understanding beyond the schema.

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?

The description opens with a specific verb+resource: 'List compact report summaries.' It defines the output fields and states the scope ('for the organization'), clearly distinguishing it from sibling report-execution tools like get_report_execution, run_report_now, and update_report. It also clarifies inclusion of on-demand reports.

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

Usage Guidelines4/5

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

The description implicitly establishes when to use this tool (when you need a compact overview of reports) and lists available filters, but it does not explicitly mention when not to use it or point to alternatives (e.g., use get_report_execution for full details). The read-only hint is clear context.

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

list_skillsA
Read-only
Inspect

List available Costory MCP workflow skills (skillId, name, description) from the remote skill catalog. Call this when you are unsure which skillId to load, then call get_skill with the chosen skillId. If already known (virtual-dimensions, dashboards, reports, query, recipes), you may skip this and call get_skill directly. EXAMPLE: "Which workflow guides can I load?" → {}

NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already provide readOnlyHint=true and destructiveHint=false. The description adds that the catalog is remote and lists the returned fields, providing useful context beyond the annotations, though it doesn't cover other behaviors like pagination.

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

Conciseness5/5

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

The description is compact, front-loads the primary purpose, and includes usage guidance and an example without any redundant filler. Every sentence earns its place.

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 simple zero-parameter read-only listing tool, the description fully covers what it does, when to use it, what it returns, and the relationship to get_skill. There are no significant gaps.

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?

The tool has zero parameters, so schema coverage is trivially complete. The description includes an example invocation with {}, satisfying the baseline for the zero-param case.

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?

The description uses a specific verb ('List') with a clear resource ('Costory MCP workflow skills') and enumerates the returned fields (skillId, name, description), making it distinct from the sibling get_skill tool.

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?

The description explicitly states when to call this tool ('when you are unsure which skillId to load') and when to skip it in favor of get_skill ('If already known... call get_skill directly'), naming the alternative.

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

list_tagsA
Read-only
Inspect

List all tags in the organization with a count of tagged resources (dashboards, views, explorers, alerts). Use to discover available tag values before passing them to create_event or update_event as the tags array, or before calling create_alert, update_alert, create_dashboard, update_dashboard, create_report, or update_report with tags.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description goes beyond that by disclosing org-level scope and the composition of the returned data (per-type counts), which an agent cannot infer from the annotations alone. It stops short of describing pagination or whether empty orgs return an empty list.

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?

Front-loaded with the core action and return shape, then the usage guidance. The enumeration of eight downstream tools is long but each entry earns its place by naming a real integration point; only minor trimming is possible.

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

Completeness4/5

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

There is no output schema, so the description usefully compensates by describing the return contents (tags with resource counts). Combined with a fully documented single parameter and read-only annotations, an agent has what it needs, though ordering and pagination behavior remain unstated.

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

Parameters3/5

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

Schema coverage is 100% and the single slug parameter is fully documented in the schema (including auto-detect behavior and the multi-org failure case). The description adds nothing about the parameter, so the baseline 3 applies.

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?

Specific verb+resource ("List all tags in the organization") plus a precise statement of what each entry contains (counts of tagged dashboards, views, explorers, alerts). This clearly distinguishes it from siblings like delete_tag or the various list_* tools by stating both scope and payload.

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?

Explicitly states when to call it ("discover available tag values before passing them to...") and enumerates the concrete downstream tools that consume tags (create_event, update_event, create_alert, update_dashboard, etc.). This is a textbook when-to-use routing instruction with named alternatives.

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

list_teamsA
Read-only
Inspect

List all non-archived teams in the organization, including teams the current user is not a member of. Each team has an id (pass as teamId on set_object_permissions), visibility, and role (the caller's membership role when they belong to the team; omitted otherwise). Each scope has an id (pass as scopeId to query or a report widget to apply the saved scope) and a pre-defined filterCel string (pass as filterCel for the same effect inline). Optional query filters by team name. Use when the user asks about a team's costs, wants to filter by team scope, or needs a teamId to share a dashboard, report, budget, or cost alert.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
queryNoOptional team-name search. Omit to list every non-archived team in the organization.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, covering the safety profile. The description adds valuable behavioral context: it includes non-member teams, explains that 'role' is omitted when the caller isn't a member, and details how the returned 'id' and scope 'id'/'filterCel' should be used in other calls. This goes beyond the annotation basics.

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?

The description is moderately long but every sentence carries functional information: resource scope, field meanings, how to repurpose IDs, and usage triggers. It is front-loaded with the core purpose and organized logically, though it could be tightened by merging the scope/filterCel details into a more compact phrasing.

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

Completeness4/5

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

Since there is no output schema, the description appropriately explains the return structure (id, visibility, role, scope id, filterCel) and how to consume those fields in other tools. It omits pagination or ordering, but those are not critical for a list operation, and the provided information is sufficient for correct invocation and interpretation.

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

Parameters3/5

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

The input schema already documents both parameters fully (slug auto-detection behavior, and query as optional team-name search) with 100% coverage. The description reiterates the query filtering but adds no new parameter-level meaning. Per the rubric, high schema coverage yields a baseline of 3, which is appropriate here.

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?

The description states a precise verb and resource ('List all non-archived teams') and clearly distinguishes itself by noting it includes teams the user is not a member of, which sets it apart from other list_* tools. It also specifies the data returned per team, removing any ambiguity about what the tool outputs.

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

Usage Guidelines4/5

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

The description explicitly lists three concrete use cases: when the user asks about team costs, wants to filter by team scope, or needs a teamId for sharing dashboards/reports/budgets/alerts. It does not mention when not to use it or name alternative tools, though the listed scenarios are sufficiently specific to guide selection.

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

list_usersA
Read-only
Inspect

List organization members so you can share a dashboard, report, budget, or cost alert with a person. Returns id, name, and email. Optional query filters by first name, last name, or email; omit it to list up to 100 members. Use the returned id as userId on set_object_permissions USER grants. You do not need to share a team with someone to list or share with them.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
queryNoOptional name or email search. Omit to list up to 100 organization members.

TDQS

A4.3/5.0
Behavior4/5

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

Annotations already mark this as read-only, and the description adds that it returns id, name, and email, lists up to 100 members by default, and filters by name/email. The extra note that sharing does not require sharing a team is useful behavioral context beyond the annotations.

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

Conciseness5/5

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

Four focused sentences cover purpose, return fields, query behavior, and the downstream use of the returned id. Every sentence earns its place and no filler is present.

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 simple, read-only, zero-required-parameter tool with complete schema coverage, the description is complete. It explains results, filtering, limits, and how to use the output, so an agent has enough to call it correctly.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The description adds the first-name/last-name/email detail and reinforces the omit-query behavior, but does not materially expand on the slug parameter beyond what the schema already says.

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

Purpose5/5

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

States the specific verb 'List' and resource 'organization members', plus the purpose of sharing dashboards/reports/budgets/alerts. Clearly distinguishes from siblings like list_teams and list_alerts by focusing on people rather than resources.

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

Usage Guidelines4/5

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

Provides clear when-to-use context: when you need a person's id to share something with them or to set object permissions. It explains the optional query behavior and the no-team-sharing prerequisite, though it does not explicitly name an alternative like list_teams for team-related queries.

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

list_virtual_dimensionsA
Read-only
Inspect

List virtual dimensions (custom cost axes) in the organization. virtualDimensionId in inputs equals id from list/get/search. Returns id, virtualDimensionId (same as id), name, bqName, description, status, computeStatus, tags (string[] of tag names), hasPendingDraft, and optionally draftValidation.ok when includeDraftStatus is true. bqName is the immutable BigQuery/CEL field name (e.g. virtual_environment) — set once at create from the initial name and never updated, even when name changes. Always use bqName (not name) for groupBy/filterCel in query. Use query to match name/bqName/description/tag; status filters DRAFT vs COMPLETED. Newly created MCP drafts typically have status DRAFT; published VDIMs are COMPLETED. Paginate with limit (default 50, max 100) and offset. Call this before get when the user refers to a VDIM by name rather than id. EXAMPLE: "Show our environment virtual dimensions" → { query: "environment" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
limitNoMax rows to return (default 50, cap 100)
queryNoFilter by name, bqName, description, or tag name
offsetNoNumber of rows to skip before returning results
statusNoFilter by virtual dimension statusall
includeDraftStatusNoInclude draftValidation.ok for rows with a pending draft

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already indicate readOnlyHint=true and destructiveHint=false; the description adds substantial behavioral context: bqName is immutable and set once at creation, status semantics for drafts vs published VDIMs, and the exact return fields. It also specifies that virtualDimensionId equals id, which is a non-obvious data model behavior. No contradiction with annotations.

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

Conciseness5/5

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

The description is long but every sentence is purposeful. It front-loads the core purpose, then explains field relationships, usage rules, and ends with a concrete example. There is no fluff or repetition of schema content; the structure is logical and scannable.

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?

With no output schema, the description takes full responsibility for explaining return values, which it does explicitly (id, virtualDimensionId, name, bqName, description, status, computeStatus, tags, hasPendingDraft, draftValidation.ok). It also covers edge cases like draft vs published status, pagination behavior, and the bqName immutability pitfall. This is complete for an agent to invoke correctly.

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?

The schema already covers all parameter descriptions at 100% (baseline 3). The description adds meaningful context beyond the schema, notably the immutability of bqName and the interpretation of status values (DRAFT vs COMPLETED). It also reiterates the limit cap of 100 and shows an example query, but does not deeply enhance every parameter; hence a 4 rather than 5.

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?

The description opens with a specific verb+resource: 'List virtual dimensions (custom cost axes) in the organization.' It clearly differentiates from the 'get' sibling by stating 'Call this before get when the user refers to a VDIM by name rather than id.' The example further anchors the purpose.

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?

The description provides explicit when-to-use guidance against the sibling 'get' tool. It also explains how to use query filters, status filters (DRAFT vs COMPLETED), pagination, and the critical rule to always use bqName (not name) for groupBy/filterCel. This is actionable direction beyond generic listing.

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

preview_alertA
Read-only
Inspect

Backtest a cost-alert condition BEFORE creating it: replays the condition against the last lookbackDays (default 45) of data and reports how many times it would have fired. Takes the same queries + condition + dedup as create_alert (no notification channel needed). The dedup window is per groupBy value; delivery stays one message listing newly eligible groups. Returns the evaluation window, firingDays (distinct days the condition held), firingRows (per-group fires), notificationsCount (days on which at least one newly eligible group would notify) and a sample of firing dates with per-group state. Use this to sanity-check a condition/threshold (and tune dedup) before calling create_alert. EXAMPLE: "Would 'alert if 7-day AWS spend tops $50k' have fired this month?" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", filterCel: "cos_provider in ["AWS"]" }], condition: "rollingSum(a, 7, DAY) > 50000", dedup: { kind: "CALENDAR", calendarUnit: "WEEK" }, lookbackDays: 30 }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
dedupNoDeduplication config controlling how often a still-firing group notifies. The window is per groupBy value; delivery stays one message listing newly eligible groups. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days. Optional here: when provided the result also reports how many notifications would actually be sent after dedup.
queriesNoSame series objects as the `query` tool `queries` array (referenced by `condition`).
conditionYesAlerts v3 firing rule: a single boolean expression over the query names (`name` field of each query). Supports arithmetic (+ - * /), comparisons (> >= < <= == !=), logical and/or/not, parentheses, and these window functions: rollingSum(a, N, UNIT) (trailing sum over the last N units, UNIT ∈ DAY|WEEK|MONTH, inclusive of today), weekToDateSum(a) (Monday-to-date), monthToDateSum(a) (1st-of-month-to-date), and timeShift(a, N, UNIT) (value shifted back N units; may wrap a window function). Examples: `a > 1000`, `rollingSum(a, 7, DAY) > 1000`, `(a - timeShift(a, 1, DAY)) / timeShift(a, 1, DAY) > 0.2`, `a > 10000 or rollingSum(a, 7, DAY) > 50000`.
lookbackDaysNoTrailing window length in days to replay the condition over (default 45).

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already flag this as read-only, and the description adds behavior well beyond that: it replays a condition, reports firing days/rows, applies dedup semantics per groupBy value, and describes the notification count computation. It also discloses the default lookback window and returns a sample of firing dates with state, giving the agent a clear model of what execution will do.

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?

The description is front-loaded with the core purpose and is organized clearly: what it does, what it takes, what it returns, and when to use it. It is somewhat long and repeats dedup details that also appear in the schema, but the example and return-field listing earn their place for such a complex tool.

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?

With no output schema, the description compensates by enumerating the return values (`firingDays`, `firingRows`, `notificationsCount`, sample dates with `state`), which is essential for the agent to interpret results. The schema handles parameter syntax fully, the annotations handle safety, and the description provides workflow context and a realistic invocation example. Nothing critical 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 baseline is 3. The description adds value by explaining how parameters combine with a concrete example ('alert if 7-day AWS spend tops $50k') and by tying queries/condition/dedup to create_alert semantics. It also clarifies that dedup affects the returned notification counts, which is not explicit in the schema.

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?

The description opens with a specific verb and resource ('Backtest a cost-alert condition') and explicitly distinguishes itself from create_alert by saying it runs BEFORE creation and needs no notification channel. This makes the tool's role unmistakable even among many sibling tools.

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?

It explicitly says to use this to 'sanity-check a condition/threshold (and tune dedup) before calling create_alert,' naming the closely related sibling and the intended workflow. It also communicates that notification-channel setup is not needed here, reinforcing the boundary between previewing and creating.

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

preview_report_widgetA
Read-only
Inspect

Dry-run preview of ONE report widget. Read-only and in-memory: does not persist a report, does not mutate any Costory object, and does not send Slack/Teams/email. Pass the same reportContext + widget object you will later hand to create_report. Returns a token-bounded, per-type result. By type: DIGEST → resolvedPeriod, comparison totals, largest changes, root nodes, summary markdown (when display is "summary"), recommendations; TOP_FLOP → bounded top/flop rows; GRAPH_SNAPSHOT → bounded series sample (no image) + explorerUrl; DASHBOARD_PDF/TEXT → validity pointer. Put shared period / groupBy / metric / currency / conditionsCel in reportContext; widgets omit matching fields to inherit. The legacy context alias is temporarily accepted but deprecated; never send both. DIGEST hierarchy: reportContext.groupBy (root, preferred) + additionalGroupBy (deeper levels). Per-widget override: set useDashboardGroupBy: false to ignore reportContext.groupBy for this widget — the first additionalGroupBy item (or queries[0].groupBy) becomes the root; false requires at least one dimension. DIGEST threshold defaults: 100 absolute / 5% relative / 20 changes (topLargestAbsoluteChange integer 1–100, applied at every tree level). DIGEST AI (opt-in, still preview-only — nothing is saved or delivered): display ("tree" default | "table" | "summary" for LLM executive narrative) and enableAiInvestigation (boolean, default false — per-node deep analysis, independent of display). DIGEST aggBy is Month or Week — never Period (Period is TOP_FLOP). EXAMPLES: • Monthly DIGEST by env → project → service (AI summary) → { reportContext: { datePreset: "LAST_MONTH", groupBy: "cos_environment", metricId: "cost", currency: "USD" }, widget: { type: "DIGEST", queries: [{ type: "cost", name: "a" }], aggBy: "Month", additionalGroupBy: ["cos_sub_account_id", "cos_service_name"], minAbsoluteDiff: 100, minRelativeDiff: 5, topLargestAbsoluteChange: 20, display: "summary", enableAiInvestigation: false } } • Kubernetes-only weekly DIGEST (per-widget filterCel) → { reportContext: { datePreset: "LAST_WEEK", groupBy: "cos_namespace_reallocated", metricId: "cost", currency: "USD" }, widget: { type: "DIGEST", title: "Kubernetes", queries: [{ type: "cost", name: "a", filterCel: "cos_cluster_name != null" }], aggBy: "Week", additionalGroupBy: ["cos_workload_name"] } } • Namespace-rooted DIGEST overriding the report group-by → { reportContext: { datePreset: "LAST_MONTH", groupBy: "cos_environment", metricId: "cost", currency: "USD" }, widget: { type: "DIGEST", title: "Kubernetes", useDashboardGroupBy: false, queries: [{ type: "cost", name: "a" }], aggBy: "Month", additionalGroupBy: ["cos_namespace_reallocated", "cos_workload_name"] } } • Weekly TOP_FLOP → { reportContext: { datePreset: "LAST_WEEK", groupBy: "cos_service_name", metricId: "cost", currency: "USD" }, widget: { type: "TOP_FLOP", queries: [{ type: "cost", name: "a" }], aggBy: "Period", topN: 5, flopN: 5 } }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
widgetYesSingle widget to preview (same shape as create/update `widgets[]` items).
contextNoDeprecated alias for `reportContext`; supported temporarily for backward compatibility. Do not send both fields.
reportContextNoOptional shared context the widget inherits (same shape as `create_report` `reportContext`).

TDQS

A4.6/5.0
Behavior5/5

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

Goes well beyond the annotations: 'read-only and in-memory', no persisted report, no Costory object mutation, no Slack/Teams/email delivery, and 'Returns a token-bounded, per-type result'. It also flags slower opt-in paths (display: "summary", enableAiInvestigation via async analysis_agent_run) and the deprecation of the `context` alias — disclosure an agent cannot get from the schema.

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?

Front-loaded with the core claim and safety profile, then organized by concern (inheritance, hierarchy, thresholds, AI options) and closed with worked examples. It is long and some clauses restate schema descriptions, but for a five-variant discriminated-union payload the density is largely earned.

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?

No output schema exists, so the description carries the return-shape burden — and it does, listing per-type results (DIGEST resolvedPeriod/comparison totals/root nodes; TOP_FLOP bounded rows; GRAPH_SNAPSHOT series sample + explorerUrl; DASHBOARD_PDF/TEXT validity pointer). Combined with the inheritance and override rules, an agent can call this correctly without further context.

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 baseline would be 3, but the description adds cross-field semantics the schema cannot express cleanly: widgets omit matching fields to inherit from reportContext, never send both `context` and `reportContext`, and the DIGEST hierarchy rules plus threshold defaults (100/5%/20). Slight redundancy with the per-parameter schema text keeps it off a 5.

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+scope: 'Dry-run preview of ONE report widget', which immediately separates it from create_report (persist), preview_alert and query. The per-type return breakdown further pins down exactly what the tool produces for each widget type.

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

Usage Guidelines4/5

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

States the lifecycle relationship explicitly: 'Pass the same reportContext + widget object you will later hand to create_report', which tells the agent this is the validation step before persistence. It also gives when-to-use guidance per widget type (DIGEST vs TOP_FLOP vs GRAPH_SNAPSHOT). It stops short of naming exclusion conditions such as when to skip preview and call create_report directly.

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

preview_virtual_dimension_draftA
Read-only
Inspect

Preview per-rule costs or a groupBy breakdown (read-only BigQuery). virtualDimensionId in inputs equals id from list/get/search. Operates on the latest pending draft if one exists (draftPersisted: true); otherwise previews published rules in memory without creating a draft (draftPersisted: false — not publishable). To publish changes after editing published-only state, call update_virtual_dimension_draft for an existing virtualDimensionId (or create_virtual_dimension_draft for a brand-new VDIM) — preview alone does not persist. Call after a successful create/update. Read the "summary" field first. Both modes share the same time window: optional datePreset (official presets — TRAILING_30_DAYS default, same enum as dashboards) or explicit from/to (YYYY-MM-DD, same shape as query); mutually exclusive. mode "costs": per-rule costs with totals.namedRulesSharePercent / totals.leftoverSharePercent, each rule's conditionCel and allocatesTo, plus howToRead. mode "breakdown": spend inside a target rule (ruleId or ruleIndex) split by groupBy — returns period (datePreset or from/to), scope.explanation, topValues[{ value, cost, percentOfScope }], and dailyTotals (not raw chart JSON). Discover valid groupBy values via search with type: ["dimensions"]. position (from get and preview costs output) and ruleIndex (preview/overlap input) refer to the same 0-based ordinal in the ordered rule list [...rules, leftover]. Prefer ruleId over ruleIndex. Target leftover via ruleId of leftoverRule or ruleIndex: rules.length. Optional currency (default USD) — pass the same value as query cost queries to align totals. costMetric selects the cost column (default cost); valid ids: cost, effective_cost, list_cost, contracted_cost (also accepts contracted_costs), unblended_cost, net_unblended_cost, amortized_cost, net_amortized_cost. EXAMPLES: • "Preview Environment VDIM draft costs" → { virtualDimensionId: "<virtualDimensionId from create/list>", mode: "costs" } • "What cos_region values sit inside Production?" → { virtualDimensionId: "<virtualDimensionId from create/list>", mode: "breakdown", ruleId: "<from get/preview costs>", groupBy: "cos_region", datePreset: "TRAILING_30_DAYS" } • "Preview costs in EUR to match earlier queries" → { virtualDimensionId: "<virtualDimensionId from create/list>", mode: "costs", currency: "EUR", from: "2025-01-01", to: "2025-03-31" }

NameRequiredDescriptionDefault
toNoExplicit window end (YYYY-MM-DD). Use with from instead of datePreset — same shape as query.
fromNoExplicit window start (YYYY-MM-DD). Use with to instead of datePreset — same shape as query.
modeYes`costs` (per-rule costs including leftover and rule metadata) or `breakdown` (drill into a rule).
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
ruleIdNoTarget rule id (breakdown mode; preferred over ruleIndex)
groupByNoDimension to split by (breakdown mode)
currencyNoCost currency (default USD). Pass the same currency as prior query calls to align preview totals.
ruleIndexNoTarget rule index (breakdown mode fallback)
costMetricNoCost column id (default cost). Valid: cost, effective_cost, list_cost, contracted_cost, unblended_cost, net_unblended_cost, amortized_cost, net_amortized_cost (also accepts contracted_costs → contracted_cost).
datePresetNoOfficial date preset (same values as dashboards/query context). Default TRAILING_30_DAYS. Mutually exclusive with from/to.
virtualDimensionIdYesVirtual dimension id (stable public identifier)

TDQS

A4.8/5.0
Behavior5/5

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

Annotations cover only the read-only safety profile, but the description adds substantial behavioral context beyond them: it operates on the latest pending draft when one exists (draftPersisted: true) and otherwise previews published rules in memory without creating a draft (draftPersisted: false, not publishable). It also clarifies both modes share the same time window and that datePreset/from-to are mutually exclusive.

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?

Front-loaded with the core purpose and mode behavior, and most sentences carry distinct information (draft persistence, rule targeting, return fields, currency). It is nonetheless very long and dense, with some overlapping restatement of from/to and costMetric between description and schema, so it is not maximally tight.

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?

With no output schema, the description carries the return-value burden and does so: it names totals.namedRulesSharePercent/totals.leftoverSharePercent, conditionCel, allocatesTo, howToRead, and breakdown's period/scope.explanation/topValues/dailyTotals. Combined with mode, targeting, and window semantics, an agent has what it needs to invoke correctly.

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 description coverage is 100%, so the baseline is 3, but the description meaningfully enriches semantics: ruleId is preferred over ruleIndex, how to target leftover via the leftoverRule id or ruleIndex: rules.length, the shared 0-based ordinal between position and ruleIndex, currency alignment with query, and the costMetric valid-id list. This is real added meaning over the schema.

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

Purpose5/5

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

States a specific verb (Preview) and resource (virtual dimension draft) with the two operating modes named explicitly ('per-rule costs or a groupBy breakdown (read-only BigQuery)'). An agent can distinguish this from update_virtual_dimension_draft and create_virtual_dimension_draft without opening any 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?

Explicitly says when to call ('After a successful create/update') and draws the line against alternatives: 'preview alone does not persist', routing to update_virtual_dimension_draft or create_virtual_dimension_draft to publish. Mode selection (costs vs breakdown) and how to discover valid groupBy values are also spelled out.

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

publish_label_dimensionsA
Destructive
Inspect

Merge add/update/delete operations onto published label dimensions, then replace the stored document (one feature-engineering refresh, about 10 minutes). Input is operations[], never the full labels array — sibling labels you do not mention are kept. add: sourceKeys (required), optional name/maps (id is generated). update/delete: target by id from list_label_dimensions (or an id created by an earlier add in the same array). Duplicate sourceKeys across labels are rejected; move a key with update on the owner in the same array. Names must be unique across labels and virtual dimension bqNames (default name is a sanitized sourceKeys[0]); a collision rejects the whole operations array — send a different unique name. Deleting a label and adding it back (same name or sourceKeys) in the same array is allowed, in either order. dryRun defaults true (preview the full next labels document, no write). Persist once with dryRun: false and confirm: true. Check list_label_dimension_usages before rename or delete. Demo orgs are read-only; dimensionsAdminOnly requires an org admin. Real write is Clerk MCP only — the service route accepts dry-run only. Do not call publish twice. EXAMPLES: • Preview adding environment + team → { dryRun: true, operations: [{ op: "add", sourceKeys: ["env", "environment"], name: "environment", maps: [{ value: "prd", to: "production" }] }, { op: "add", sourceKeys: ["team"], name: "team" }] } • Persist the same ops once → { dryRun: false, confirm: true, operations: [] }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
dryRunNoWhen true (default), merge and validate only — no Prisma write and no feature-engineering job.
confirmNoMust be true to persist. Merges add/update/delete onto all existing label dimensions, replaces the stored document, and starts a feature-engineering refresh that takes about 10 minutes. Put every change into this one call. Check list_label_dimension_usages before delete or rename.
operationsYesadd / update / delete operations applied in order onto the currently published labels.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations mark it destructive and non-read-only, and the description adds substantial context beyond them: a ~10 minute feature-engineering refresh, sibling labels not mentioned are preserved, duplicate sourceKeys and name collisions reject the whole array, delete-then-re-add is permitted in either order, and an auth/route constraint (admin-only, Clerk-only writes). This is far more than the annotations convey.

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?

Purpose and the dryRun-first workflow are front-loaded, and given the merge/collision/ordering complexity few sentences are wasted. It is a dense single paragraph rather than a structured list, which makes the many constraints harder to scan, but it is not padded.

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?

Despite no output schema, the description covers what dryRun returns (the full next labels document, preview only) versus what the real write does, plus ordering, collision, and auth constraints. An agent has everything needed to construct a correct call for this high-risk mutation.

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 description coverage is 100%, so baseline is 3, but the description adds array-level semantics the schema cannot express: ids are generated for add, update/delete target an id from list_label_dimensions or an earlier add in the same array, default name is a sanitized sourceKeys[0], and moving a key with update on the owner in the same array. It largely restates but usefully frames the per-item fields in operation terms.

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?

Specific verb and resource: 'Merge add/update/delete operations onto published label dimensions, then replace the stored document.' It immediately distinguishes itself from read-only siblings (list_label_dimensions, list_label_dimension_usages) and from the virtual-dimension publish path, so an agent can route correctly without opening a 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 and when-not-to: dryRun defaults true for preview, persist once with dryRun:false and confirm:true, check list_label_dimension_usages before rename/delete, demo orgs are read-only, dimensionsAdminOnly requires an org admin, and real writes happen through Clerk MCP only (the service route is dry-run only). It also warns not to call publish twice.

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

publish_virtual_dimensionA
Destructive
Inspect

Validate the latest persisted pending virtual dimension draft, then promote it to published and kick off a BigQuery refresh. virtualDimensionId in inputs equals id from list/get/search. Requires a pending draft row — call update_virtual_dimension_draft for an existing virtualDimensionId (or create_virtual_dimension_draft for a brand-new VDIM) before publish. Preview alone does not create a draft. Rejects invalid drafts with draftValidation errors (no publish). On success returns virtualDimensionId, immutable bqName, name, computeStatus, and published rules — does not wait for the refresh job. After publish, query using returned bqName for groupBy/filterCel in query — bqName is immutable (set at create from the initial name) and does not change when name is renamed. computeStatus is REFRESHING when the refresh job was queued (async — poll via get or list_virtual_dimensions until COMPLETED before querying), or TO_REFRESH when the draft was promoted but queuing the refresh job failed — do not query yet; retry publish or re-check computeStatus until COMPLETED. Deletes the pending draft version. Clerk MCP only — not available on the service route. EXAMPLE: "Publish the Environment VDIM draft" → { virtualDimensionId: "<virtualDimensionId from create/list>" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
virtualDimensionIdYesVirtual dimension id (stable public identifier)

TDQS

A4.8/5.0
Behavior5/5

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

Annotations cover destructiveHint; description adds substantial beyond that — rejects invalid drafts with draftValidation errors, deletes the pending draft version, does not wait for refresh job, discloses computeStatus semantics (REFRESHING async vs TO_REFRESH on queue failure), bqName immutability, and Clerk MCP only restriction. No contradiction with annotations.

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?

Dense but front-loaded and organized: action → prerequisite → error semantics → return fields → follow-up. Some long run-on clauses about computeStatus and bqName could be tightened, but every sentence carries operational value.

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?

Complete for a mutation tool that both deletes a draft and triggers async work. Covers prerequisites, error path, async polling, immutable identifier for downstream query, and environment restriction (Clerk MCP only). No output schema exists, and the description appropriately describes return fields.

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 baseline 3. Description adds meaning: virtualDimensionId equals id from list/get/search, and success returns bqName used for query groupBy/filterCel, with example showing virtualDimensionId sourced from create/list.

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

Purpose5/5

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

States a specific multi-step action: validate persisted draft, promote to published, kick off BigQuery refresh. Distinguishes from siblings by naming update_virtual_dimension_draft, create_virtual_dimension_draft, and preview_virtual_dimension_draft as prerequisites/alternatives.

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: requires a pending draft row; tells agent to call update/create draft first, and that preview alone does not create a draft. Also gives post-publish polling guidance (poll get/list until COMPLETED) and retry guidance on TO_REFRESH.

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

queryA
Read-only
Inspect

MINIMUM VALID CALL: { "queries": [{ "type": "cost", "name": "a", "metricId": "cost", "currency": "USD" }], "datePreset": "MTD", "aggBy": "Day" } Required per series: type (cost|metric|usage|formula|budget|externalMetric) and name. Put labels in alias.

Unified query tool for cost data, custom metrics, usage metrics, external (live integration) metrics, period comparisons, formulas, and budgets. QUERY NAMING: set type and name (prefer short ids like a/b/c for formulas); put human labels in alias (e.g. "Cost by environment") — never in name. Example: { type: "cost", name: "a", alias: "Cost by environment", groupBy: "cos_environment", ... }. For costs: metricId (cost column, default "cost") and currency (default "USD"). Use costMetricId and currency from get when aligning with a budget. For custom business metrics: use [{ type: "metric", metricId: "..." }] — get IDs from list_metrics. For infra usage metrics (e.g. CPU hours, network bytes): use [{ type: "usage", metricId: "..." }] — call suggest_usage_metrics first to discover valid metricIds for your scope. BigQuery job metrics (orgs with the BigQuery jobs integration) are usage metrics too: metricIds start with query_ (e.g. query_compute_ms, query_bytes_billed, query_count), returned by suggest_usage_metrics with their label and unit; split/scope them with the cos_query_* dimensions (e.g. cos_query_user) like any billing dimension. For live external metrics (not saved as Costory metrics): use [{ type: "externalMetric", provider: "...", integrationId: "...", metricName: "...", aggregator: "SUM", groupByFields: [], conditions: "..." }] — discover provider, integrationId, and metricName via list_metrics with includeExternal: true and a specific search term. Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. Datadog: same shape as Tsuga — metricName is the Datadog metric name (e.g. system.cpu.user), groupByFields are tag keys (e.g. host, service), conditions is an optional Datadog tag filter (e.g. env:prod). When query is set it is the Datadog metrics query string (pass-through); metricName / aggregator / conditions / groupByFields are ignored; .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. CloudWatch: set provider: "cloudwatch"; metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names (e.g. InstanceId); conditions is an optional dimension filter. BigQuery: set provider: "bigquery"; metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required — pick dateColumn/metricColumn from list_metrics schema (first DATE / first NUMERIC) and default gapFillingMethod to FORWARD_FILL; groupByFields are string column names (not CEL); conditions is an optional BigQuery WHERE predicate ANDed with the date range. S3: set provider: "s3"; identical field shape to bigquery — metricName is the fully-qualified table id returned by list_metrics (a Costory-managed external table over the customer's mirrored Parquet); same schema-derived columns; conditions is the same optional WHERE predicate. Snowflake: set provider: "snowflake"; metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-./doctor-ai.'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected. Use externalMetric for exploration when no saved metric matches; prefer saved { type: "metric" } when one exists. PERIOD: prefer datePreset (same as Explore, e.g. MTD, LAST_MONTH, TRAILING_30_DAYS). Forecast (same Forecast group as the explorer date picker): CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR — observed *TD plus Billy to EOM/EOQ/EOY. YTD/MTD/QTD stay observed-only. Mutually exclusive with from/to. Response includes the resolved period dates. For comparison: add compare: {} (or compare: { from, to }) — omit compare dates to auto-derive the preceding period (preset-aware, e.g. LAST_MONTH → previous calendar month). For formulas: add { type: "formula", formula: "a / b" } referencing other queries by name. Optional unitOverride forces the series unit (e.g. "EUR", "slot-h/TiB", "%"); omit to infer from inputs. Currency codes follow the widget currency. For budgets: use [{ type: "budget", budgetId: "..." }] — despite the field name, this must be the budget version ID (same value as budgetVersionId from get); search returns the parent budget id only, so call get with that id to obtain budgetVersionId before querying. Optional groupBy is that budget's virtual dimension bqName from get and splits one series per budget line; omit for the total. For per-line formulas (e.g. variance a - b) set the same groupBy on the sibling cost/usage/metric series. Optional chartType on each query: BAR, LINE, AREA, WATERFALL, or TABLE (defaults to LINE). groupBy is the SPLIT dimension, filterCel is the SCOPE (CEL). Before guessing CEL field names, call search with type: ["dimensions"] — empty query lists all fields; a keyword narrows to matching values. Costory label dimensions use a cos_ prefix (e.g. cos_service_name). Unlabelled resources have null on label dimensions; use filterCel with == null / != null (not is_null or string "null"). Custom virtual dimensions: use immutable bqName from list/get VDIM tools as groupBy / filterCel (not display name). Poll computeStatus until COMPLETED after publish. Optional analyze.changePoint (true or { ignoreWeekends }) runs change-point detection once per query after a timeseries result (incompatible with compare). Optional limit (integer 1–1000): max groups/rows per series. Do NOT set limit unless you need a different cap — when omitted, results default to 100 groups. Set limit above 100 (e.g. 250 or 500) when the user asks for a long tail or full breakdown list. OPTIONAL: After receiving results, consider calling "list_events" for the same date range to correlate cost changes with events, and "suggest_actions" to present follow-up options to the user. EXAMPLES: • "What are my total costs this month?" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }], datePreset: "MTD", aggBy: "Day" } • "2026 spend actual + forecast to year-end" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }], datePreset: "CURRENT_YEAR", aggBy: "Month" } • "Break down AWS costs by service over the last 90 days" → { queries: [{ type: "cost", name: "a", alias: "AWS by service", metricId: "cost", currency: "USD", groupBy: "cos_service_name", filterCel: "cos_provider in ["AWS"]" }], datePreset: "TRAILING_90_DAYS", aggBy: "Week" } • "Show costs for resources without an environment label" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", filterCel: "cos_environment == null" }], datePreset: "TRAILING_30_DAYS", aggBy: "Day" } • "How did our costs change vs last month?" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }], datePreset: "LAST_MONTH", compare: {} } • "Show CPU hours alongside compute costs" (call suggest_usage_metrics first to get valid metricIds) → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }, { type: "usage", name: "b", metricId: "k8s_cpu_hours" }], datePreset: "TRAILING_30_DAYS", aggBy: "Week" } • "What is our cost per request?" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }, { type: "metric", name: "b", metricId: "" }, { type: "formula", name: "c", formula: "a / b" }], datePreset: "TRAILING_30_DAYS" } • "Usage converted to euros (force formula unit)" → { queries: [{ type: "usage", name: "b", metricId: "query_compute_ms" }, { type: "formula", name: "c", formula: "b / 3600000 * 0.055", unitOverride: "EUR" }], datePreset: "LAST_MONTH" } • "Cost per request volume" (after list_metrics with includeExternal: true and search: "request") → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }, { type: "externalMetric", name: "b", provider: "tsuga", integrationId: "", metricName: "", aggregator: "SUM" }, { type: "formula", name: "c", formula: "a / b" }], datePreset: "TRAILING_30_DAYS", aggBy: "Week" } • "Cost per BigQuery revenue table" (after list_metrics with includeExternal: true and search: "revenue") → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }, { type: "externalMetric", name: "b", provider: "bigquery", integrationId: "", metricName: "my-project.analytics.revenue", dateColumn: "event_date", metricColumn: "amount", gapFillingMethod: "ZERO", aggregator: "SUM" }, { type: "formula", name: "c", formula: "a / b" }], datePreset: "TRAILING_30_DAYS", aggBy: "Week" } • "Cost per CPU usage from Datadog" (after list_metrics with includeExternal: true and search: "cpu") → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }, { type: "externalMetric", name: "b", provider: "datadog", integrationId: "", metricName: "system.cpu.user", aggregator: "AVG", groupByFields: ["host"] }, { type: "formula", name: "c", formula: "a / b" }], datePreset: "TRAILING_30_DAYS", aggBy: "Week" } • "Cost per EC2 CPU from CloudWatch" (after list_metrics with includeExternal: true and search: "CPUUtilization") → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }, { type: "externalMetric", name: "b", provider: "cloudwatch", integrationId: "", metricName: "AWS/EC2/CPUUtilization", aggregator: "AVG", groupByFields: ["InstanceId"] }, { type: "formula", name: "c", formula: "a / b" }], datePreset: "TRAILING_30_DAYS", aggBy: "Week" } • "Budget per calendar month" → { queries: [{ type: "budget", name: "a", budgetId: "" }], datePreset: "LAST_3_MONTHS", aggBy: "Month" } (budgetVersionId from get, not the parent id from search) • "Budget month-to-date by day (cumulative within each month — which day did we reach the budget?)" → { queries: [{ type: "budget", name: "a", budgetId: "", rollingAggregation: { aggregator: "SUM", window: { preset: "MONTH" } } }], datePreset: "MTD", aggBy: "Day" } • "Formula: month-to-date cost vs month-to-date budget (both rolling SUM per month, e.g. utilization a/b)" → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", rollingAggregation: { aggregator: "SUM", window: { preset: "MONTH" } } }, { type: "budget", name: "b", budgetId: "", rollingAggregation: { aggregator: "SUM", window: { preset: "MONTH" } } }, { type: "formula", name: "c", formula: "a / b" }], datePreset: "MTD", aggBy: "Day" } • "Budget vs actual per line" (bqName from get virtualDimension.bqName) → { queries: [{ type: "cost", name: "a", alias: "Actual", metricId: "cost", currency: "USD", groupBy: "" }, { type: "budget", name: "b", alias: "Budget", budgetId: "", groupBy: "" }, { type: "formula", name: "c", alias: "Variance", formula: "a - b" }], datePreset: "YTD", aggBy: "Month" } • Custom one-off range → { queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD" }], from: "2026-01-15", to: "2026-02-12", aggBy: "Day" }

NameRequiredDescriptionDefault
toNoExplicit window end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.
fromNoExplicit window start (YYYY-MM-DD). Use with to instead of datePreset.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
aggByNoTime grain for the series: Hour, Day, Week, Month, or Period (default Month). Hour requires Costory Pro.Month
limitNoMax 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.
analyzeNoOptional analyses. Set changePoint true (or { ignoreWeekends }) to run change-point detection once per query after a timeseries result. Incompatible with compare.
compareNoAdd 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.
queriesNoOne or more series (cost / metric / usage / externalMetric / formula / budget). Each needs a `name` for formulas (prefer short ids like a/b/c); put human labels in `alias`.
scopeIdNoOptional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries.
datePresetNoOfficial date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to.
displayOptionsNoTABLE-only. sort {by, direction}, hideEmptyRows, topN (omit limit), showTotal, precision, pivot {rows, columns}. get_skill dashboards.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare readOnlyHint/openWorldHint/destructiveHint, so the description carries the real behavioral burden and does so richly: limit defaults to 100 groups and must be raised for long tails, the response includes resolved period dates, computeStatus must be polled until COMPLETED, and BigQuery/S3/Snowflake conditions reject separators, comments, and unbalanced quotes. These are concrete operational traits not present in structured fields.

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?

Strongly front-loaded: the minimum valid call and naming convention precede the long provider-specific detail, and worked examples follow. However, the prose duplicates a substantial amount of the externalMetric provider detail already present in the schema, making it very long. It is well-organized but not maximally economical.

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 an 11-parameter tool with nested oneOf query variants and no output schema, the description covers the naming contract, every query type, period/comparison semantics, dimension discovery, and the budget-ID pitfall. It even notes what the response contains (resolved period dates) and suggests follow-up tools. Nothing needed to invoke it correctly 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 description coverage is 100%, so the baseline is 3, but the description adds genuine meaning beyond the schema: it warns that budgetId must be the budget version ID despite the field name, distinguishes groupBy (SPLIT) from filterCel (SCOPE), explains rollingAggregation for running totals, and clarifies unitOverride/currency behavior. Some overlap with the schema remains, keeping it from a 5.

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 'Unified query tool for cost data, custom metrics, usage metrics, external (live integration) metrics, period comparisons, formulas, and budgets' — a specific verb (query) plus an exhaustive enumeration of resources. It also leads with a MINIMUM VALID CALL block, so an agent knows both what the tool does and the smallest valid invocation. It is clearly distinguishable from siblings like get_dashboard_widget_data or list_metrics.

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

Usage Guidelines5/5

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

Gives explicit routing rules: call suggest_usage_metrics before usage queries, use list_metrics with includeExternal: true to discover external metric fields, call search with type: ['dimensions'] before guessing CEL names, and call get to obtain budgetVersionId. It states when to prefer saved { type: 'metric' } over externalMetric and names exclusions (analyze.changePoint incompatible with compare, datePreset mutually exclusive with from/to).

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

retry_report_executionAInspect

Side effect: retries one failed delivery only. DANGER ZONE: state the failed execution and its destination from get_report_execution, then ask the user to confirm before calling. Use after partial failure.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
executionIdYesReport execution id to retry.

TDQS

A4.2/5.0
Behavior4/5

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

The description discloses that the operation has a side effect, is a 'DANGER ZONE', and should only be used after confirmation. This adds meaningful behavioral context beyond the annotations (readOnlyHint=false, destructiveHint=false). It also clarifies the scope ('one failed delivery only'), which is not apparent from the schema. No contradiction with annotations.

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

Conciseness5/5

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

The description is extremely concise, with a clear front-loaded warning ('Side effect', 'DANGER ZONE') followed by actionable instructions. All sentences earn their place, and there is no redundancy or filler.

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

Completeness4/5

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

The description is complete for a side-effectful tool: it states the trigger condition, the required preliminary step, and the need for user confirmation. It does not describe the return value, but no output schema exists and the description does not need to. Slight gap: it does not mention what happens on success or failure, but the core context is sufficiently covered.

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

Parameters3/5

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

The input schema already provides full descriptions for both parameters (slug and executionId), so schema description coverage is 100%. The description does not add further parameter-level detail, but the schema suffices. Baseline score of 3 is appropriate.

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?

The description clearly states the tool's function: it retries one failed delivery only. This specifies the verb (retry), the resource (failed delivery), and the scope (one only), distinguishing it from sibling tools like run_report_now or transfer_report_execution. The purpose is unambiguous.

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

Usage Guidelines4/5

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

The description provides explicit when-to-use guidance ('Use after partial failure') and a required precondition (state the failed execution and its destination from get_report_execution, then ask the user to confirm). It does not explicitly name alternatives, but the instructions are clear enough for safe invocation. Slight deduction for lacking explicit when-not-to-use alternatives.

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

run_report_nowAInspect

Side effect: sends real messages now to every configured destination. DANGER ZONE: show the report name and complete destination list from get, then ask the user to confirm before calling. Returns canonical execution URLs and statuses. Never use this to recover only failed destinations.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
reportIdYesReport id to run immediately.

TDQS

A4.7/5.0
Behavior5/5

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

The description goes beyond the annotations (readOnlyHint=false, destructiveHint=false) by disclosing the real side effect of sending messages and labeling it a 'DANGER ZONE.' It also reveals the return behavior (canonical execution URLs and statuses) and the need for user confirmation. No contradiction with annotations exists; the description adds crucial behavioral context.

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

Conciseness5/5

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

The description is highly concise with three purposeful sentences: it states the core side effect, the safety step, and the return value/exclusion. There is zero filler and the 'DANGER ZONE' warning is front-loaded for immediate visibility.

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?

Despite having no output schema, the description clearly states what is returned (canonical execution URLs and statuses) and covers prerequisites, confirmation, and exclusions. For a two-parameter tool with no nested objects, this is complete and actionable for an agent.

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

Parameters3/5

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

The input schema already provides 100% description coverage for all parameters (slug and reportId), so the baseline is 3. The description does not add extra parameter-level semantics beyond the schema; it focuses on usage context rather than parameter syntax.

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?

The description explicitly states the tool 'sends real messages now to every configured destination,' which clearly identifies the action (sends) and resource (report destinations). It distinguishes itself from siblings by noting 'Never use this to recover only failed destinations,' pointing to retry_report_execution as an alternative.

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?

The description provides explicit when-to-use and when-not-to-use guidance: it instructs to 'show the report name and complete destination list from get, then ask the user to confirm before calling' and explicitly warns against using it to recover only failed destinations. This gives clear operational context and an implicit alternative (retry_report_execution).

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

search_documentationA
Read-only
Inspect

Search Costory product docs (Mintlify) and knowledge base in parallel. Synthesize both: Mintlify is the product source of truth, the KB complements with org-specific or internal detail; if they conflict, trust Mintlify. Returns Mintlify matches (titles, snippets, and full docs URLs (Url: https://docs.costory.io/...)) and KB articles (title, summary, full markdown). Optional limit (1–10, default 5) applies to KB. For a full Mintlify page, use get_documentation_page. When citing a page in chat, use the full Url: value verbatim as the markdown href — do not convert to a relative app path. EXAMPLES: • "How do I create a budget alert?" → { query: "budget alert" } • "Why do costs differ from AWS Cost Explorer?" → { query: "AWS Cost Explorer discrepancy", limit: 3 }

NameRequiredDescriptionDefault
limitNoMax number of results to return (1–10, default 5)
queryYesSearch term to find in documentation (e.g. 'budget alerts', 'dimensions', 'API reference')

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already mark this as read-only and non-destructive; the description adds substantial context beyond that: parallel search behavior, Mintlify as source of truth, KB as complementary, conflict-resolution priority, return format specifics, and the critical instruction to use the full URL verbatim when citing. No contradiction with annotations.

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

Conciseness5/5

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

The description is dense but every sentence earns its place: purpose, synthesis rule, return structure, limit nuance, alternative tool, citation guidance, and examples. It is well-organized, front-loaded with the core behavior, and uses examples to clarify usage without unnecessary filler.

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?

There is no output schema, so the description appropriately explains return values: Mintlify matches with titles, snippets, and full URLs, and KB articles with title, summary, and markdown. It also covers the limit behavior, conflict resolution, and citation format. For a search tool with this level of nuance, nothing essential 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 query and limit are documented. The description enhances this by clarifying that the limit applies only to KB results (not Mintlify matches) and by providing concrete query examples. This adds meaning beyond the schema's generic descriptions, though the schema already carries most of the parameter burden.

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?

Description uses specific verb 'Search' with clear resources: Costory product docs (Mintlify) and knowledge base. It states the search runs in parallel and describes the output, distinguishing it from the sibling get_documentation_page by explicitly naming it for full-page retrieval. This gives an agent a precise understanding of what the tool does.

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

Usage Guidelines4/5

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

Provides explicit guidance: use get_documentation_page for a full Mintlify page, includes query-to-parameter examples, and explains how to handle conflicts between sources. It lacks a broader comparison to other search-like siblings (e.g., search, query), but the key alternatives are addressed and the intended context is clear.

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

set_object_permissionsA
Destructive
Inspect

Replace the full grant list on a dashboard, report, budget, or cost alert. One tool for all four kinds — pass resourceKind, the object id, and the complete intended grants array. Omitted principals lose access. Roles are READER, EDITOR, or ADMIN. ORGANIZATION may be Reader or Editor, never Admin. CLERK_ADMIN may use any role and applies only to Clerk organization admins; omit it for No access. Every replacement must retain at least one USER, TEAM, or CLERK_ADMIN Admin grant, so empty grants[] is invalid. Call get_object_permissions first, then send the full list including grants you want to keep. New creates start as creator-only Admin and do not include CLERK_ADMIN. Do not use PRIVATE/PUBLIC or teamId on create/update tools. Resolve people with list_users (userId) and teams with list_teams (teamId) — both list the full organization, not only membership. EXAMPLES: • "Share the AWS dashboard read-only with the whole org" (keep yourself as Admin) → { resourceKind: "dashboard", resourceId: "clx9aws", grants: [{ principalType: "USER", userId: "", role: "ADMIN" }, { principalType: "ORGANIZATION", role: "READER" }] } • "Give the infra team Editor on this budget" (keep yourself as Admin) → { resourceKind: "budget", resourceId: "clx9bud", grants: [{ principalType: "USER", userId: "", role: "ADMIN" }, { principalType: "TEAM", teamId: "team_xyz", role: "EDITOR" }] }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
grantsYesFull replacement of direct grants. Omitted principals lose access. Every object must retain a USER, TEAM, or CLERK_ADMIN Admin grant. Each principal may appear once.
resourceIdYesObject id from search, get, or create.
resourceKindYesdashboard, report, budget, or costAlert. Budget alerts use the parent budget.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare destructiveHint=true, and the description reinforces and enriches this: omitted principals lose access, empty grants[] is invalid, every replacement must retain at least one Admin grant, and new objects start as creator-only Admin. It also documents role restrictions (ORGANIZATION never Admin, CLERK_ADMIN org-admin only).

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?

Front-loaded with the core operation, then rules, then two worked examples. Dense but almost every sentence carries a constraint or routing instruction; slightly long, with some rules that could be tightened.

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

Completeness4/5

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

For a destructive mutation with no output schema, the description covers prerequisites, replacement semantics, role validity, and a full workflow, plus examples. It does not describe the response or error behavior on invalid input, which is the only notable gap.

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 baseline is 3, but the description adds real semantic constraints the schema cannot express: ORGANIZATION may only be Reader/Editor, CLERK_ADMIN applies only to Clerk org admins and means No access when omitted, and resourceKind maps to the four object types. It stops short of explaining the slug parameter, which the schema covers.

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

Purpose5/5

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

States a specific verb and resource ('Replace the full grant list on a dashboard, report, budget, or cost alert') and enumerates the four supported resource kinds. It is immediately distinguishable from the sibling get_object_permissions, which reads rather than replaces.

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?

Explicitly says to call get_object_permissions first and send the full list including retained grants, tells the agent not to use PRIVATE/PUBLIC or teamId on create/update tools, and routes people/teams resolution to list_users and list_teams. When-to-use and prerequisites are fully covered.

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

suggest_actionsA
Read-only
Inspect

Suggests interesting actions the user can perform next based on the current investigation context (e.g. save a view, set up an alert, share to Slack, drill down, compare periods). Call this after investigation flows (after query or get) to present follow-up options to the user. EXAMPLES: • Standard post-query call → { hasEvents: false, hasDiff: false } • When events were found and a period comparison was already run → { hasEvents: true, hasDiff: true }

NameRequiredDescriptionDefault
hasDiffNoWhether query with compare was already called in this flow
hasEventsNoWhether list_events returned any matching events

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful context by showing how the input flags (hasEvents, hasDiff) affect the suggestions, using examples. It also implies that the tool is context-dependent, which is beyond the annotations.

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

Conciseness5/5

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

The description is appropriately concise and well-structured. The first sentence states the purpose, the second gives usage timing, and examples are presented in a clear bullet list. Every sentence contributes information without redundancy.

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

Completeness4/5

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

Given the simple tool with two boolean parameters and no output schema, the description covers purpose, usage timing, and parameter semantics. A minor gap is that it does not explicitly describe the return format (e.g., list of action objects), but the examples and phrase 'present follow-up options' make it sufficiently clear. Overall, it is complete enough for an agent to invoke correctly.

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?

The schema description coverage is 100%, giving baseline 3. The description adds semantic value by providing concrete example parameter combinations (e.g., { hasEvents: false, hasDiff: false } for standard post-query, { hasEvents: true, hasDiff: true } for events+difference), which clarifies how the flags map to real investigation flows.

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?

The description clearly states the tool 'Suggests interesting actions the user can perform next' with specific examples (save a view, set up an alert, share to Slack, drill down, compare periods). It also distinguishes itself from siblings like suggest_groupby and suggest_usage_metrics by focusing on follow-up actions rather than metrics or group-by suggestions.

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

Usage Guidelines4/5

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

The description provides explicit when-to-use guidance: 'Call this after investigation flows (after query or get) to present follow-up options to the user.' It gives concrete usage scenarios with the parameter examples, but does not explicitly mention when not to use it or contrast with alternatives, so it falls short of a 5.

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

suggest_groupbyA
Read-only
Inspect

Suggest the best dimensions to group costs by, based on an optional filterCel (CEL). Call this when the user asks "what should I look at?" or when you need columns for query or find_cost_change_factors. Prefer datePreset over from/to. Omit compare for current-window ranking. Pass compare ({} auto-derives, or { from, to }) when the user asks what changed — then pass 2–4 of the returned column names (max 8; { column, contains } for token columns, dropping metrics) into find_cost_change_factors. Returns { column } or { column, contains } plus metrics; do not invent columns. filterCel omitted or "" is unfiltered (not AWS-only). filterCel supports == null for unlabelled dimension values (e.g. cos_environment == null). EXAMPLES: • "What should I split last month's EC2 cost by?" → { datePreset: "LAST_MONTH", filterCel: "cos_service_name in ["AmazonEC2"]" } • "Costs of EC2 spiked last month, what should I investigate?" → { datePreset: "LAST_MONTH", compare: {}, filterCel: "cos_service_name in ["AmazonEC2"]" }

NameRequiredDescriptionDefault
toNoCurrent period end (YYYY-MM-DD), inclusive. Omit when using datePreset.
fromNoCurrent period start (YYYY-MM-DD). Omit when using datePreset.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
compareNoOptional reference (previous) period. Omit for current-window ranking. `{}` auto-derives from the current window (same helper as query). `{ from, to }` pins it. Prefer passing this when the user asks what changed, before find_cost_change_factors.
filterCelNoOptional CEL scope. Omit or "" for unfiltered (Billy where_clause TRUE). That is not an AWS-only filter even though columns_where_clause falls back to ["cos_provider"].
datePresetNo

TDQS

A4.9/5.0
Behavior5/5

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

The annotations already cover read-only and non-destructive behavior. The description adds meaningful behavioral context: return shape ({ column } or { column, contains } plus metrics), a 'do not invent columns' constraint, clarification that an omitted filter is unfiltered and not AWS-only, and support for == null on unlabelled dimension values. This is substantial beyond the structured fields.

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?

The description is long but dense and front-loaded with the core purpose and usage trigger. It earns most of its length with concrete examples and downstream routing, but some compare/filterCel guidance is duplicated from the schema descriptions and could be tightened.

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 tool with six parameters, one nested object, and no output schema, the description is remarkably complete: it covers parameter selection, return shape, filter semantics, examples, and how the result feeds into find_cost_change_factors. An agent has enough context to call it correctly without further inference.

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

Parameters5/5

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

Schema coverage is high at 83%, but the description still adds value beyond it: it explains when to pass compare, what {} auto-derives, why to prefer datePreset over from/to, and what filterCel null/unfiltered means. The examples further clarify realistic parameter combinations, especially the CEL syntax for service filtering.

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?

The description states a specific verb and resource: 'Suggest the best dimensions to group costs by.' It distinguishes itself from siblings by explicitly tying its output to query and find_cost_change_factors, and by framing the tool as the one to call when the user asks 'what should I look at?'.

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?

The description gives explicit trigger conditions: 'Call this when the user asks "what should I look at?" or when you need columns for query or find_cost_change_factors.' It also provides conditional guidance for compare, datePreset vs from/to, and downstream use, so an agent knows exactly when and how to invoke it.

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

suggest_usage_metricsA
Read-only
Inspect

Suggest usage metric units (e.g. k8s_cpu_hours, network_bytes_out) to analyze in the current billing context. Only use when a specific filterCel scope is provided; broad queries will return unhelpful results. filterCel supports == null for unlabelled dimension values (e.g. cos_environment == null). EXAMPLE: "What usage metrics make sense for our GCP compute spend?" → { filterCel: "cos_provider in ["GCP"]" }

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
filterCelNoOptional CEL filter to scope which rows are considered when discovering usage units. Same syntax as the explorer filter.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, so the tool is known to be safe. The description adds behavioral context: the warning that broad queries return unhelpful results and the detail that filterCel supports == null for unlabelled dimension values, which goes beyond the schema.

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

Conciseness5/5

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

The description is compact: two sentences plus an example. It is front-loaded with the core purpose, followed by usage guidance and a clarifying example. No wasted words.

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

Completeness4/5

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

The tool has no output schema, but the description covers what it does, when to use it, and includes an example. It does not detail the return format, but for a suggestion tool with no output schema this is acceptable. The annotations and sibling context provide enough completeness.

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%, but the description adds meaningful value by providing an example filterCel value ("cos_provider in [\"GCP\"]") and explaining the == null syntax for unlabelled dimension values. This enriches the parameter semantics beyond the schema alone.

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?

The description uses a specific verb 'Suggest' and resource 'usage metric units' with concrete examples (k8s_cpu_hours, network_bytes_out) to analyze in the current billing context. It clearly differentiates from sibling tools like suggest_actions or suggest_groupby by focusing on metric units in billing context.

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

Usage Guidelines4/5

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

The description explicitly states when to use ('Only use when a specific filterCel scope is provided') and warns against broad queries ('broad queries will return unhelpful results'). It does not name alternatives, but the condition is clear and actionable, with an example.

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

transfer_report_executionAInspect

Side effect: sends real messages now. Re-delivers an already-rendered successful execution without recomputing widgets. Destinations use the same shape as create_report: { destinationType: "SLACK" | "TEAMS", channelId } or { destinationType: "EMAIL", email }. Resolve channel ids with list_available_destinations. DANGER ZONE: list every target destination and ask the user to confirm before calling.

NameRequiredDescriptionDefault
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
executionIdYesReport execution id to re-deliver.
destinationsYesSame destination shape as create (1–10 targets). Resolve channels via `list_available_destinations`.

TDQS

A4.7/5.0
Behavior5/5

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

Beyond annotations (readOnlyHint=false, destructiveHint=false), the description explicitly states 'Side effect: sends real messages now' and includes a DANGER ZONE warning to list and confirm destinations. This adds crucial behavioral context about real-world impact and safety, going well beyond what annotations provide.

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

Conciseness5/5

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

The description is extremely concise and front-loaded, leading with the side-effect warning, then the core action, destination format, and a clear safety directive. Every sentence contributes operational value without waste.

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?

Given the tool's mutation nature and no output schema, the description is complete: it covers the action, side effect, destination format, a necessary prerequisite (list_available_destinations), and a mandatory user confirmation step. It leaves no significant gaps for safe invocation.

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?

The schema already has 100% coverage with detailed descriptions for all parameters. The description adds complementary value by noting the destination shape matches create_report and that channel ids must be resolved via list_available_destinations, reinforcing the schema's explainer and providing cross-tool guidance.

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?

The description clearly states the tool's function: 'Re-delivers an already-rendered successful execution without recomputing widgets.' This is a specific verb+resource pair that distinguishes it from sibling tools like retry_report_execution or run_report_now. The mention of 'sends real messages' also clarifies the real-world side effect, leaving no ambiguity about its purpose.

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

Usage Guidelines4/5

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

The description gives solid usage context: it is for re-delivering successful executions, references the destination shape from create_report, and instructs resolving channel ids via list_available_destinations. However, it does not explicitly mention alternatives or when not to use it, so it falls short of a 5.

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

update_alertA
Destructive
Inspect

Update an existing cost alert. Look up alertId via search / list_alerts / get / create_alert. All fields except alertId (and slug) are optional — omit a field to keep the stored value. Most edits (name, description, tagIds, condition, dedup) need nothing else. tagIds replaces the full list: existing IDs from list_tags and/or { name, color? } for new tags; color defaults to #6366F1; missing tags are created. Omit keeps stored tags; [] clears them. Explorer (queries + period) and notification dest are wholesale groups: if you send any field in the group, send the full group, written from scratch exactly as for create_alert — the stored queries from get are not a valid input. Inside the explorer group, omit scopeId to keep the alert's saved scope (send null to clear it); it cannot be sent on its own. scopeId is the same id as list_teams, stored on the alert (read it from get) and not merged into the stored queries. Do not send aggBy: the stored grain is always Day. Setting condition on a legacy threshold alert that has no dedup config succeeds but the response may include warning: pass dedup too (or in a follow-up call) to avoid notifying on every firing evaluation. Sharing is not this tool — use get_object_permissions then set_object_permissions with resourceKind "costAlert". EXAMPLE: rename → { alertId, name: "New name" } EXAMPLE: dest switch to Slack → { alertId, notificationChannel: "SLACK", slackChannelId: "C01ABC" } EXAMPLE: condition change → { alertId, condition: "a > 2000" } EXAMPLE: narrow the monitored series (scope kept) → { alertId, queries: [{ type: "cost", name: "a", metricId: "cost", currency: "USD", filterCel: "cos_provider in ["AWS"]" }], datePreset: "TRAILING_90_DAYS" }

NameRequiredDescriptionDefault
toNoExplicit window end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.
fromNoExplicit window start (YYYY-MM-DD). Use with to instead of datePreset.
nameNoDisplay name for the alert.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
dedupNoDeduplication config controlling how often a still-firing group notifies. The window is per groupBy value; delivery stays one message listing newly eligible groups. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days.
emailsNoEmail addresses (required if EMAIL)
tagIdsNoReplaces the full tag list. Omit to keep stored tags; pass [] to clear. Pass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1).
alertIdYesAlert ID from search, list_alerts, get, or create_alert.
queriesNoReplaces the monitored series wholesale, and `condition` references these `name`s. 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`. Write them from scratch: the stored `queries` returned by the `get` tool are a different, read-only shape.
scopeIdNoTeam scope id (list_teams), stored on the alert, not merged into query filters. A change still needs full queries plus period. Omit (with queries+period) to keep the saved scope; null clears it. Do not send scopeId alone.
conditionNoAlerts v3 firing rule: a single boolean expression over the query names (`name` field of each query). Supports arithmetic (+ - * /), comparisons (> >= < <= == !=), logical and/or/not, parentheses, and these window functions: rollingSum(a, N, UNIT) (trailing sum over the last N units, UNIT ∈ DAY|WEEK|MONTH, inclusive of today), weekToDateSum(a) (Monday-to-date), monthToDateSum(a) (1st-of-month-to-date), and timeShift(a, N, UNIT) (value shifted back N units; may wrap a window function). Examples: `a > 1000`, `rollingSum(a, 7, DAY) > 1000`, `(a - timeShift(a, 1, DAY)) / timeShift(a, 1, DAY) > 0.2`, `a > 10000 or rollingSum(a, 7, DAY) > 50000`.
datePresetNoOfficial date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to.
descriptionNoAlert description.
slackChannelIdNoSlack target id (required if SLACK): a channel id (C…) to post to a channel, or a Slack user id (U…) to deliver a direct message to that user. Use list_available_destinations to discover both channels and the signed-in user's DM.
teamsChannelIdNoTeams channel ID (required if TEAMS)
notificationChannelNoNotification channel

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already flag destructiveHint=true and openWorldHint=true, but the description adds genuinely non-obvious behavior: `tagIds` replaces the whole list (`[]` clears), `scopeId` cannot be sent alone and null clears it, `aggBy` must never be sent because stored grain is always Day, and a legacy alert edit can succeed while emitting a `warning` about per-firing notifications.

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?

It is long, but appropriately so for a 16-parameter destructive mutation tool. It is front-loaded with purpose and the alertId lookup, then rules, then four concrete call examples — only mild redundancy with the schema's own field descriptions prevents a 5.

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, destructive, annotation-covered mutation with no output schema, the description closes the gaps an agent needs: how to source alertId, which sibling handles sharing, group-atomicity rules, the Day grain constraint, and the `warning` that can appear in the response.

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 baseline is 3, but the description adds cross-field rules the schema cannot express: the wholesale-group rule for queries+period, the omit-vs-null distinction for scopeId, the ban on `aggBy`, and that `condition` references query `name`s. Some prose (e.g. tagIds, condition examples) duplicates the schema text, so it is not fully additive, but the field-interaction guidance is valuable.

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 ("Update an existing cost alert") and immediately routes the agent on how to obtain the required alertId (search / list_alerts / get / create_alert). This clearly separates it from sibling create_alert, list_alerts, and get without the agent opening any 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?

Explicitly states the omit-to-keep default semantics, which edits need no other fields, that Explorer and notification-destination are wholesale groups requiring a full write from scratch, and that the stored `queries` from get are not valid input. It also names the correct alternative for sharing (get_object_permissions then set_object_permissions) and warns about the legacy-threshold `warning` requiring `dedup`.

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

update_dashboardA
Destructive
Inspect

Update an existing dashboard's name, description, shared dashboardContext, widgets, and/or tags. Call get_skill with skillId: "dashboards" first — see skill for inheritance rules. Look up the dashboard id via search. Pass name and/or description to rename without recreating (empty description clears). Pass dashboardContext as a partial patch to edit the global filter (conditionsCel), period, groupBy, metricId, currency, or scopeId without recreating the dashboard — omit fields you want to keep; empty conditionsCel clears the filter. The legacy context alias is temporarily accepted but deprecated; never send both. Pass operations to add/replace/remove widgets. Pass tags to replace the full tag list (existing IDs from list_tags and/or { name, color? } for new tags; color defaults to #6366F1; missing tags are created). Omit keeps stored tags; [] clears. At least one of dashboardContext, operations, tags, name, or description is required. Sharing is not an update_dashboard field — use get_object_permissions / set_object_permissions. Response includes inheritedContext so new chart widgets can omit fields matching the dashboard. Cost series may omit metricId, currency, and groupBy. Usage requires metricId and has no currency; omit groupBy to inherit. Budget groupBy is explicit (the budget VD bqName) and does not inherit dashboardContext.groupBy. Both inherit period and conditionsCel. Hide formula inputs with visible: false. Text widgets: { type: "text", title, textContent }. Do not repeat from/to or datePreset when they match the dashboard context. Set extendDashboardConditions: false on the widget to ignore the dashboard filter, or on one cost/usage series to opt out just that series. Optional grid fields on add: x/y/w/h (from get). Returns a URL — you MUST include it in your response. EXAMPLES: see skill dashboards Workflow B (widgets) and Workflow D (context / global filter). • "Tag the AWS dashboard as infrastructure" (after list_tags returned tag id "tag_abc") → { dashboardId: "clx9aws", tags: ["tag_abc"] }

NameRequiredDescriptionDefault
nameNoDashboard title. Omit to keep.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagsNoComplete tag list to set on the dashboard (replaces current tags). Pass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1). Pass [] to clear all tags. Use `get` to read current tags before removing one. Optional; omit to leave tags unchanged.
contextNoDeprecated alias for `dashboardContext`; supported temporarily for backward compatibility. Do not send both fields.
operationsNoList of operations to apply atomically. Each op is "add" (append a new widget), "replace" (overwrite an existing widget in place), or "remove" (delete a widget). For add/replace, widgets inherit dashboard context by default; only pass per-widget overrides. Optional when `dashboardContext` or `tags` is provided. Example: [{"op":"add","widget":{"title":"Monthly cost","queries":[{"type":"cost","name":"a","chartType":"BAR"}],"aggBy":"Month"}}].
dashboardIdYesID of the DashboardV2 to mutate. Get it from `search` (V2 surface).
descriptionNoDashboard description. Omit to keep; empty string clears.
dashboardContextNoPartial patch for dashboard-level shared context (global filter, period, groupBy, metricId, currency, scopeId). Omitted fields keep their current values. Set `conditionsCel` to update/clear the global filter (empty string clears it). When changing period mode, null the unused side (`datePreset` vs `startDate`/`endDate`). Can be used alone or together with `operations` or `tags`.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare destructiveHint=true, and the description reinforces that with concrete destructive semantics (remove deletes a widget, tags replaces the full list, [] clears, empty description clears). It also adds non-annotation behavior: atomic operation application, the 'at least one field required' constraint (not in schema), and 'Returns a URL — you MUST include it in your response'. It does not cover auth/permission requirements, which tempers the score.

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

Conciseness3/5

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

Purpose and required-field guidance are reasonably front-loaded, but the body is a single dense paragraph of ~300 words mixing invocation rules, inheritance logic, and widget guidance. Most sentences earn their place, yet the lack of structure makes a complex spec harder to scan than it needs to be.

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 heavily nested 8-parameter mutation tool with no output schema, the description covers invocation, inheritance/override semantics, destructive side effects, the response URL obligation, and cross-references (get_skill, search, permissions siblings). Nothing an agent needs to call it correctly appears to be 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 description coverage is 100%, so the baseline is 3. The description still adds real meaning beyond the schema: inheritance rules for dashboardContext vs widget queries, the deprecated `context` alias and 'never send both', budget groupBy being explicit rather than inherited, and extendDashboardConditions opt-out behavior.

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 and enumerates the mutable fields ('Update an existing dashboard's name, description, shared dashboardContext, widgets, and/or tags'). This clearly distinguishes it from siblings (create_dashboard, update_report, update_alert) without needing to name them.

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?

Explicitly routes the agent: 'Call get_skill with skillId: "dashboards" first', 'Look up the dashboard id via search', and names a when-NOT with a concrete alternative ('Sharing is not an update_dashboard field — use get_object_permissions / set_object_permissions'). It also states the minimum required combination of fields, so the agent knows how to invoke it correctly.

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

update_eventA
Destructive
Inspect

Persist changes to an existing cost-chart annotation event already saved in Costory. This is a write (not a preview): it overwrites the event's name, date, description, tags, metadata, team scope, and/or the annotation chart in the database. It does not create a new event, does not send Slack/Teams/email, and does not archive or delete the event. Use list_events to find the event id first. All fields except eventId are optional — omit a field to keep the stored value. Metadata is merged into existing values; source is preserved on the event column and should not be supplied. Tags replace the full tag list. Name, date, description, tags, metadata, and scopeId need no widget.

scopeId (same id as list_teams) sets the event scope and leaves the chart unchanged. Omit it to keep the saved scope. null clears it. An id replaces it. If both scopeId and widget.scopeId are sent, scopeId wins.

widget replaces the annotation chart wholesale, or creates one if none exists. If you send widget, send the full chart on the first call, written from scratch exactly as for query: title, queries, and datePreset or from/to. Set chartType on every series (BAR, LINE, AREA, WATERFALL, or TABLE). Omitting it stores LINE and replaces the previous chart type. widget.scopeId alone is invalid. list_events returns chart id and title only, not the stored queries, so do not patch or echo the current chart. Omit widget to leave the chart unchanged. A full widget without widget.scopeId keeps the saved event scope unless top-level scopeId is set. widget.scopeId: null clears the event scope when top-level scopeId is omitted. If the event has multiple charts, pass widgetEventId. EXAMPLE: "Add a PR link to yesterday's deploy event" → { eventId: "clx9abc", metadata: { link: "https://github.com/acme/app/pull/99" } } EXAMPLE: "Fix the description on the migration event" → { eventId: "clx9abc", description: "Migrated prod cluster; temporary 2-day cost spike from dual-running nodes." } EXAMPLE: "Scope the migration event to the platform team" → { eventId: "clx9abc", scopeId: "" } EXAMPLE: "Clear the event scope" → { eventId: "clx9abc", scopeId: null }

NameRequiredDescriptionDefault
dateNoNew event date (YYYY-MM-DD).
nameNoNew event name.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
tagsNoReplace all tags on the event.
labelsNoDeprecated alias for tags. Ignored when tags is sent.
widgetNoAnnotation chart for the event. Same shape as the `query` tool (`queries`, `datePreset` or `from`/`to`, `aggBy`, `compare`, `limit`, `scopeId`) plus `title` and optional `description`. Providing a widget creates a visual annotation so the team can see which cost movement the event documents. On create: STRONGLY RECOMMENDED; omit only for truly org-wide events with no cost chart. On update: omit to leave the chart unchanged. If sent, widget is a full replacement (title, queries, and datePreset or from/to required; scopeId alone is invalid). Pass widgetEventId when the event has multiple charts.
eventIdYesEvent ID from list_events or create_event.
scopeIdNoEvent scope id from list_teams. Omit to keep the saved scope. null clears it. Does not change the chart. If widget.scopeId is also sent, this field wins.
categoryNoDeprecated. If sent, merged into tags then discarded.
metadataNoMetadata fields to merge into existing metadata (e.g. link, owner). Existing source is preserved.
descriptionNoNew description.
widgetEventIdNoID of the widgetEvent to update when the event has multiple annotation charts.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only declare destructiveHint=true and readOnlyHint=false; the description goes far beyond that by disclosing overwrite semantics per field, merge-vs-replace behavior (metadata merged, tags replace the full list, source preserved), omission meaning 'keep stored value', and the wholesale-replacement nature of the widget. This is exactly the extra behavioral context a mutation tool needs.

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?

Purpose and write-vs-preview caveat are front-loaded, and the worked examples make intent concrete. It is long, though justified by 12 parameters and nested objects, with some overlap between the top-level scopeId precedence sentence and the later widget/scopeId discussion that could be consolidated.

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 12-parameter mutation tool with a nested widget object and no output schema, the description covers defaults, replacement vs merge semantics, precedence rules, and cross-tool lookups (list_events, list_teams). Nothing an agent needs to call it correctly is missing.

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

Parameters5/5

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

Although schema coverage is 100% (baseline 3), the description adds semantics the schema does not: scopeId precedence over widget.scopeId, null-clears vs id-replaces behavior, the full-replacement requirement for widget including mandatory chartType on every series, and the requirement to pass widgetEventId for multi-chart events. These rules materially change how an agent fills the fields.

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

Purpose5/5

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

States a specific verb and resource ('Persist changes to an existing cost-chart annotation event'), and immediately disambiguates from siblings by declaring it is a write, not a preview, and does not create a new event (create_event), send notifications, or archive/delete (archive_object). An agent can route to it correctly without opening a 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?

Explicitly names prerequisites ('Use list_events to find the event id first') and enumerates when-not conditions: it does not create events, does not notify Slack/Teams/email, and does not archive or delete. It also names list_teams as the source of scope ids, giving concrete routing context.

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

update_reportA
Destructive
Inspect

Apply declarative partial changes to one non-archived report. Call get_skill with skillId: "reports" first when changing DIGEST content, schedule, destinations, or reportContext. Omitted fields are preserved. Pass reportContext as a partial patch to edit the report-wide period, groupBy, metricId, currency, scopeId, or conditionsCel without recreating widgets — omit fields you want to keep; empty conditionsCel clears the filter. The legacy context alias is temporarily accepted but deprecated; never send both. tagIds replaces the full list: existing IDs from list_tags and/or { name, color? } for new tags; color defaults to #6366F1; missing tags are created. Omit keeps stored tags; [] clears them. DANGER ZONE when changing schedule, widget, destinations, resuming to ACTIVE, or using schedule.mode NOW: summarize the merged future configuration and ask the user to confirm before calling. Pure pause plus metadata / reportContext edits can apply immediately. schedule.mode NOW converts to on-demand ACTIVE and sends immediately. Archived restore is forbidden in MCP. destinations replaces the full list (must be non-empty; omit to leave it unchanged). widgets (an array) replaces the report's entire widget list wholesale, with type inside each widget; omit widgets to leave the widgets unchanged. The input field is always widgets (array) — a singular widget key is silently ignored. EXAMPLE pause: { reportId: "clx…", state: "PAUSED" } EXAMPLE context patch: { reportId: "clx…", reportContext: { datePreset: "LAST_WEEK", groupBy: "cos_service_name" } }

NameRequiredDescriptionDefault
nameNoOptional name patch.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
stateNoACTIVE or PAUSED (MCP-facing status).
tagIdsNoReplaces the full tag list. Omit to keep stored tags; pass [] to clear. Pass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1).
contextNoDeprecated alias for `reportContext`; supported temporarily for backward compatibility. Do not send both fields.
widgetsNoWhen set, replaces the widget list wholesale; omit to leave unchanged. Same widget objects as `create_report` `widgets[]`.
reportIdYesReport id to patch.
scheduleNoOptional schedule replace. NOW / UNSCHEDULED / SCHEDULED (WEEKLY requires `weekday`).
descriptionNoOptional description patch.
destinationsNoWhen set, replaces the destination list wholesale; omit to leave unchanged (never empties it). Same destination objects as `create_report` `destinations`.
reportContextNoPartial patch for report-level shared context (same fields as `create_report` `reportContext`). Omitted fields keep their current values. Empty conditionsCel clears the filter. Can be used alone or together with `widgets`.

TDQS

A4.9/5.0
Behavior5/5

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

Goes well beyond the destructiveHint/openWorldHint annotations: declares replace-vs-preserve semantics for tagIds, destinations, widgets, that omitted fields are preserved, that empty conditionsCel clears the filter, that schedule.mode NOW sends immediately, that archived restore is forbidden in MCP, and that a singular `widget` key is silently ignored. This is exactly the behavioral context a destructive mutation tool needs.

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?

Front-loads the verb and resource, then prerequisites, then the DANGER ZONE, then worked examples at the end. It is dense and some sentences run together, but for an 11-parameter destructive patch tool nearly every clause earns its place.

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 destructive mutation with nested widget/destination objects and no output schema, the description covers mutation semantics, safety/confirmation flow, deprecations, and example payloads. An agent has what it needs to call it correctly without opening the schema.

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

Parameters5/5

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

Schema coverage is already 100%, yet the description adds meaning the schema doesn't carry: reportContext as a partial patch (omit to keep, empty conditionsCel clears), tagIds replaces the full list with color default #6366F1 and auto-creation, destinations must be non-empty, widgets replace wholesale with type inside each widget, and the legacy `context` alias must never be co-sent. Genuine value beyond structured fields.

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

Purpose5/5

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

States a specific verb and resource ("Apply declarative partial changes to one non-archived report") and scopes it (non-archived). It is immediately distinguishable from create_report, archive_report, and update_dashboard.

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?

Explicitly names the prerequisite (call get_skill with skillId: "reports" before changing DIGEST/schedule/destinations/reportContext) and gives conditional routing (DANGER ZONE operations require user confirmation, pure pause + metadata edits apply immediately). It also names supporting reads like list_tags and list_teams, leaving little to inference.

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

update_virtual_dimension_draftA
Destructive
Inspect

Upsert the virtual dimension draft for an existing virtualDimensionId — updates a pending draft or seeds one from published state when none exists (response may include warning: "Initialized draft from published state"). virtualDimensionId in inputs equals id from list/get/search. Use create_virtual_dimension_draft only for brand-new VDIMs. Call get_skill with skillId: "virtual-dimensions" first — see skill for allocation shapes and workflow. For a new telemetry allocation, discover a live integration metric via list_metrics with includeExternal: true and a specific search term, then persist inline externalMetric { provider, integrationId, metricName, aggregator, groupByFields }. For BigQuery/S3, also set dateColumn and metricColumn from the returned schema (first DATE / first NUMERIC) and gapFillingMethod (default FORWARD_FILL). Catalog-complete providers (Tsuga, Datadog, CloudWatch, Amplitude, Google Cloud Monitoring) do not need those fields. Do not set datasource on new reallocations (echo a leftover stored datasource unchanged unless the user asks to switch). bqName is immutable; use returned bqName for groupBy/filterCel in query. Declarative: rules is optional — omit to change only metadata (name, description, tagNames); when provided, fully replaces the rules array. Omitting rules on a published-only VDIM still persists a draft (metadata-only promotion). Carry forward each existing rule's id and allocation from get; ids are sticky — reorder by moving id with its rule. Do not include leftover in rules. Rejects invalid payloads — nothing persisted unless validation passes. On success: values, draftValidation: { ok: true }, draftPersisted: true. Does not publish or refresh BigQuery. Clerk MCP only. EXAMPLE: "Add staging to Environment VDIM" — rules is the full desired set → { virtualDimensionId: "<id from create/list>", rules: [{ id: "", name: "Production", conditionCel: "cos_environment in ["prod"]", allocation: { allocationType: "dimensionValue", dimensionValue: "prod" } }, { name: "Staging", conditionCel: "cos_environment in ["staging"]", allocation: { allocationType: "dimensionValue", dimensionValue: "staging" } }] }

NameRequiredDescriptionDefault
nameNoOptional rename for the draft.
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
rulesNoFull desired ordered rules array (declarative, not diffs). Omit to keep the current draft rules unchanged and edit only name/description/tags. Omitting rules on a published-only VDIM still persists a draft (metadata-only promotion path).
tagNamesNoReplace tags when provided (created if missing)
descriptionNoOptional draft description patch.
virtualDimensionIdYesVirtual dimension id (stable public identifier)

TDQS

A4.7/5.0
Behavior5/5

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

Annotations say only readOnly=false/destructive=true/openWorld=false; the description adds the specific destructive semantics that matter — `rules` is declarative and "fully replaces the rules array," leftover rules must be excluded, rule `id`s are sticky, invalid payloads persist nothing, and the operation "Does not publish or refresh BigQuery." It also discloses the success payload and the possible `warning: "Initialized draft from published state"`, none of which the annotations carry.

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

Conciseness3/5

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

Purpose and sibling routing are correctly front-loaded, but the body is a very dense run-on that re-states large blocks already present verbatim in the schema's `allocation` description (datasource handling, BigQuery/S3 columns, mapping/regex/identity rules). The embedded example is useful but the duplication means not every sentence earns its place.

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 upsert with a deeply nested declarative schema and no output schema, the description supplies the workflow, prerequisites, validation behavior, and the success-response shape (`values`, `draftValidation: { ok: true }`, `draftPersisted: true`). Nothing an agent needs to call it correctly 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 baseline is 3, but the description adds real meaning beyond the schema: `virtualDimensionId` equals `id` from list/get/search, `bqName` is immutable, and the declarative-`rules`/id-stickiness contract governs how the array must be constructed. Some of this duplicates the schema's own allocation prose, which keeps it out of the top band.

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 precise verb+resource+scope: "Upsert the virtual dimension draft for an existing `virtualDimensionId` — updates a pending draft or seeds one from published state when none exists." It explicitly separates itself from the sibling create_virtual_dimension_draft ("only for brand-new VDIMs"), so an agent can route between the two without opening either 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?

Gives explicit when-to-use (existing ID, pending vs. published-only), when-not (brand-new VDIMs → create_virtual_dimension_draft), prerequisites (get_skill with skillId "virtual-dimensions" first), and downstream alternatives (list_metrics with includeExternal:true to discover a metric). It also states the metadata-only path (omit `rules`), which is a real selection decision an agent must make.

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

virtual_dimension_overlap_matrixA
Read-only
Inspect

Compute a lower-triangular overlap matrix for ordered virtual dimension rules (read-only). virtualDimensionId in inputs equals id from list/get/search. When includeDraft is true (default), operates on the latest pending draft if one exists (draftPersisted: true); otherwise analyzes published rules in memory without creating a draft (draftPersisted: false — not publishable). Set includeDraft false to force published order regardless. Trailing 30 days when from/to are omitted (optional from/to override the window). Returns overlaps for all named rules (excludes leftover). position (from get) and ruleIndex (here) refer to the same 0-based ordinal; ordered rules are [...rules, leftover] with leftover at index rules.length (excluded from this matrix). Returns overlaps[{ ruleId, ruleTargetId, ruleIndex, ruleTargetIndex, overlapCost }] where ruleTargetIndex <= ruleIndex. Diagonal entries (ruleId = ruleTargetId) are each rule's raw membership cost; off-diagonal entries are shared spend shadowed by the earlier rule. costMetric selects the cost column (default cost); valid ids: cost, effective_cost, list_cost, contracted_cost (also accepts contracted_costs), unblended_cost, net_unblended_cost, amortized_cost, net_amortized_cost. EXAMPLE: "Show rule overlap for Environment VDIM" → { virtualDimensionId: "<virtualDimensionId from create/list>" }

NameRequiredDescriptionDefault
toNoOptional window end (YYYY-MM-DD); must be set together with `from`
fromNoOptional window start (YYYY-MM-DD); must be set together with `to`
slugNoOrganization slug. Omit to auto-detect from your account (fails if you belong to multiple orgs).
costMetricNoCost column id (default cost). Valid: cost, effective_cost, list_cost, contracted_cost, unblended_cost, net_unblended_cost, amortized_cost, net_amortized_cost (also accepts contracted_costs → contracted_cost).
includeDraftNoUse latest draft rules when true; published rules when false
virtualDimensionIdYesVirtual dimension id (stable public identifier)

TDQS

A4.8/5.0
Behavior5/5

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

The description richly discloses behavioral details beyond annotations: draft handling with draftPersisted flag, in-memory analysis without creating a draft, trailing 30-day default window, exclusion of leftover rules, index mapping (position vs ruleIndex), and matrix diagonal/off-diagonal semantics. This goes far beyond the readOnlyHint annotation.

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

Conciseness5/5

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

Despite being lengthy, the description is front-loaded with the core purpose and structured logically. Every sentence adds critical information (draft behavior, return format, examples, metric options) without redundancy. The example at the end aids comprehension without bloating the text.

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?

Given no output schema, the description fully specifies the return structure (overlaps array with ruleId, ruleTargetId, ruleIndex, ruleTargetIndex, overlapCost) and explains diagonal/off-diagonal semantics. It also covers default time window and costMetric options, making the tool's behavior completely understandable for an agent.

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

Parameters5/5

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

Adds substantial meaning beyond schema: correlates virtualDimensionId with 'id' from list/get/search, explains includeDraft's effect on draft persistence, clarifies that from/to default to trailing 30 days, and details the costMetric valid values (including alias). Every parameter's purpose is enriched.

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?

The description clearly states the tool's function with a specific verb and resource: 'Compute a lower-triangular overlap matrix for ordered virtual dimension rules.' It also clarifies the read-only nature and includes an example, distinguishing it from sibling tools that manage or retrieve virtual dimensions.

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

Usage Guidelines4/5

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

Provides clear context on when to use the tool (computing overlap matrices) and explains parameter behavior like includeDraft and time window defaults. However, it does not explicitly name alternatives or state when not to use this tool, though the unique purpose makes alternatives obvious.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updates
    • Changedcreate_report1 field changed
      • changedInput schema / properties / widgets / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "queries": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        -        "maximum": 100,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "queries": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      },
        +      "useDashboardGroupBy": {
        +        "default": true,
        +        "description": "Use `reportContext.groupBy` as this DIGEST's root group-by (default true). Set false to override: the report context group-by is ignored for this widget and the first `additionalGroupBy` item (or `queries[0].groupBy`) becomes the root. `false` requires at least one dimension (a non-empty `additionalGroupBy` or a `queries[0].groupBy`). Example: useDashboardGroupBy: false + additionalGroupBy: [\"cos_namespace_reallocated\",\"cos_workload_name\"] → root cos_namespace_reallocated, report context key ignored for this widget only.",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedpreview_report_widget1 field changed
      • changedInput schema / properties / widget / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "queries": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        -        "maximum": 100,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "queries": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      },
        +      "useDashboardGroupBy": {
        +        "default": true,
        +        "description": "Use `reportContext.groupBy` as this DIGEST's root group-by (default true). Set false to override: the report context group-by is ignored for this widget and the first `additionalGroupBy` item (or `queries[0].groupBy`) becomes the root. `false` requires at least one dimension (a non-empty `additionalGroupBy` or a `queries[0].groupBy`). Example: useDashboardGroupBy: false + additionalGroupBy: [\"cos_namespace_reallocated\",\"cos_workload_name\"] → root cos_namespace_reallocated, report context key ignored for this widget only.",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_report1 field changed
      • changedInput schema / properties / widgets / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "queries": {
        -        "$ref": "#/definitions/ReportMcpQueries"
        -      },
        -      "scopeId": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        -      },
        -      "title": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        -        "maximum": 100,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "queries": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      },
        +      "useDashboardGroupBy": {
        +        "default": true,
        +        "description": "Use `reportContext.groupBy` as this DIGEST's root group-by (default true). Set false to override: the report context group-by is ignored for this widget and the first `additionalGroupBy` item (or `queries[0].groupBy`) becomes the root. `false` requires at least one dimension (a non-empty `additionalGroupBy` or a `queries[0].groupBy`). Example: useDashboardGroupBy: false + additionalGroupBy: [\"cos_namespace_reallocated\",\"cos_workload_name\"] → root cos_namespace_reallocated, report context key ignored for this widget only.",
        +        "type": "boolean"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
  2. 6 tool updates
    • Changedcreate_dashboard1 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"
        +  }
        +]
    • Changedcreate_report1 field changed
      • changedInput schema / definitions / ReportMcpQueries / description
        Previous value: -"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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports."New value: +"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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Budget groupBy is explicit (budget VD bqName); it does not inherit reportContext.groupBy. Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports."
    • Changedpreview_report_widget1 field changed
      • changedInput schema / definitions / ReportMcpQueries / description
        Previous value: -"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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports."New value: +"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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Budget groupBy is explicit (budget VD bqName); it does not inherit reportContext.groupBy. Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports."
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "unitOverride": {
        -        "description": "Optional unit override. Omit to infer from formula inputs. Currency codes (EUR, USD, GBP, CNY, KRW) format as money and follow the widget/dashboard currency; any other string (e.g. \"slot-h/TiB\", \"%\") is displayed as-is.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY",
        +          "KRW"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "unitOverride": {
        +        "description": "Optional unit override. Omit to infer from formula inputs. Currency codes (EUR, USD, GBP, CNY, KRW) format as money and follow the widget/dashboard currency; any other string (e.g. \"slot-h/TiB\", \"%\") is displayed as-is.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }. Optional groupBy (the budget virtual dimension bqName from get) splits one series per budget line; omit for the total. Sibling cost/usage/metric groupBy must be that same field so formulas like a - b match per line.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Split by budget line. Must be this budget's virtual dimension bqName from get. Omit for the total. Sibling cost/usage/metric groupBy must be that same field so formulas match per line."
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_dashboard1 field changed
      • changedInput schema / properties / operations / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "add",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "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"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "op"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "replace",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "additionalProperties": {},
        -        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to overwrite (keeps its position).",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId",
        -      "widget"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "remove",
        -        "type": "string"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to delete.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "add",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "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"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "op"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "replace",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "additionalProperties": {},
        +        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to overwrite (keeps its position).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId",
        +      "widget"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "remove",
        +        "type": "string"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to delete.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_report1 field changed
      • changedInput schema / definitions / ReportMcpQueries / description
        Previous value: -"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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports."New value: +"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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Budget groupBy is explicit (budget VD bqName); it does not inherit reportContext.groupBy. Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports."
  3. 6 tool updates
    • Changedcreate_dashboard4 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"
        +  }
        +]
    • Changedcreate_report9 fields changed
      • addedInput schema / definitions
        Added value: +{
        +  "ReportMcpContext": {
        +    "properties": {
        +      "conditionsCel": {
        +        "description": "Report-wide CEL filter merged into cost and usage widgets. Omit or empty string for no report-level filter.",
        +        "type": "string"
        +      },
        +      "currency": {
        +        "anyOf": [
        +          {
        +            "enum": [
        +              "USD",
        +              "EUR",
        +              "GBP",
        +              "CNY",
        +              "KRW"
        +            ],
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        +      },
        +      "endDate": {
        +        "anyOf": [
        +          {
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        +      },
        +      "metricId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Default metric inherited by widget cost queries that omit `metricId`."
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        +      },
        +      "startDate": {
        +        "anyOf": [
        +          {
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "ReportMcpQueries": {
        +    "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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports.",
        +    "items": {
        +      "additionalProperties": {},
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "type": "array"
        +  }
        +}
      • addedInput schema / properties / context / allOf
        Added value: +[
        +  {
        +    "$ref": "#/definitions/ReportMcpContext"
        +  }
        +]
      • removedInput schema / properties / context / properties
        Removed value: -{
        -  "conditionsCel": {
        -    "description": "Report-wide CEL filter merged into cost widgets. Omit or empty string for no report-level filter.",
        -    "type": "string"
        -  },
        -  "currency": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        -  },
        -  "endDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "groupBy": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        -  },
        -  "metricId": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default metric inherited by widget cost queries that omit `metricId`."
        -  },
        -  "scopeId": {
        -    "anyOf": [
        -      {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        -  },
        -  "startDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        -  }
        -}
      • removedInput schema / properties / context / type
        Removed value: -"object"
      • addedInput schema / properties / reportContext / allOf
        Added value: +[
        +  {
        +    "$ref": "#/definitions/ReportMcpContext"
        +  }
        +]
      • removedInput schema / properties / reportContext / properties
        Removed value: -{
        -  "conditionsCel": {
        -    "description": "Report-wide CEL filter merged into cost widgets. Omit or empty string for no report-level filter.",
        -    "type": "string"
        -  },
        -  "currency": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        -  },
        -  "endDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "groupBy": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        -  },
        -  "metricId": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default metric inherited by widget cost queries that omit `metricId`."
        -  },
        -  "scopeId": {
        -    "anyOf": [
        -      {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        -  },
        -  "startDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        -  }
        -}
      • removedInput schema / properties / reportContext / type
        Removed value: -"object"
      • changedInput schema / properties / widgets / description
        Previous value: -"One or more report widgets (DIGEST / GRAPH_SNAPSHOT / TOP_FLOP / TEXT / DASHBOARD_PDF). For query-backed widgets prefer sparse cost `queries` and inherit period / groupBy / metricId / currency from `reportContext`. Call get_skill skillId: \"reports\" for examples."New value: +"One or more report widgets (DIGEST / GRAPH_SNAPSHOT / TOP_FLOP / TEXT / DASHBOARD_PDF). Call get_skill skillId: \"reports\" for examples."
      • changedInput schema / properties / widgets / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        -        "maximum": 100,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "queries": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedpreview_report_widget8 fields changed
      • addedInput schema / definitions
        Added value: +{
        +  "ReportMcpContext": {
        +    "properties": {
        +      "conditionsCel": {
        +        "description": "Report-wide CEL filter merged into cost and usage widgets. Omit or empty string for no report-level filter.",
        +        "type": "string"
        +      },
        +      "currency": {
        +        "anyOf": [
        +          {
        +            "enum": [
        +              "USD",
        +              "EUR",
        +              "GBP",
        +              "CNY",
        +              "KRW"
        +            ],
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        +      },
        +      "endDate": {
        +        "anyOf": [
        +          {
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        +      },
        +      "metricId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Default metric inherited by widget cost queries that omit `metricId`."
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        +      },
        +      "startDate": {
        +        "anyOf": [
        +          {
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "ReportMcpQueries": {
        +    "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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports.",
        +    "items": {
        +      "additionalProperties": {},
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "type": "array"
        +  }
        +}
      • addedInput schema / properties / context / allOf
        Added value: +[
        +  {
        +    "$ref": "#/definitions/ReportMcpContext"
        +  }
        +]
      • removedInput schema / properties / context / properties
        Removed value: -{
        -  "conditionsCel": {
        -    "description": "Report-wide CEL filter merged into cost widgets. Omit or empty string for no report-level filter.",
        -    "type": "string"
        -  },
        -  "currency": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        -  },
        -  "endDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "groupBy": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        -  },
        -  "metricId": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default metric inherited by widget cost queries that omit `metricId`."
        -  },
        -  "scopeId": {
        -    "anyOf": [
        -      {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        -  },
        -  "startDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        -  }
        -}
      • removedInput schema / properties / context / type
        Removed value: -"object"
      • addedInput schema / properties / reportContext / allOf
        Added value: +[
        +  {
        +    "$ref": "#/definitions/ReportMcpContext"
        +  }
        +]
      • removedInput schema / properties / reportContext / properties
        Removed value: -{
        -  "conditionsCel": {
        -    "description": "Report-wide CEL filter merged into cost widgets. Omit or empty string for no report-level filter.",
        -    "type": "string"
        -  },
        -  "currency": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        -  },
        -  "endDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "groupBy": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        -  },
        -  "metricId": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default metric inherited by widget cost queries that omit `metricId`."
        -  },
        -  "scopeId": {
        -    "anyOf": [
        -      {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        -  },
        -  "startDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        -  }
        -}
      • removedInput schema / properties / reportContext / type
        Removed value: -"object"
      • changedInput schema / properties / widget / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        -        "maximum": 100,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "queries": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedquery2 fields changed
      • addedInput schema / properties / displayOptions
        Added value: +{
        +  "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"
        +}
      • changedInput schema / properties / limit / description
        Previous value: -"Max groups/rows per series. Omit to use the default (100). Increase up to 1000 when you need more than 100 breakdown groups."New value: +"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."
    • Changedupdate_dashboard5 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 / 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."
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "Dashboard description. Omit to keep; empty string clears.",
        +  "type": "string"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Dashboard title. Omit to keep.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • changedInput schema / properties / operations / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "add",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "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"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "op"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "replace",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "additionalProperties": {},
        -        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to overwrite (keeps its position).",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId",
        -      "widget"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "remove",
        -        "type": "string"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to delete.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "add",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "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"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "op"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "replace",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "additionalProperties": {},
        +        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to overwrite (keeps its position).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId",
        +      "widget"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "remove",
        +        "type": "string"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to delete.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_report8 fields changed
      • addedInput schema / definitions
        Added value: +{
        +  "ReportMcpContext": {
        +    "properties": {
        +      "conditionsCel": {
        +        "description": "Report-wide CEL filter merged into cost and usage widgets. Omit or empty string for no report-level filter.",
        +        "type": "string"
        +      },
        +      "currency": {
        +        "anyOf": [
        +          {
        +            "enum": [
        +              "USD",
        +              "EUR",
        +              "GBP",
        +              "CNY",
        +              "KRW"
        +            ],
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        +      },
        +      "endDate": {
        +        "anyOf": [
        +          {
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        +      },
        +      "metricId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Default metric inherited by widget cost queries that omit `metricId`."
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "type": "null"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        +      },
        +      "startDate": {
        +        "anyOf": [
        +          {
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        +      }
        +    },
        +    "type": "object"
        +  },
        +  "ReportMcpQueries": {
        +    "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 inherits metricId/currency/groupBy from reportContext; usage requires metricId (omit groupBy = ungrouped). Cost/usage inherit conditionsCel. `visible: false` hides a series. DIGEST: one cost query. See skill reports.",
        +    "items": {
        +      "additionalProperties": {},
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "type": "array"
        +  }
        +}
      • addedInput schema / properties / context / allOf
        Added value: +[
        +  {
        +    "$ref": "#/definitions/ReportMcpContext"
        +  }
        +]
      • removedInput schema / properties / context / properties
        Removed value: -{
        -  "conditionsCel": {
        -    "description": "Report-wide CEL filter merged into cost widgets. Omit or empty string for no report-level filter.",
        -    "type": "string"
        -  },
        -  "currency": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        -  },
        -  "endDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "groupBy": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        -  },
        -  "metricId": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default metric inherited by widget cost queries that omit `metricId`."
        -  },
        -  "scopeId": {
        -    "anyOf": [
        -      {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        -  },
        -  "startDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        -  }
        -}
      • removedInput schema / properties / context / type
        Removed value: -"object"
      • addedInput schema / properties / reportContext / allOf
        Added value: +[
        +  {
        +    "$ref": "#/definitions/ReportMcpContext"
        +  }
        +]
      • removedInput schema / properties / reportContext / properties
        Removed value: -{
        -  "conditionsCel": {
        -    "description": "Report-wide CEL filter merged into cost widgets. Omit or empty string for no report-level filter.",
        -    "type": "string"
        -  },
        -  "currency": {
        -    "anyOf": [
        -      {
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "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": "Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
        -  },
        -  "endDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  "groupBy": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default group-by axis inherited by widgets that omit `groupBy`. For DIGEST, this is the root hierarchy axis — put deeper levels in `additionalGroupBy`."
        -  },
        -  "metricId": {
        -    "anyOf": [
        -      {
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Default metric inherited by widget cost queries that omit `metricId`."
        -  },
        -  "scopeId": {
        -    "anyOf": [
        -      {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Optional saved team scope id (from list_teams). Applied report-wide unless a widget overrides."
        -  },
        -  "startDate": {
        -    "anyOf": [
        -      {
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ],
        -    "description": "Used only when `datePreset` is null; ISO date (YYYY-MM-DD)."
        -  }
        -}
      • removedInput schema / properties / reportContext / type
        Removed value: -"object"
      • changedInput schema / properties / widgets / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 100,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        -        "maximum": 100,
        -        "minimum": 1,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "queries": {
        +        "$ref": "#/definitions/ReportMcpQueries"
        +      },
        +      "scopeId": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."
        +      },
        +      "title": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
  4. 8 tool updates
    • Changedcreate_alert1 field changed
      • changedInput schema / properties / datePreset / description
        Previous value: -"Official date preset (same DatePreset as dashboards/reports, e.g. MTD, LAST_MONTH, TRAILING_30_DAYS). Prefer this over hand-computed from/to when a preset matches. Mutually exclusive with from/to."New value: +"Official date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to."
    • Changedcreate_dashboard2 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."
    • Changedcreate_report2 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."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
      • changedInput schema / properties / reportContext / 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."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
    • Changedpreview_report_widget2 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."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
      • changedInput schema / properties / reportContext / 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."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
    • Changedquery3 fields changed
      • changedInput schema / properties / datePreset / description
        Previous value: -"Official date preset (same DatePreset as dashboards/reports, e.g. MTD, LAST_MONTH, TRAILING_30_DAYS). Prefer this over hand-computed from/to when a preset matches. Mutually exclusive with from/to."New value: +"Official date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to."
      • removedInput schema / properties / forecastDays
        Removed value: -{
        -  "description": "Extend the query window by N days into the future and include forecasted values.",
        -  "maximum": 9007199254740991,
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY",
        +          "KRW"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "unitOverride": {
        +        "description": "Optional unit override. Omit to infer from formula inputs. Currency codes (EUR, USD, GBP, CNY, KRW) format as money and follow the widget/dashboard currency; any other string (e.g. \"slot-h/TiB\", \"%\") is displayed as-is.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_alert1 field changed
      • changedInput schema / properties / datePreset / description
        Previous value: -"Official date preset (same DatePreset as dashboards/reports, e.g. MTD, LAST_MONTH, TRAILING_30_DAYS). Prefer this over hand-computed from/to when a preset matches. Mutually exclusive with from/to."New value: +"Official date preset (same as Explore, e.g. MTD, LAST_MONTH). Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Mutually exclusive with from/to."
    • Changedupdate_dashboard2 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."
    • Changedupdate_report2 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."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
      • changedInput schema / properties / reportContext / 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."New value: +"Default date preset inherited when a widget omits date fields. Forecast: CURRENT_MONTH / CURRENT_QUARTER / CURRENT_YEAR. Prefer this over startDate/endDate."
  5. 2 tool updates
    • Changedget1 field changed
      • changedInput schema / properties / id / description
        Previous value: -"ID of a V2 dashboard, budget, cost alert, report, virtual dimension, or BigQuery job (from search / list tools). For budgets, pass parent budget id or budget version id. For BigQuery jobs, pass the canonical `<project>:<location>.<job_id>` id. Response includes a `type` discriminator: dashboard | budget | costAlert | report | virtualDimension | bigquery_job."New value: +"ID of a V2 dashboard, budget, cost alert, report, virtual dimension, or BigQuery job (from search / list tools). For budgets, pass parent budget id or budget version id. For BigQuery jobs, pass `<project>:<location>.<job_id>` — location is case-insensitive. Response includes a `type` discriminator: dashboard | budget | costAlert | report | virtualDimension | bigquery_job."
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics / list_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and  For BigQuery jobs: set provider: \"bigqueryJobs\"; metricName is one of bq_slot_ms, bq_bytes_billed, bq_bytes_processed, bq_duration_ms, bq_job_count (values read from the enriched BigQuery billing rows — requires the org's BigQuery jobs integration); scope with filterCel like cost (never conditions); groupByFields are the bq_* billing dimensions (bq_user_email, bq_query_hash, bq_destination_table, bq_referenced_tables, bq_statement_type, bq_job_type, bq_error_reason, bq_reservation_id, bq_parent_job_id).",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "whereClause": {
        -        "additionalProperties": {},
        -        "properties": {},
        -        "type": "object"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY",
        +          "KRW"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
  6. 2 tool updates
    • Changedget2 fields changed
      • changedInput schema / properties / id / description
        Previous value: -"ID of a V2 dashboard, budget, cost alert, report, or virtual dimension (from search / list tools). For budgets, pass parent budget id or budget version id. Response includes a `type` discriminator: dashboard | budget | costAlert | report | virtualDimension."New value: +"ID of a V2 dashboard, budget, cost alert, report, virtual dimension, or BigQuery job (from search / list tools). For budgets, pass parent budget id or budget version id. For BigQuery jobs, pass the canonical `<project>:<location>.<job_id>` id. Response includes a `type` discriminator: dashboard | budget | costAlert | report | virtualDimension | bigquery_job."
      • addedInput schema / properties / type
        Added value: +{
        +  "description": "Restrict the lookup to one resource type. Omit to try every type; a BigQuery job id is also auto-detected from its `<project>:<location>.<job_id>` shape.",
        +  "enum": [
        +    "dashboard",
        +    "budget",
        +    "costAlert",
        +    "report",
        +    "virtualDimension",
        +    "bigquery_job"
        +  ],
        +  "type": "string"
        +}
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY",
        -          "KRW"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY",
        +          "KRW"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics / list_usage_metrics). Either a billing consumed_unit (e.g. \"hours\") or an enrichment metric column published by an integration — those start with `query_` (e.g. query_compute_ms, query_bytes_billed) and are only available to orgs with that integration. Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and  For BigQuery jobs: set provider: \"bigqueryJobs\"; metricName is one of bq_slot_ms, bq_bytes_billed, bq_bytes_processed, bq_duration_ms, bq_job_count (values read from the enriched BigQuery billing rows — requires the org's BigQuery jobs integration); scope with filterCel like cost (never conditions); groupByFields are the bq_* billing dimensions (bq_user_email, bq_query_hash, bq_destination_table, bq_referenced_tables, bq_statement_type, bq_job_type, bq_error_reason, bq_reservation_id, bq_parent_job_id).",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "whereClause": {
        +        "additionalProperties": {},
        +        "properties": {},
        +        "type": "object"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
  7. 11 tool updates
    • Changedcreate_dashboard2 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"
        +  }
        +]
    • Changedcreate_report2 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 / reportContext / 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"
        +  }
        +]
    • Addedlist_dimension_candidates
    • Addedlist_label_dimension_usages
    • Addedlist_label_dimensions
    • Changedpreview_report_widget2 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 / reportContext / 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"
        +  }
        +]
    • Changedpreview_virtual_dimension_draft1 field changed
      • changedInput schema / properties / currency / enum
        Previous value: -[
        -  "USD",
        -  "EUR",
        -  "GBP",
        -  "CNY"
        -]New value: +[
        +  "USD",
        +  "EUR",
        +  "GBP",
        +  "CNY",
        +  "KRW"
        +]
    • Addedpublish_label_dimensions
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY",
        +          "KRW"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_dashboard2 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"
        +  }
        +]
    • Changedupdate_report2 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 / reportContext / 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"
        +  }
        +]
  8. 1 tool update
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional BigQuery WHERE predicate ANDed with the date range. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required; conditions is the same optional WHERE predicate. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names; conditions is an optional Snowflake WHERE predicate ANDed with the date range (e.g. PRIMARY_PROVIDER_AND_MODEL RLIKE 'azure-.*/doctor-ai.*'). BigQuery, S3, and Snowflake conditions are appended as AND (…); statement separators, comments, and unbalanced quotes/parentheses outside string literals are rejected.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
  9. 1 tool update
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
  10. 5 tool updates
    • Addedarchive_object
    • Changedcreate_alert1 field changed
      • changedInput schema / properties / scopeId / description
        Previous value: -"Optional saved team scope id (from list_teams). Merges the scope whereClause into cost/usage queries."New value: +"Team scope id (list_teams). Stored on the alert, not merged into query filters. Omit for no scope."
    • Changedcreate_event1 field changed
      • changedInput schema / properties / widget / description
        Previous value: -"Annotation chart for the event. Same shape as the `query` tool (`queries`, `datePreset` or `from`/`to`, `aggBy`, `compare`, `limit`, `scopeId`) plus `title` and optional `description`. Providing a widget creates a visual annotation so the team can see which cost movement the event documents. On create: STRONGLY RECOMMENDED; omit only for truly org-wide events with no cost chart. On update: omit to leave existing annotation charts unchanged; pass widgetEventId when the event has multiple charts."New value: +"Annotation chart for the event. Same shape as the `query` tool (`queries`, `datePreset` or `from`/`to`, `aggBy`, `compare`, `limit`, `scopeId`) plus `title` and optional `description`. Providing a widget creates a visual annotation so the team can see which cost movement the event documents. On create: STRONGLY RECOMMENDED; omit only for truly org-wide events with no cost chart. On update: omit to leave the chart unchanged. If sent, widget is a full replacement (title, queries, and datePreset or from/to required; scopeId alone is invalid). Pass widgetEventId when the event has multiple charts."
    • Changedupdate_alert1 field changed
      • changedInput schema / properties / scopeId / description
        Previous value: -"Saved team scope id (from list_teams). Changing it still requires complete queries plus period. Omit (with queries+period) to keep the saved scope; send null to clear. Do not send scopeId alone."New value: +"Team scope id (list_teams), stored on the alert, not merged into query filters. A change still needs full queries plus period. Omit (with queries+period) to keep the saved scope; null clears it. Do not send scopeId alone."
    • Changedupdate_event2 fields changed
      • addedInput schema / properties / scopeId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Event scope id from list_teams. Omit to keep the saved scope. null clears it. Does not change the chart. If widget.scopeId is also sent, this field wins."
        +}
      • changedInput schema / properties / widget / description
        Previous value: -"Annotation chart for the event. Same shape as the `query` tool (`queries`, `datePreset` or `from`/`to`, `aggBy`, `compare`, `limit`, `scopeId`) plus `title` and optional `description`. Providing a widget creates a visual annotation so the team can see which cost movement the event documents. On create: STRONGLY RECOMMENDED; omit only for truly org-wide events with no cost chart. On update: omit to leave existing annotation charts unchanged; pass widgetEventId when the event has multiple charts."New value: +"Annotation chart for the event. Same shape as the `query` tool (`queries`, `datePreset` or `from`/`to`, `aggBy`, `compare`, `limit`, `scopeId`) plus `title` and optional `description`. Providing a widget creates a visual annotation so the team can see which cost movement the event documents. On create: STRONGLY RECOMMENDED; omit only for truly org-wide events with no cost chart. On update: omit to leave the chart unchanged. If sent, widget is a full replacement (title, queries, and datePreset or from/to required; scopeId alone is invalid). Pass widgetEventId when the event has multiple charts."
  11. 5 tool updates
    • Changedcreate_alert1 field changed
      • addedInput schema / properties / tagIds
        Added value: +{
        +  "description": "`list_tags` id or `{ name, color? }` (created if missing, default #6366F1). Omit and [] leave it 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"
        +}
    • Changedcreate_dashboard1 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"
        +}
    • Changedcreate_report2 fields changed
      • changedInput schema / properties / schedule / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "mode": {
        -        "const": "NOW",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "mode"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "mode": {
        -        "const": "UNSCHEDULED",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "mode"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "firstRunAt": {
        -        "description": "First send time as ISO-8601 UTC datetime (e.g. 2026-07-16T10:00:00.000Z)",
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
        -        "type": "string"
        -      },
        -      "mode": {
        -        "const": "SCHEDULED",
        -        "type": "string"
        -      },
        -      "period": {
        -        "description": "Recurrence: DAILY, WEEKDAYS, WEEKLY, or MONTHLY. WEEKLY requires `weekday`.",
        -        "enum": [
        -          "DAILY",
        -          "WEEKDAYS",
        -          "WEEKLY",
        -          "MONTHLY"
        -        ],
        -        "type": "string"
        -      },
        -      "weekday": {
        -        "description": "Day of week for WEEKLY: 0 = Sunday … 6 = Saturday. Required when period is WEEKLY (Zod refine; may appear optional in JSON Schema).",
        -        "maximum": 6,
        -        "minimum": 0,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "mode",
        -      "period"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "mode": {
        +        "const": "NOW",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "mode"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "mode": {
        +        "const": "UNSCHEDULED",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "mode"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "firstRunAt": {
        +        "description": "First send date as ISO-8601 UTC datetime (e.g. 2026-07-16T00:00:00.000Z). The time of day is ignored; the report is due for that whole UTC day.",
        +        "format": "date-time",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
        +        "type": "string"
        +      },
        +      "mode": {
        +        "const": "SCHEDULED",
        +        "type": "string"
        +      },
        +      "period": {
        +        "description": "Recurrence: DAILY, WEEKDAYS, WEEKLY, or MONTHLY. WEEKLY requires `weekday`.",
        +        "enum": [
        +          "DAILY",
        +          "WEEKDAYS",
        +          "WEEKLY",
        +          "MONTHLY"
        +        ],
        +        "type": "string"
        +      },
        +      "weekday": {
        +        "description": "Day of week for WEEKLY: 0 = Sunday … 6 = Saturday. Required when period is WEEKLY (Zod refine; may appear optional in JSON Schema).",
        +        "maximum": 6,
        +        "minimum": 0,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "period"
        +    ],
        +    "type": "object"
        +  }
        +]
      • addedInput schema / properties / tagIds
        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 report 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"
        +}
    • Addedupdate_alert
    • Changedupdate_report2 fields changed
      • changedInput schema / properties / schedule / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "mode": {
        -        "const": "NOW",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "mode"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "mode": {
        -        "const": "UNSCHEDULED",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "mode"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "firstRunAt": {
        -        "anyOf": [
        -          {
        -            "format": "date-time",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "First send time as ISO-8601 UTC datetime, or null to clear"
        -      },
        -      "mode": {
        -        "const": "SCHEDULED",
        -        "type": "string"
        -      },
        -      "period": {
        -        "description": "Recurrence: DAILY, WEEKDAYS, WEEKLY, or MONTHLY. WEEKLY requires `weekday`.",
        -        "enum": [
        -          "DAILY",
        -          "WEEKDAYS",
        -          "WEEKLY",
        -          "MONTHLY"
        -        ],
        -        "type": "string"
        -      },
        -      "weekday": {
        -        "description": "Day of week for WEEKLY: 0 = Sunday … 6 = Saturday. Required when period is WEEKLY.",
        -        "maximum": 6,
        -        "minimum": 0,
        -        "type": "integer"
        -      }
        -    },
        -    "required": [
        -      "mode",
        -      "period"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "mode": {
        +        "const": "NOW",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "mode"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "mode": {
        +        "const": "UNSCHEDULED",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "mode"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "firstRunAt": {
        +        "anyOf": [
        +          {
        +            "format": "date-time",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "First send date as ISO-8601 UTC datetime, or null to clear. The time of day is ignored."
        +      },
        +      "mode": {
        +        "const": "SCHEDULED",
        +        "type": "string"
        +      },
        +      "period": {
        +        "description": "Recurrence: DAILY, WEEKDAYS, WEEKLY, or MONTHLY. WEEKLY requires `weekday`.",
        +        "enum": [
        +          "DAILY",
        +          "WEEKDAYS",
        +          "WEEKLY",
        +          "MONTHLY"
        +        ],
        +        "type": "string"
        +      },
        +      "weekday": {
        +        "description": "Day of week for WEEKLY: 0 = Sunday … 6 = Saturday. Required when period is WEEKLY.",
        +        "maximum": 6,
        +        "minimum": 0,
        +        "type": "integer"
        +      }
        +    },
        +    "required": [
        +      "mode",
        +      "period"
        +    ],
        +    "type": "object"
        +  }
        +]
      • addedInput schema / properties / tagIds
        Added value: +{
        +  "description": "Replaces the full tag list. Omit to keep stored tags; pass [] to clear. Pass existing tag IDs from `list_tags`, and/or new tag objects `{ name, color? }` (created in the org if missing; color defaults to #6366F1).",
        +  "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"
        +}
  12. 1 tool update
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring",
        -          "push"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required. For Snowflake: identical to BigQuery — metricName is DATABASE.SCHEMA.TABLE; dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
  13. 10 tool updates
    • Changedcreate_alert1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedcreate_dashboard3 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"
        +  }
        +]
    • Changedcreate_report3 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 / reportContext / 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,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        -        "type": "number"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedfind_cost_change_factors1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedpreview_report_widget3 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 / reportContext / 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 / widget / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        -        "type": "number"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedpreview_virtual_dimension_draft1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedquery1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedsuggest_groupby1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedupdate_dashboard3 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 / operations / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "add",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "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"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "op"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "replace",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "additionalProperties": {},
        -        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to overwrite (keeps its position).",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId",
        -      "widget"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "remove",
        -        "type": "string"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to delete.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "add",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "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"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "op"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "replace",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "additionalProperties": {},
        +        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to overwrite (keeps its position).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId",
        +      "widget"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "remove",
        +        "type": "string"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to delete.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_report3 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 / reportContext / 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,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        -        "type": "number"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 100,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface (integer 1–100). Applied at every tree level.",
        +        "maximum": 100,
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
  14. 2 tool updates
    • Changedcreate_alert1 field changed
      • changedInput schema / properties / dedup / description
        Previous value: -"Deduplication config controlling how often a still-firing alert notifies. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days."New value: +"Deduplication config controlling how often a still-firing group notifies. The window is per groupBy value; delivery stays one message listing newly eligible groups. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days."
    • Changedpreview_alert1 field changed
      • changedInput schema / properties / dedup / description
        Previous value: -"Deduplication config controlling how often a still-firing alert notifies. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days. Optional here: when provided the result also reports how many notifications would actually be sent after dedup."New value: +"Deduplication config controlling how often a still-firing group notifies. The window is per groupBy value; delivery stays one message listing newly eligible groups. Either CALENDAR (kind: CALENDAR, calendarUnit: WEEK | MONTH) = at most once per current ISO week / calendar month, or ROLLING (kind: ROLLING, windowDays: N) = at most once every N days. Optional here: when provided the result also reports how many notifications would actually be sent after dedup."
  15. 10 tool updates
    • Changedcreate_dashboard2 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"
        -}
    • Changedcreate_event4 fields changed
      • removedInput schema / properties / category / default
        Removed value: -"TECHNICAL"
      • changedInput schema / properties / category / description
        Previous value: -"BUSINESS = org/budget change, TECHNICAL = deployment/infra change, PROVIDER = cloud provider update"New value: +"Deprecated. If sent, merged into tags then discarded."
      • removedInput schema / properties / category / enum
        Removed value: -[
        -  "BUSINESS",
        -  "TECHNICAL",
        -  "PROVIDER"
        -]
      • addedInput schema / properties / labels
        Added value: +{
        +  "description": "Deprecated alias for tags. Ignored when tags is sent.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Changedcreate_report2 fields changed
      • removedInput schema / properties / teamId
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Optional owning team id. Independent of type/visibility; omit or null for no team."
        -}
      • removedInput schema / properties / visibility
        Removed value: -{
        -  "default": "PRIVATE",
        -  "description": "PRIVATE (default) or PUBLIC (maps to API `type`). Set `teamId` to share with a team — there is no TEAM visibility value. TEMPLATE is dashboard-only.",
        -  "enum": [
        -    "PRIVATE",
        -    "PUBLIC"
        -  ],
        -  "type": "string"
        -}
    • Addedget_object_permissions
    • Changedlist_events1 field changed
      • removedInput schema / properties / category
        Removed value: -{
        -  "description": "Filter by category. Omit to return all categories.",
        -  "enum": [
        -    "BUSINESS",
        -    "TECHNICAL",
        -    "PROVIDER"
        -  ],
        -  "type": "string"
        -}
    • Changedlist_teams1 field changed
      • addedInput schema / properties / query
        Added value: +{
        +  "description": "Optional team-name search. Omit to list every non-archived team in the organization.",
        +  "type": "string"
        +}
    • Addedlist_users
    • Addedset_object_permissions
    • Changedupdate_dashboard3 fields changed
      • changedInput schema / properties / dashboardContext / description
        Previous value: -"Partial patch for dashboard-level shared context (global filter, period, groupBy, metricId, currency, scopeId). Omitted fields keep their current values. Set `conditionsCel` to update/clear the global filter (empty string clears it). When changing period mode, null the unused side (`datePreset` vs `startDate`/`endDate`). Can be used alone or together with `operations`, `tags`, or `teamId`."New value: +"Partial patch for dashboard-level shared context (global filter, period, groupBy, metricId, currency, scopeId). Omitted fields keep their current values. Set `conditionsCel` to update/clear the global filter (empty string clears it). When changing period mode, null the unused side (`datePreset` vs `startDate`/`endDate`). Can be used alone or together with `operations` or `tags`."
      • changedInput schema / properties / operations / description
        Previous value: -"List of operations to apply atomically. Each op is \"add\" (append a new widget), \"replace\" (overwrite an existing widget in place), or \"remove\" (delete a widget). For add/replace, widgets inherit dashboard context by default; only pass per-widget overrides. Optional when `dashboardContext`, `tags`, or `teamId` is provided. Example: [{\"op\":\"add\",\"widget\":{\"title\":\"Monthly cost\",\"queries\":[{\"type\":\"cost\",\"name\":\"a\",\"chartType\":\"BAR\"}],\"aggBy\":\"Month\"}}]."New value: +"List of operations to apply atomically. Each op is \"add\" (append a new widget), \"replace\" (overwrite an existing widget in place), or \"remove\" (delete a widget). For add/replace, widgets inherit dashboard context by default; only pass per-widget overrides. Optional when `dashboardContext` or `tags` is provided. Example: [{\"op\":\"add\",\"widget\":{\"title\":\"Monthly cost\",\"queries\":[{\"type\":\"cost\",\"name\":\"a\",\"chartType\":\"BAR\"}],\"aggBy\":\"Month\"}}]."
      • removedInput schema / properties / teamId
        Removed value: -{
        -  "anyOf": [
        -    {
        -      "type": "string"
        -    },
        -    {
        -      "type": "null"
        -    }
        -  ],
        -  "description": "Team to assign the dashboard to (from `list_teams`), or null to detach from any team. Optional; omit to leave team unchanged."
        -}
    • Changedupdate_event4 fields changed
      • changedInput schema / properties / category / description
        Previous value: -"New category."New value: +"Deprecated. If sent, merged into tags then discarded."
      • removedInput schema / properties / category / enum
        Removed value: -[
        -  "BUSINESS",
        -  "TECHNICAL",
        -  "PROVIDER"
        -]
      • addedInput schema / properties / labels
        Added value: +{
        +  "description": "Deprecated alias for tags. Ignored when tags is sent.",
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / tags / description
        Previous value: -"Replace all labels on the event."New value: +"Replace all tags on the event."
  16. 12 tool updates
    • Changedcreate_alert1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedcreate_dashboard3 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"
        +  }
        +]
    • Changedcreate_report3 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 / reportContext / 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,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        -        "type": "number"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 50,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 50,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        +        "type": "number"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedcreate_virtual_dimension_draft1 field changed
      • changedInput schema / properties / rules / items / properties / allocation / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "dimensionValue",
        -        "type": "string"
        -      },
        -      "dimensionValue": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "dimensionValue"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "existingColumn",
        -        "type": "string"
        -      },
        -      "existingColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "existingColumn"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "splitCost",
        -        "type": "string"
        -      },
        -      "reAllocationParams": {
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "properties": {
        -              "partitions": {
        -                "items": {
        -                  "properties": {
        -                    "label": {
        -                      "minLength": 1,
        -                      "type": "string"
        -                    },
        -                    "weight": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "label",
        -                    "weight"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "type": {
        -                "const": "custom",
        -                "type": "string"
        -              }
        -            },
        -            "required": [
        -              "type",
        -              "partitions"
        -            ],
        -            "type": "object"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "reAllocationParams"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "telemetry",
        -        "type": "string"
        -      },
        -      "datasource": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "externalMetric": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "conditions": {
        -            "type": "string"
        -          },
        -          "dateColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "gapFillingMethod": {
        -            "enum": [
        -              "ZERO",
        -              "FORWARD_FILL",
        -              "LINEAR_INTERPOLATION",
        -              "SPREAD"
        -            ],
        -            "type": "string"
        -          },
        -          "groupByFields": {
        -            "default": [],
        -            "items": {
        -              "minLength": 1,
        -              "type": "string"
        -            },
        -            "maxItems": 7,
        -            "type": "array"
        -          },
        -          "integrationId": {
        -            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricName": {
        -            "default": "",
        -            "type": "string"
        -          },
        -          "provider": {
        -            "enum": [
        -              "tsuga",
        -              "bigquery",
        -              "datadog",
        -              "cloudwatch",
        -              "s3",
        -              "amplitude",
        -              "snowflake",
        -              "cloudmonitoring"
        -            ],
        -            "type": "string"
        -          },
        -          "query": {
        -            "minLength": 1,
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "provider",
        -          "integrationId"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingParams": {
        -        "properties": {
        -          "mapping": {
        -            "additionalProperties": {
        -              "type": "string"
        -            },
        -            "propertyNames": {
        -              "type": "string"
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "mapping"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingType": {
        -        "enum": [
        -          "mapping",
        -          "regexMapping",
        -          "identity"
        -        ],
        -        "type": "string"
        -      },
        -      "regexTransformation": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "mappingType",
        -      "mappingParams"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "dimensionValue",
        +        "type": "string"
        +      },
        +      "dimensionValue": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "dimensionValue"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "existingColumn",
        +        "type": "string"
        +      },
        +      "existingColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "existingColumn"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "splitCost",
        +        "type": "string"
        +      },
        +      "reAllocationParams": {
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "properties": {
        +              "partitions": {
        +                "items": {
        +                  "properties": {
        +                    "label": {
        +                      "minLength": 1,
        +                      "type": "string"
        +                    },
        +                    "weight": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "label",
        +                    "weight"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "type": {
        +                "const": "custom",
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "type",
        +              "partitions"
        +            ],
        +            "type": "object"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "reAllocationParams"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "telemetry",
        +        "type": "string"
        +      },
        +      "datasource": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "externalMetric": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "conditions": {
        +            "type": "string"
        +          },
        +          "dateColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "gapFillingMethod": {
        +            "enum": [
        +              "ZERO",
        +              "FORWARD_FILL",
        +              "LINEAR_INTERPOLATION",
        +              "SPREAD"
        +            ],
        +            "type": "string"
        +          },
        +          "groupByFields": {
        +            "default": [],
        +            "items": {
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "maxItems": 7,
        +            "type": "array"
        +          },
        +          "integrationId": {
        +            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricName": {
        +            "default": "",
        +            "type": "string"
        +          },
        +          "provider": {
        +            "enum": [
        +              "tsuga",
        +              "bigquery",
        +              "datadog",
        +              "cloudwatch",
        +              "s3",
        +              "amplitude",
        +              "snowflake",
        +              "cloudmonitoring",
        +              "push"
        +            ],
        +            "type": "string"
        +          },
        +          "query": {
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "provider",
        +          "integrationId"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingParams": {
        +        "properties": {
        +          "mapping": {
        +            "additionalProperties": {
        +              "type": "string"
        +            },
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "mapping"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingType": {
        +        "enum": [
        +          "mapping",
        +          "regexMapping",
        +          "identity"
        +        ],
        +        "type": "string"
        +      },
        +      "regexTransformation": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "mappingType",
        +      "mappingParams"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedfind_cost_change_factors1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedpreview_report_widget3 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 / reportContext / 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 / widget / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        -        "type": "number"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 50,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 50,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        +        "type": "number"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedpreview_virtual_dimension_draft1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedquery2 fields changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake",
        -          "cloudmonitoring"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring",
        +          "push"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedsuggest_groupby1 field changed
      • changedInput schema / properties / datePreset / enum
        Previous value: -[
        -  "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"
        -]New value: +[
        +  "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"
        +]
    • Changedupdate_dashboard3 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 / operations / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "add",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "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"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "op"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "replace",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "additionalProperties": {},
        -        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to overwrite (keeps its position).",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId",
        -      "widget"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "remove",
        -        "type": "string"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to delete.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "add",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "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"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "op"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "replace",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "additionalProperties": {},
        +        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to overwrite (keeps its position).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId",
        +      "widget"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "remove",
        +        "type": "string"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to delete.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_report3 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 / reportContext / 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,
        -    "properties": {
        -      "dashboardId": {
        -        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "datePreset": {
        -        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "DASHBOARD_PDF",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "dashboardId"
        -    ],
        -    "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": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "GRAPH_SNAPSHOT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "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"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "flopN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "from": {
        -        "description": "Widget-level start date override. Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topN": {
        -        "default": 5,
        -        "maximum": 50,
        -        "minimum": 0,
        -        "type": "integer"
        -      },
        -      "type": {
        -        "const": "TOP_FLOP",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "contentMarkdown": {
        -        "maxLength": 10000,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "title": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "TEXT",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "contentMarkdown"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "additionalGroupBy": {
        -        "default": [],
        -        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "type": "array"
        -      },
        -      "aggBy": {
        -        "default": "Month",
        -        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        -        "enum": [
        -          "Week",
        -          "Month"
        -        ],
        -        "type": "string"
        -      },
        -      "compare": {
        -        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        -        "properties": {
        -          "from": {
        -            "description": "Comparison period start date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          },
        -          "to": {
        -            "description": "Comparison period end date.",
        -            "format": "date",
        -            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "from",
        -          "to"
        -        ],
        -        "type": "object"
        -      },
        -      "datePreset": {
        -        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        -        "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"
        -      },
        -      "description": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "display": {
        -        "default": "tree",
        -        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        -        "enum": [
        -          "tree",
        -          "table",
        -          "summary"
        -        ],
        -        "type": "string"
        -      },
        -      "enableAiInvestigation": {
        -        "default": false,
        -        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        -        "type": "boolean"
        -      },
        -      "from": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "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"
        -      },
        -      "minAbsoluteDiff": {
        -        "default": 100,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "minRelativeDiff": {
        -        "default": 5,
        -        "minimum": 0,
        -        "type": "number"
        -      },
        -      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        -        "default": "Cost changes",
        -        "type": "string"
        -      },
        -      "to": {
        -        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        -        "format": "date",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        -        "type": "string"
        -      },
        -      "topLargestAbsoluteChange": {
        -        "default": 20,
        -        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        -        "type": "number"
        -      },
        -      "type": {
        -        "const": "DIGEST",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "dashboardId": {
        +        "description": "Id of the dashboard to render as a PDF (from `search`/`get`).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "datePreset": {
        +        "description": "Optional period override for the PDF. Omit to inherit the report (and destination) period.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Optional custom range start (YYYY-MM-DD). Use with to instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Optional custom range end (inclusive, YYYY-MM-DD). Use with from instead of datePreset.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "DASHBOARD_PDF",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "dashboardId"
        +    ],
        +    "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": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "GRAPH_SNAPSHOT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "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"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Use either datePreset OR explicit from/to, not both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "flopN": {
        +        "default": 5,
        +        "maximum": 50,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "from": {
        +        "description": "Widget-level start date override. Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Widget-level end date override (inclusive). Omit to inherit report context period.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topN": {
        +        "default": 5,
        +        "maximum": 50,
        +        "minimum": 0,
        +        "type": "integer"
        +      },
        +      "type": {
        +        "const": "TOP_FLOP",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "contentMarkdown": {
        +        "maxLength": 10000,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "title": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "TEXT",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "contentMarkdown"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "additionalGroupBy": {
        +        "default": [],
        +        "description": "Deeper DIGEST hierarchy levels AFTER the root groupBy, in order. Root axis is `reportContext.groupBy` (preferred) or `queries[0].groupBy` when overriding. Example: reportContext.groupBy=\"cos_environment\" + additionalGroupBy=[\"cos_sub_account_id\",\"cos_service_name\"] → tree path environment → project → service.",
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "type": "array"
        +      },
        +      "aggBy": {
        +        "default": "Month",
        +        "description": "DIGEST time grain: Week or Month (default Month). Never Period (use TOP_FLOP for whole-period movers).",
        +        "enum": [
        +          "Week",
        +          "Month"
        +        ],
        +        "type": "string"
        +      },
        +      "compare": {
        +        "description": "Required only with explicit from/to when not using datePreset or reportContext. Prefer datePreset / reportContext.",
        +        "properties": {
        +          "from": {
        +            "description": "Comparison period start date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          },
        +          "to": {
        +            "description": "Comparison period end date.",
        +            "format": "date",
        +            "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "from",
        +          "to"
        +        ],
        +        "type": "object"
        +      },
        +      "datePreset": {
        +        "description": "Widget-level period override for scheduled DIGESTs (same DatePreset as dashboards, e.g. LAST_WEEK). Omit to inherit `reportContext.datePreset` / startDate/endDate. Mutually exclusive with explicit from/to/compare — do not set both.",
        +        "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"
        +      },
        +      "description": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "display": {
        +        "default": "tree",
        +        "description": "DIGEST presentation: \"tree\" (default, change tree only — faster), \"summary\" (LLM executive narrative — slower; opt-in AI summary), or \"table\" (flat table). Set \"summary\" when the user wants the AI write-up.",
        +        "enum": [
        +          "tree",
        +          "table",
        +          "summary"
        +        ],
        +        "type": "string"
        +      },
        +      "enableAiInvestigation": {
        +        "default": false,
        +        "description": "When true, deepest-leaf cost movers get per-node AI investigation before delivery (async analysis_agent_run — noticeably slower). Default false. Independent of display: \"summary\" (executive narrative). Prefer display: \"summary\" alone for a written overview; enable this only when the user wants deep node analysis.",
        +        "type": "boolean"
        +      },
        +      "from": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "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"
        +      },
        +      "minAbsoluteDiff": {
        +        "default": 100,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "minRelativeDiff": {
        +        "default": 5,
        +        "minimum": 0,
        +        "type": "number"
        +      },
        +      "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 report widgets prefer sparse `{ type: \"cost\", name: \"a\", alias?, filterCel? }` and inherit metricId / currency / groupBy / period from `reportContext`. DIGEST: exactly one `{ type: \"cost\", ... }`. Call get_skill skillId: \"reports\" 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": {
        +        "default": "Cost changes",
        +        "type": "string"
        +      },
        +      "to": {
        +        "description": "Only for one-off custom ranges (YYYY-MM-DD). Omit to inherit report context. Do not set when datePreset is set.",
        +        "format": "date",
        +        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$",
        +        "type": "string"
        +      },
        +      "topLargestAbsoluteChange": {
        +        "default": 20,
        +        "description": "How many largest-absolute-change nodes to surface. Allowed values: 5, 10, 15, or 20.",
        +        "type": "number"
        +      },
        +      "type": {
        +        "const": "DIGEST",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_virtual_dimension_draft1 field changed
      • changedInput schema / properties / rules / items / properties / allocation / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "dimensionValue",
        -        "type": "string"
        -      },
        -      "dimensionValue": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "dimensionValue"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "existingColumn",
        -        "type": "string"
        -      },
        -      "existingColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "existingColumn"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "splitCost",
        -        "type": "string"
        -      },
        -      "reAllocationParams": {
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "properties": {
        -              "partitions": {
        -                "items": {
        -                  "properties": {
        -                    "label": {
        -                      "minLength": 1,
        -                      "type": "string"
        -                    },
        -                    "weight": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "label",
        -                    "weight"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "type": {
        -                "const": "custom",
        -                "type": "string"
        -              }
        -            },
        -            "required": [
        -              "type",
        -              "partitions"
        -            ],
        -            "type": "object"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "reAllocationParams"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "telemetry",
        -        "type": "string"
        -      },
        -      "datasource": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "externalMetric": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "conditions": {
        -            "type": "string"
        -          },
        -          "dateColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "gapFillingMethod": {
        -            "enum": [
        -              "ZERO",
        -              "FORWARD_FILL",
        -              "LINEAR_INTERPOLATION",
        -              "SPREAD"
        -            ],
        -            "type": "string"
        -          },
        -          "groupByFields": {
        -            "default": [],
        -            "items": {
        -              "minLength": 1,
        -              "type": "string"
        -            },
        -            "maxItems": 7,
        -            "type": "array"
        -          },
        -          "integrationId": {
        -            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricName": {
        -            "default": "",
        -            "type": "string"
        -          },
        -          "provider": {
        -            "enum": [
        -              "tsuga",
        -              "bigquery",
        -              "datadog",
        -              "cloudwatch",
        -              "s3",
        -              "amplitude",
        -              "snowflake",
        -              "cloudmonitoring"
        -            ],
        -            "type": "string"
        -          },
        -          "query": {
        -            "minLength": 1,
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "provider",
        -          "integrationId"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingParams": {
        -        "properties": {
        -          "mapping": {
        -            "additionalProperties": {
        -              "type": "string"
        -            },
        -            "propertyNames": {
        -              "type": "string"
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "mapping"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingType": {
        -        "enum": [
        -          "mapping",
        -          "regexMapping",
        -          "identity"
        -        ],
        -        "type": "string"
        -      },
        -      "regexTransformation": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "mappingType",
        -      "mappingParams"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "dimensionValue",
        +        "type": "string"
        +      },
        +      "dimensionValue": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "dimensionValue"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "existingColumn",
        +        "type": "string"
        +      },
        +      "existingColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "existingColumn"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "splitCost",
        +        "type": "string"
        +      },
        +      "reAllocationParams": {
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "properties": {
        +              "partitions": {
        +                "items": {
        +                  "properties": {
        +                    "label": {
        +                      "minLength": 1,
        +                      "type": "string"
        +                    },
        +                    "weight": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "label",
        +                    "weight"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "type": {
        +                "const": "custom",
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "type",
        +              "partitions"
        +            ],
        +            "type": "object"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "reAllocationParams"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "telemetry",
        +        "type": "string"
        +      },
        +      "datasource": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "externalMetric": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "conditions": {
        +            "type": "string"
        +          },
        +          "dateColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "gapFillingMethod": {
        +            "enum": [
        +              "ZERO",
        +              "FORWARD_FILL",
        +              "LINEAR_INTERPOLATION",
        +              "SPREAD"
        +            ],
        +            "type": "string"
        +          },
        +          "groupByFields": {
        +            "default": [],
        +            "items": {
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "maxItems": 7,
        +            "type": "array"
        +          },
        +          "integrationId": {
        +            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricName": {
        +            "default": "",
        +            "type": "string"
        +          },
        +          "provider": {
        +            "enum": [
        +              "tsuga",
        +              "bigquery",
        +              "datadog",
        +              "cloudwatch",
        +              "s3",
        +              "amplitude",
        +              "snowflake",
        +              "cloudmonitoring",
        +              "push"
        +            ],
        +            "type": "string"
        +          },
        +          "query": {
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "provider",
        +          "integrationId"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingParams": {
        +        "properties": {
        +          "mapping": {
        +            "additionalProperties": {
        +              "type": "string"
        +            },
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "mapping"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingType": {
        +        "enum": [
        +          "mapping",
        +          "regexMapping",
        +          "identity"
        +        ],
        +        "type": "string"
        +      },
        +      "regexTransformation": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "mappingType",
        +      "mappingParams"
        +    ],
        +    "type": "object"
        +  }
        +]
  17. 6 tool updates
    • Changedcreate_dashboard1 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"
        +  }
        +]
    • Changedcreate_report2 fields changed
      • changedInput schema / properties / visibility / description
        Previous value: -"PRIVATE (default), PUBLIC, or TEMPLATE (maps to API `type`). Set `teamId` to share with a team — there is no TEAM visibility value."New value: +"PRIVATE (default) or PUBLIC (maps to API `type`). Set `teamId` to share with a team — there is no TEAM visibility value. TEMPLATE is dashboard-only."
      • changedInput schema / properties / visibility / enum
        Previous value: -[
        -  "PRIVATE",
        -  "PUBLIC",
        -  "TEMPLATE"
        -]New value: +[
        +  "PRIVATE",
        +  "PUBLIC"
        +]
    • Changedcreate_virtual_dimension_draft1 field changed
      • changedInput schema / properties / rules / items / properties / allocation / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "dimensionValue",
        -        "type": "string"
        -      },
        -      "dimensionValue": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "dimensionValue"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "existingColumn",
        -        "type": "string"
        -      },
        -      "existingColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "existingColumn"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "splitCost",
        -        "type": "string"
        -      },
        -      "reAllocationParams": {
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "properties": {
        -              "partitions": {
        -                "items": {
        -                  "properties": {
        -                    "label": {
        -                      "minLength": 1,
        -                      "type": "string"
        -                    },
        -                    "weight": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "label",
        -                    "weight"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "type": {
        -                "const": "custom",
        -                "type": "string"
        -              }
        -            },
        -            "required": [
        -              "type",
        -              "partitions"
        -            ],
        -            "type": "object"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "reAllocationParams"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "telemetry",
        -        "type": "string"
        -      },
        -      "datasource": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "externalMetric": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "conditions": {
        -            "type": "string"
        -          },
        -          "dateColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "gapFillingMethod": {
        -            "enum": [
        -              "ZERO",
        -              "FORWARD_FILL",
        -              "LINEAR_INTERPOLATION",
        -              "SPREAD"
        -            ],
        -            "type": "string"
        -          },
        -          "groupByFields": {
        -            "default": [],
        -            "items": {
        -              "minLength": 1,
        -              "type": "string"
        -            },
        -            "maxItems": 7,
        -            "type": "array"
        -          },
        -          "integrationId": {
        -            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricName": {
        -            "default": "",
        -            "type": "string"
        -          },
        -          "provider": {
        -            "enum": [
        -              "tsuga",
        -              "bigquery",
        -              "datadog",
        -              "cloudwatch",
        -              "s3",
        -              "amplitude",
        -              "snowflake"
        -            ],
        -            "type": "string"
        -          },
        -          "query": {
        -            "minLength": 1,
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "provider",
        -          "integrationId"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingParams": {
        -        "properties": {
        -          "mapping": {
        -            "additionalProperties": {
        -              "type": "string"
        -            },
        -            "propertyNames": {
        -              "type": "string"
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "mapping"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingType": {
        -        "enum": [
        -          "mapping",
        -          "regexMapping",
        -          "identity"
        -        ],
        -        "type": "string"
        -      },
        -      "regexTransformation": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "mappingType",
        -      "mappingParams"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "dimensionValue",
        +        "type": "string"
        +      },
        +      "dimensionValue": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "dimensionValue"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "existingColumn",
        +        "type": "string"
        +      },
        +      "existingColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "existingColumn"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "splitCost",
        +        "type": "string"
        +      },
        +      "reAllocationParams": {
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "properties": {
        +              "partitions": {
        +                "items": {
        +                  "properties": {
        +                    "label": {
        +                      "minLength": 1,
        +                      "type": "string"
        +                    },
        +                    "weight": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "label",
        +                    "weight"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "type": {
        +                "const": "custom",
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "type",
        +              "partitions"
        +            ],
        +            "type": "object"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "reAllocationParams"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "telemetry",
        +        "type": "string"
        +      },
        +      "datasource": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "externalMetric": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "conditions": {
        +            "type": "string"
        +          },
        +          "dateColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "gapFillingMethod": {
        +            "enum": [
        +              "ZERO",
        +              "FORWARD_FILL",
        +              "LINEAR_INTERPOLATION",
        +              "SPREAD"
        +            ],
        +            "type": "string"
        +          },
        +          "groupByFields": {
        +            "default": [],
        +            "items": {
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "maxItems": 7,
        +            "type": "array"
        +          },
        +          "integrationId": {
        +            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricName": {
        +            "default": "",
        +            "type": "string"
        +          },
        +          "provider": {
        +            "enum": [
        +              "tsuga",
        +              "bigquery",
        +              "datadog",
        +              "cloudwatch",
        +              "s3",
        +              "amplitude",
        +              "snowflake",
        +              "cloudmonitoring"
        +            ],
        +            "type": "string"
        +          },
        +          "query": {
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "provider",
        +          "integrationId"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingParams": {
        +        "properties": {
        +          "mapping": {
        +            "additionalProperties": {
        +              "type": "string"
        +            },
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "mapping"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingType": {
        +        "enum": [
        +          "mapping",
        +          "regexMapping",
        +          "identity"
        +        ],
        +        "type": "string"
        +      },
        +      "regexTransformation": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "mappingType",
        +      "mappingParams"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedquery1 field changed
      • changedInput schema / properties / queries / items / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "currency": {
        -        "default": "USD",
        -        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        -        "enum": [
        -          "USD",
        -          "EUR",
        -          "GBP",
        -          "CNY"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "default": "cost",
        -        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        -        "enum": [
        -          "cost",
        -          "effective_cost",
        -          "list_cost",
        -          "contracted_cost",
        -          "unblended_cost",
        -          "net_unblended_cost",
        -          "amortized_cost",
        -          "net_amortized_cost"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "cost",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "metric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "filterCel": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ],
        -        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        -      },
        -      "groupBy": {
        -        "anyOf": [
        -          {
        -            "anyOf": [
        -              {
        -                "type": "string"
        -              },
        -              {
        -                "items": {
        -                  "minLength": 1,
        -                  "type": "string"
        -                },
        -                "type": "array"
        -              }
        -            ]
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "metricId": {
        -        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "usage",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "metricId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "formula": {
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "type": {
        -        "const": "formula",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "formula",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        -    "properties": {
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "budgetId": {
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "budget",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      },
        -      "virtualDimensionValue": {
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "budgetId",
        -      "name"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required.",
        -    "properties": {
        -      "aggregator": {
        -        "enum": [
        -          "SUM",
        -          "AVG",
        -          "MAX",
        -          "MIN"
        -        ],
        -        "type": "string"
        -      },
        -      "alias": {
        -        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        -        "maxLength": 50,
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "chartType": {
        -        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        -        "enum": [
        -          "BAR",
        -          "LINE",
        -          "AREA",
        -          "WATERFALL",
        -          "TABLE"
        -        ],
        -        "type": "string"
        -      },
        -      "conditions": {
        -        "type": "string"
        -      },
        -      "dateColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "gapFillingMethod": {
        -        "enum": [
        -          "ZERO",
        -          "FORWARD_FILL",
        -          "LINEAR_INTERPOLATION",
        -          "SPREAD"
        -        ],
        -        "type": "string"
        -      },
        -      "groupByFields": {
        -        "default": [],
        -        "items": {
        -          "minLength": 1,
        -          "type": "string"
        -        },
        -        "maxItems": 7,
        -        "type": "array"
        -      },
        -      "integrationId": {
        -        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "metricName": {
        -        "default": "",
        -        "type": "string"
        -      },
        -      "name": {
        -        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        -        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        -        "type": "string"
        -      },
        -      "provider": {
        -        "default": "tsuga",
        -        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        -        "enum": [
        -          "tsuga",
        -          "bigquery",
        -          "datadog",
        -          "cloudwatch",
        -          "s3",
        -          "amplitude",
        -          "snowflake"
        -        ],
        -        "type": "string"
        -      },
        -      "query": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "rollingAggregation": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "window": {
        -            "properties": {
        -              "preset": {
        -                "enum": [
        -                  "MONTH",
        -                  "WEEK"
        -                ],
        -                "type": "string"
        -              },
        -              "relativeDays": {
        -                "maximum": 9007199254740991,
        -                "minimum": 1,
        -                "type": "integer"
        -              }
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "aggregator",
        -          "window"
        -        ],
        -        "type": "object"
        -      },
        -      "type": {
        -        "const": "externalMetric",
        -        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "type",
        -      "integrationId",
        -      "name"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "currency": {
        +        "default": "USD",
        +        "description": "Currency for cost values (USD, EUR, GBP). Defaults to \"USD\".",
        +        "enum": [
        +          "USD",
        +          "EUR",
        +          "GBP",
        +          "CNY"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "default": "cost",
        +        "description": "Cost column to query (e.g. \"cost\", \"effective_cost\", \"amortized_cost\"). Defaults to \"cost\".",
        +        "enum": [
        +          "cost",
        +          "effective_cost",
        +          "list_cost",
        +          "contracted_cost",
        +          "unblended_cost",
        +          "net_unblended_cost",
        +          "amortized_cost",
        +          "net_amortized_cost"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "cost",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Saved Costory metric id from list_metrics metrics[].id. This is the query identity — not list_metrics `datasourceId` (that filter only returns groupBy dimensions for telemetry).",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "metric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "filterCel": {
        +        "anyOf": [
        +          {
        +            "type": "string"
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ],
        +        "description": "Optional scope filter as CEL (Common Expression Language). Examples: cos_service_name in [\"AmazonEC2\"]; cos_provider in [\"AWS\"] && cos_environment in [\"prod\"]. Label dimensions use the cos_ prefix; native provider fields omit it. Unlabelled/untagged resources have null values; use == null to match them (e.g. cos_environment == null) and != null to exclude them. Omit or pass empty string for no filter."
        +      },
        +      "groupBy": {
        +        "anyOf": [
        +          {
        +            "anyOf": [
        +              {
        +                "type": "string"
        +              },
        +              {
        +                "items": {
        +                  "minLength": 1,
        +                  "type": "string"
        +                },
        +                "type": "array"
        +              }
        +            ]
        +          },
        +          {
        +            "type": "null"
        +          }
        +        ]
        +      },
        +      "metricId": {
        +        "description": "Usage metric id (from suggest_usage_metrics). Distinct from cost metricId and from list_metrics datasourceId.",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "usage",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "metricId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "formula": {
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "type": {
        +        "const": "formula",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "formula",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Plot a budget. Use aggBy Month for one value per calendar month. For a daily running total within each month (to see which day the budget was reached), use aggBy Day with rollingAggregation { aggregator: SUM, window: { preset: MONTH } }.",
        +    "properties": {
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "budgetId": {
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "budget",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      },
        +      "virtualDimensionValue": {
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "budgetId",
        +      "name"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "description": "Plot a live external metric from an integration. integrationId comes from list_metrics(includeExternal: true). For Tsuga: metricName is the provider metric name; groupByFields are provider metric attributes; conditions is an optional provider filter string. For Datadog: metricName is the Datadog metric name; groupByFields are metric tags; conditions is an optional Datadog filter/query string. When query is set it is the Datadog metrics query string (pass-through to queryMetrics); metricName / aggregator / conditions / groupByFields are leftover UI state and are not a second writer. .rollup is required and the interval must be ≥ 24h (daily / weekly / monthly or seconds ≥ 86400). Costory will not fill an empty weekly series. For CloudWatch: metricName is Namespace/MetricName (e.g. AWS/EC2/CPUUtilization); groupByFields are CloudWatch dimension names; conditions is an optional dimension filter. For Amplitude: metricName is one of active_users, new_users, active_users_weekly, active_users_monthly; aggregator must be SUM; groupByFields is at most one built-in user property from list_metrics attributes (version, country, city, region, DMA, language, platform, os, device, device_type, start_version, paying); conditions is an optional Amplitude segment string (s parameter); Hour aggBy is unsupported; weekly/monthly metrics snap Amplitude period-end dates to the week/month start. For BigQuery: metricName is the fully-qualified table id (project.dataset.table); dateColumn, metricColumn, and gapFillingMethod are required; groupByFields are string column names. For S3: identical to BigQuery — metricName is the fully-qualified id of a Costory-managed external table over the customer's mirrored Parquet; dateColumn, metricColumn, and gapFillingMethod are required.",
        +    "properties": {
        +      "aggregator": {
        +        "enum": [
        +          "SUM",
        +          "AVG",
        +          "MAX",
        +          "MIN"
        +        ],
        +        "type": "string"
        +      },
        +      "alias": {
        +        "description": "Optional human-readable label (e.g. \"Cost by environment\", \"AWS spend\"). Prefer short identifiers in name; put descriptive text here.",
        +        "maxLength": 50,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "chartType": {
        +        "description": "Explorer chart for this series: BAR, LINE, AREA, WATERFALL, or TABLE. Omit to use LINE.",
        +        "enum": [
        +          "BAR",
        +          "LINE",
        +          "AREA",
        +          "WATERFALL",
        +          "TABLE"
        +        ],
        +        "type": "string"
        +      },
        +      "conditions": {
        +        "type": "string"
        +      },
        +      "dateColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "gapFillingMethod": {
        +        "enum": [
        +          "ZERO",
        +          "FORWARD_FILL",
        +          "LINEAR_INTERPOLATION",
        +          "SPREAD"
        +        ],
        +        "type": "string"
        +      },
        +      "groupByFields": {
        +        "default": [],
        +        "items": {
        +          "minLength": 1,
        +          "type": "string"
        +        },
        +        "maxItems": 7,
        +        "type": "array"
        +      },
        +      "integrationId": {
        +        "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "metricName": {
        +        "default": "",
        +        "type": "string"
        +      },
        +      "name": {
        +        "description": "Required series identifier referenced by formulas (e.g. \"a\", \"b\", \"a__r6\"). Prefer short identifiers; put human labels in alias — never spaces or descriptive phrases in name.",
        +        "pattern": "^[A-Za-z_][A-Za-z0-9_]*$",
        +        "type": "string"
        +      },
        +      "provider": {
        +        "default": "tsuga",
        +        "description": "External metric provider. Defaults to \"tsuga\" when omitted for backward compatibility with existing Tsuga MCP clients.",
        +        "enum": [
        +          "tsuga",
        +          "bigquery",
        +          "datadog",
        +          "cloudwatch",
        +          "s3",
        +          "amplitude",
        +          "snowflake",
        +          "cloudmonitoring"
        +        ],
        +        "type": "string"
        +      },
        +      "query": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "rollingAggregation": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "window": {
        +            "properties": {
        +              "preset": {
        +                "enum": [
        +                  "MONTH",
        +                  "WEEK"
        +                ],
        +                "type": "string"
        +              },
        +              "relativeDays": {
        +                "maximum": 9007199254740991,
        +                "minimum": 1,
        +                "type": "integer"
        +              }
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "aggregator",
        +          "window"
        +        ],
        +        "type": "object"
        +      },
        +      "type": {
        +        "const": "externalMetric",
        +        "description": "Required series discriminator — always set explicitly, never omit. One of: \"cost\" | \"metric\" | \"usage\" | \"formula\" | \"budget\" | \"externalMetric\".",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "type",
        +      "integrationId",
        +      "name"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_dashboard1 field changed
      • changedInput schema / properties / operations / items / oneOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "add",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "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"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "op"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "replace",
        -        "type": "string"
        -      },
        -      "widget": {
        -        "additionalProperties": {},
        -        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        -        "propertyNames": {
        -          "type": "string"
        -        },
        -        "type": "object"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to overwrite (keeps its position).",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId",
        -      "widget"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "op": {
        -        "const": "remove",
        -        "type": "string"
        -      },
        -      "widgetId": {
        -        "description": "ID of the widget to delete.",
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "op",
        -      "widgetId"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "add",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "description": "Widget definition to append. Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "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"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "op"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "replace",
        +        "type": "string"
        +      },
        +      "widget": {
        +        "additionalProperties": {},
        +        "description": "Same widget object as `widget` on op: \"add\" (text or chart). Chart `queries` match the `query` tool shape; pass only overrides relative to dashboard context.",
        +        "propertyNames": {
        +          "type": "string"
        +        },
        +        "type": "object"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to overwrite (keeps its position).",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId",
        +      "widget"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "op": {
        +        "const": "remove",
        +        "type": "string"
        +      },
        +      "widgetId": {
        +        "description": "ID of the widget to delete.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "op",
        +      "widgetId"
        +    ],
        +    "type": "object"
        +  }
        +]
    • Changedupdate_virtual_dimension_draft1 field changed
      • changedInput schema / properties / rules / items / properties / allocation / oneOf
        Previous value: -[
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "dimensionValue",
        -        "type": "string"
        -      },
        -      "dimensionValue": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "dimensionValue"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "existingColumn",
        -        "type": "string"
        -      },
        -      "existingColumn": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "existingColumn"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "splitCost",
        -        "type": "string"
        -      },
        -      "reAllocationParams": {
        -        "discriminator": {
        -          "propertyName": "type"
        -        },
        -        "oneOf": [
        -          {
        -            "properties": {
        -              "partitions": {
        -                "items": {
        -                  "properties": {
        -                    "label": {
        -                      "minLength": 1,
        -                      "type": "string"
        -                    },
        -                    "weight": {
        -                      "type": "number"
        -                    }
        -                  },
        -                  "required": [
        -                    "label",
        -                    "weight"
        -                  ],
        -                  "type": "object"
        -                },
        -                "type": "array"
        -              },
        -              "type": {
        -                "const": "custom",
        -                "type": "string"
        -              }
        -            },
        -            "required": [
        -              "type",
        -              "partitions"
        -            ],
        -            "type": "object"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "reAllocationParams"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "properties": {
        -      "allocationType": {
        -        "const": "telemetry",
        -        "type": "string"
        -      },
        -      "datasource": {
        -        "minLength": 1,
        -        "type": "string"
        -      },
        -      "externalMetric": {
        -        "properties": {
        -          "aggregator": {
        -            "enum": [
        -              "SUM",
        -              "AVG",
        -              "MAX",
        -              "MIN"
        -            ],
        -            "type": "string"
        -          },
        -          "conditions": {
        -            "type": "string"
        -          },
        -          "dateColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "gapFillingMethod": {
        -            "enum": [
        -              "ZERO",
        -              "FORWARD_FILL",
        -              "LINEAR_INTERPOLATION",
        -              "SPREAD"
        -            ],
        -            "type": "string"
        -          },
        -          "groupByFields": {
        -            "default": [],
        -            "items": {
        -              "minLength": 1,
        -              "type": "string"
        -            },
        -            "maxItems": 7,
        -            "type": "array"
        -          },
        -          "integrationId": {
        -            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricColumn": {
        -            "minLength": 1,
        -            "type": "string"
        -          },
        -          "metricName": {
        -            "default": "",
        -            "type": "string"
        -          },
        -          "provider": {
        -            "enum": [
        -              "tsuga",
        -              "bigquery",
        -              "datadog",
        -              "cloudwatch",
        -              "s3",
        -              "amplitude",
        -              "snowflake"
        -            ],
        -            "type": "string"
        -          },
        -          "query": {
        -            "minLength": 1,
        -            "type": "string"
        -          }
        -        },
        -        "required": [
        -          "provider",
        -          "integrationId"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingParams": {
        -        "properties": {
        -          "mapping": {
        -            "additionalProperties": {
        -              "type": "string"
        -            },
        -            "propertyNames": {
        -              "type": "string"
        -            },
        -            "type": "object"
        -          }
        -        },
        -        "required": [
        -          "mapping"
        -        ],
        -        "type": "object"
        -      },
        -      "mappingType": {
        -        "enum": [
        -          "mapping",
        -          "regexMapping",
        -          "identity"
        -        ],
        -        "type": "string"
        -      },
        -      "regexTransformation": {
        -        "minLength": 1,
        -        "type": "string"
        -      }
        -    },
        -    "required": [
        -      "allocationType",
        -      "mappingType",
        -      "mappingParams"
        -    ],
        -    "type": "object"
        -  }
        -]New value: +[
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "dimensionValue",
        +        "type": "string"
        +      },
        +      "dimensionValue": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "dimensionValue"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "existingColumn",
        +        "type": "string"
        +      },
        +      "existingColumn": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "existingColumn"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "splitCost",
        +        "type": "string"
        +      },
        +      "reAllocationParams": {
        +        "discriminator": {
        +          "propertyName": "type"
        +        },
        +        "oneOf": [
        +          {
        +            "properties": {
        +              "partitions": {
        +                "items": {
        +                  "properties": {
        +                    "label": {
        +                      "minLength": 1,
        +                      "type": "string"
        +                    },
        +                    "weight": {
        +                      "type": "number"
        +                    }
        +                  },
        +                  "required": [
        +                    "label",
        +                    "weight"
        +                  ],
        +                  "type": "object"
        +                },
        +                "type": "array"
        +              },
        +              "type": {
        +                "const": "custom",
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "type",
        +              "partitions"
        +            ],
        +            "type": "object"
        +          }
        +        ]
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "reAllocationParams"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "properties": {
        +      "allocationType": {
        +        "const": "telemetry",
        +        "type": "string"
        +      },
        +      "datasource": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "externalMetric": {
        +        "properties": {
        +          "aggregator": {
        +            "enum": [
        +              "SUM",
        +              "AVG",
        +              "MAX",
        +              "MIN"
        +            ],
        +            "type": "string"
        +          },
        +          "conditions": {
        +            "type": "string"
        +          },
        +          "dateColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "gapFillingMethod": {
        +            "enum": [
        +              "ZERO",
        +              "FORWARD_FILL",
        +              "LINEAR_INTERPOLATION",
        +              "SPREAD"
        +            ],
        +            "type": "string"
        +          },
        +          "groupByFields": {
        +            "default": [],
        +            "items": {
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "maxItems": 7,
        +            "type": "array"
        +          },
        +          "integrationId": {
        +            "description": "External metric integration ID from list_metrics(includeExternal: true).",
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricColumn": {
        +            "minLength": 1,
        +            "type": "string"
        +          },
        +          "metricName": {
        +            "default": "",
        +            "type": "string"
        +          },
        +          "provider": {
        +            "enum": [
        +              "tsuga",
        +              "bigquery",
        +              "datadog",
        +              "cloudwatch",
        +              "s3",
        +              "amplitude",
        +              "snowflake",
        +              "cloudmonitoring"
        +            ],
        +            "type": "string"
        +          },
        +          "query": {
        +            "minLength": 1,
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "provider",
        +          "integrationId"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingParams": {
        +        "properties": {
        +          "mapping": {
        +            "additionalProperties": {
        +              "type": "string"
        +            },
        +            "propertyNames": {
        +              "type": "string"
        +            },
        +            "type": "object"
        +          }
        +        },
        +        "required": [
        +          "mapping"
        +        ],
        +        "type": "object"
        +      },
        +      "mappingType": {
        +        "enum": [
        +          "mapping",
        +          "regexMapping",
        +          "identity"
        +        ],
        +        "type": "string"
        +      },
        +      "regexTransformation": {
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "allocationType",
        +      "mappingType",
        +      "mappingParams"
        +    ],
        +    "type": "object"
        +  }
        +]

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI cost calculation, comparison, and optimization across major providers like Anthropic, OpenAI, Google, Meta, and Mistral. Supports cost estimation, budget-aware model finding, and token estimation through a simple API and MCP integration.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables AI agents to pre-flight estimate query costs, enforce hard budgets, reconcile actual billed spend, and suggest cheaper rewrites across BigQuery, Snowflake, and Databricks.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    A local-first, multi-provider cost meter for LLM usage, exposed as MCP tools. Captures every call into a local SQLite ledger and lets any coding agent query spend, compare providers, and get recommendations — no cloud, no account. First-class support for Chinese providers (Qwen, DeepSeek) alongside Anthropic and OpenAI.
    7
    53 PyPI
    5
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Local-first FinOps MCP server. Ask about your AWS, Azure, GCP, and SaaS costs in plain English. Anomaly detection, rightsizing, idle-resource cleanup, and Jira/Linear ticketing. Credentials never leave your machine.
    10
    19
    Apache 2.0
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources