> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vistazo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Widgets

> Add widgets, wire them to data, and set their style and layout.

A widget is two halves: a **pipeline** (which data-source tools feed it, plus the transform that shapes the rows) and a **payload** (the chart or table config). `add_widget` creates it, `set_widget_pipeline` wires it, `set_widget_style` dresses it.

| Tool                                              | What it does          |                   |
| ------------------------------------------------- | --------------------- | ----------------- |
| [`list_widgets`](#list_widgets)                   | List widgets          | Read-only         |
| [`get_widget`](#get_widget)                       | Get widget            | Read-only         |
| [`get_widget_data`](#get_widget_data)             | Get widget data       | Read-only         |
| [`search_widgets`](#search_widgets)               | Search widgets        | Read-only         |
| [`get_widget_inputs`](#get_widget_inputs)         | Get widget inputs     | Read-only         |
| [`add_widget`](#add_widget)                       | Add widget            | Additive write    |
| [`set_widget_pipeline`](#set_widget_pipeline)     | Set widget pipeline   | Destructive write |
| [`patch_widget_pipeline`](#patch_widget_pipeline) | Patch widget pipeline | Destructive write |
| [`set_widget_style`](#set_widget_style)           | Set widget style      | Destructive write |
| [`set_widget_layout`](#set_widget_layout)         | Set widget layout     | Destructive write |
| [`remove_widget`](#remove_widget)                 | Remove widget         | Destructive write |
| [`restore_widget`](#restore_widget)               | Restore widget        | Destructive write |

## list\_widgets

`Read-only`

List all widgets on a dashboard: id, title, type (payload dialect), kind (the semantic renderer — kpi | table | pivot | progress for Vistazo-native widgets, the lead series type for ECharts widgets, markdown, visualization), layout, and the current pipelineId. ARCHIVED (removed) widgets are hidden by default — pass includeArchived:true to list them too, each marked archived:true; that is how a restore\_widget target is found without already knowing its id. For one widget's full config and pipeline wiring, use get\_widget; to retitle or edit a description, set\_widget\_style.

## get\_widget

`Read-only`

Return ONE widget in full: title, description, type + semantic kind, archived (true = soft-deleted by remove\_widget, restorable with restore\_widget), layout, the stored payload config (echartsConfig / vistazoConfig / markdownContent / visualizationRef), the skill fields, and the complete pipeline wiring — every fetch stage's mcpId / toolName / argumentTemplate / role plus the persisted transform function body. READ THIS BEFORE EDITING a widget: set\_widget\_pipeline and set\_widget\_style replace what they touch, so fetch the current wiring/config here and re-send it with your modification instead of reconstructing it from guesses. (Edits route: title/description/payload → set\_widget\_style; wiring → set\_widget\_pipeline; position/size → set\_widget\_layout.) This read fetches nothing; to also see what each stage returns TODAY (a fresh sample per source to write a transform against), call get\_widget\_inputs.

## get\_widget\_data

`Read-only`

Return the last refresh result for a widget without triggering a new refresh — the cheap way to read a chart's actual numbers. Echoes the widget `title`, so readings across several widgets can be correlated without a get\_widget per id. TWO DIFFERENT FRESHNESS FACTS COME BACK, DO NOT CONFLATE THEM: `lastRefreshedAt` is REFRESH recency (when the pipeline last ran) and `latestPeriod` is DATA recency (`{field, value, granularity}` — the newest period present in the rows, and the column it was read from). A widget refreshed four minutes ago whose latestPeriod is 2019 is running fine and reporting stale years — that is a pinned fetch window; check\_freshness names the argument that pins it. latestPeriod is best-effort and null when no column reads as a time dimension, which is never evidence of freshness. `fields` gives the units and decimal precision the widget APPLIES when rendering each row field — check it before drawing a conclusion from a small difference, which may sit inside the displayed rounding. `status` values: idle = the last run completed (data can still be null when nothing has refreshed yet or the cached rows expired — refresh to materialize), running = a refresh is in flight, error = the last run failed (errorMessage says why).

## search\_widgets

`Read-only`

Full-text search across widget titles and descriptions in the dashboards you can access within a workspace.

## get\_widget\_inputs

`Read-only`

The HYDRATE read for editing a widget's data: everything get\_widget returns PLUS, per fetch stage, the arguments as rendered against the dashboard's current parameter values, the alias the transform receives that stage under (`inputs.<alias>`; the first stage is also `rawResponse`), the full row count, and a fresh 3-row sample of the unwrapped payload — fetched live from the source now, nothing cached or written. Call this BEFORE writing or changing a transform, so it is authored against the real shape instead of a guess; then set\_widget\_pipeline with transformFunctionBody + fields and NO transformedData validates that transform against these same sources before anything is written. A stage whose source is unreachable comes back with `error` instead of a sample (style edits via set\_widget\_style never need the data; a transform edit needs every stage reachable). Costs one call per stage against the live sources, so it is a deliberate authoring read, not a browse — for a widget's published numbers use get\_widget\_data, for its wiring alone use get\_widget. Requires a connection to each stage's server (CONNECTION\_NOT\_AUTHENTICATED names add\_connection as the remedy).

## add\_widget

`Additive write`

Add a widget to a dashboard. `type` names the PAYLOAD you will supply and nothing else — one of four: vistazoConfig (a Vistazo-native kpi | table | pivot | progress, picked with `kind`), echartsConfig (an ECharts option object), visualizationRef (a saved library visualization, via entryId), markdownContent (authored prose, the one type with no data pipeline). Where the dialects overlap take the purpose-built kind — a single-value display is a vistazoConfig kpi, never an ECharts gauge — A series with `seriesField: "*"` is a TEMPLATE that expands at render into one series per numeric row field no other series claims (named by the field key) — use it when the column set only exists at run time, e.g. one line per country when the countries are a multi\_select parameter and the transform pivots to one column per country. Note that the chart kind itself lives INSIDE the payload (series\[].type for ECharts, `kind` for the Vistazo dialect), never at the tool layer. Placement: defaults to full-width (w=12) appended below existing widgets; pass width/height and optionally x/y (same grid semantics as set\_widget\_layout) to place it directly — a side-by-side row is chart \{x:0,width:8} + KPI \{x:8,width:4} at the same y. Reposition/resize later with set\_widget\_layout. The widget is created EMPTY: wire its data with set\_widget\_pipeline, author the payload with set\_widget\_style, then refresh\_pipeline and VERIFY with get\_widget\_data (a refresh reporting ok:true with rowCount 0 means the fetch matched nothing). Requires edit access.

## set\_widget\_pipeline

`Destructive write`

Wire one or more connected MCP data-source tools to a widget — the REWIRE tool. REPLACES the widget's whole pipeline on every call: a fresh pipelineId is returned and the superseded pipeline is deleted, so read the current wiring with get\_widget first and re-send the complete stage list with your change. USE THE RIGHT TOOL FOR THE SIZE OF THE EDIT: if all you are changing is a stage's ARGUMENTS (a country code, a date bound, dropping a pinned end\_year), call patch\_widget\_pipeline instead — it edits those arguments in place and leaves the stage list, the transform and the fields untouched, so a one-token change cannot corrupt working wiring by mistranscribing the rest. Use this tool when the STRUCTURE changes: a different tool or connection, adding/removing a stage, a new transform or field list, a role change. Single tool: pass mcpId + toolName (+ argumentTemplate). Multi-tool pipeline: pass `invocations` (2+ stages): all stages fetch in parallel on refresh and ONE stitch transform combines their results (it receives `inputs` keyed by stage alias — the tool name, `_2`-suffixed on repeats — plus `rawResponse` aliasing the first stage). Optionally persist an agent-authored transform (transformFunctionBody + fields) so refresh reuses it instead of regenerating — and when you do, OMIT transformedData: the server then fetches every stage with the current parameter values, runs your transform exactly as refresh will, seeds its output so the widget renders at once, and REFUSES the whole write (nothing changes, error `transform_degraded` naming the rung: script\_error / empty\_output / field\_key\_mismatch / data\_literal / missing\_data) if the transform throws, returns no rows, misses a declared field, or a source is unreachable. Read get\_widget\_inputs first for a fresh sample of each stage to author against. Rows you pass in transformedData are trusted verbatim and skip that run; a call with neither rows nor a transform wires the stages and seeds nothing (the response says so). Transforms RESHAPE stage results, never carry data — never inline fetched values as literals (baked rows freeze; refresh only re-runs fetch stages). Rolling windows ("last 14 days", "stay current"): for date-typed arguments, define\_parameter with a relative default (today-14) referenced as \{\{ params.key }}; for integer-period sources (years, month counts), OMIT the end bound if the source treats it as optional — an open-ended window grows on its own — otherwise fetch wide (mind the source's row cap and truncation order) and take the trailing N periods in the transform. Either way the window only advances when a refresh actually RUNS: pair it with set\_refresh\_cadence, or the chart silently pins at its last refresh. A pipeline serves exactly ONE role: `widget` (chart data) or `parameter_source` (dropdown options), never both — a parameter source is its own hidden widget, separate from any chart. After changing WHAT a widget fetches, fix any prose that named the old state — widget title/description (set\_widget\_style), dashboard description (update\_dashboard) — then regenerate\_dashboard\_context, or the text and the AI skill summary built from it keep describing data that is no longer there; the response warns you when the prose still matches an argument value you just changed. Requires edit access.

## patch\_widget\_pipeline

`Destructive write`

Change a widget's fetch ARGUMENTS without re-sending its pipeline. The small-edit counterpart to set\_widget\_pipeline: that tool replaces the whole pipeline (every stage, the transform, the fields) and mints a new pipelineId, so a one-token argument change means re-transcribing wiring you did not intend to touch — and every re-send is a chance to corrupt working wiring someone else built. This tool edits the arguments IN PLACE: the pipelineId is unchanged, the stage list, the persisted transform, and the skill fields are untouched, and stages you don't name keep their current arguments. Reach for it whenever the edit is "append ;ITA to country\_code", "move end\_year to 2025", "drop the pinned end bound so the window rolls". Pass `stages`, one entry per stage you are changing, each identifying its target by `invocationId` (from get\_widget) or `stageIndex` (0-based) — omit both when the pipeline has exactly one stage. Per entry, EITHER `setArguments` / `removeArguments` for key-level edits (setArguments adds or overwrites named arguments, removeArguments deletes them; removing an argument that isn't there is refused rather than silently ignored), OR `argumentTemplate` to replace that one stage's whole template. Values may be `{{ params.<key> }}` holes, and an existing hole in an argument you don't touch survives verbatim. The merged result is validated against the tool's own input schema before anything is written (an out-of-range literal is refused with nothing changed), the stale-prose check runs on it, and the response echoes the EFFECTIVE wiring of every stage — before/after for what changed — so you can verify the merge instead of assuming it. When the pipeline has a persisted transform, the merged arguments are also FETCHED and the transform re-run BEFORE the write: a patch that breaks it is refused with nothing changed (error `transform_degraded`, same rungs as set\_widget\_pipeline), and one that works republishes the rows, so the widget renders the new arguments immediately — the response's `rows.source` says 'validated'. A pipeline with no transform yet keeps its previous rows ('previous') until refresh\_pipeline runs. Requires edit access.

## set\_widget\_style

`Destructive write`

Update a widget's presentation: its title, description, and the payload its type declares — echartsConfig, vistazoConfig (whose `kind` selects kpi | table | pivot | progress), or markdownContent. This is also the tool that RENAMES a widget — title and description live here (there is no update\_widget). PARTIAL: fields you omit are left unchanged, so a title-only edit never touches the stored payload; a payload you do pass replaces the stored one and must match the widget's type. ECharts series binding: series\[].name IS the row-field key the series reads — ADDING a series means adding an entry whose name is the new field's key; use seriesNames only when the DISPLAY label must differ from the field key (it renames while preserving the binding — never repurpose an existing series' name for display text). ECharts number formatting is SEMANTIC: put a `format` object on a value axis or series (e.g. yAxis.format = \{ kind: "currency", currency: "USD" }, kinds number | currency | percent | bytes | duration | date | text, plus decimals / unit / fullPrecision) and the renderer compiles it into axis-label and tooltip formatters with locale grouping and compaction (\$15B) — never scale values in the transform to shrink an axis, and never send a JS function (configs are JSON; functions are rejected). For position/size/mobile-order use set\_widget\_layout instead; for data wiring use set\_widget\_pipeline. Requires edit access.

## set\_widget\_layout

`Destructive write`

Override a widget's grid layout on a 12-column dashboard. Partial update — only the fields you pass change. Desktop position is \{x,y,w,h}: `y` is stacking order (empty rows compact away, so you can't author a blank row), while `x` (0–11) and `w` (2–12) place and size within a row, keeping x+w ≤ 12. A shared row is emergent — put widgets at the same `y` with widths summing to ≤12 (e.g. a 30/70 split = one widget \{x:0,w:4} and its neighbor \{x:4,w:8}); the model computes the widths. `h` is 2–20 rows tall. `order` (≥0) is the SEPARATE mobile single-column stack position (lower = higher on phones); set it to keep a logical group (KPI column + its chart) contiguous, otherwise leave it unset and mobile falls back to reading order. Widgets WITH an explicit `order` sort before ALL unset widgets on mobile — setting it on a subset hoists that subset above everything unordered, so when customizing the phone stack set `order` on every widget (or know that unordered ones follow after, in reading order). Execute the user's desktop coordinates faithfully; the mobile collapse is automatic and governed by `order`, not by desktop coordinates. Requires edit access.

## remove\_widget

`Destructive write`

Remove a widget from a dashboard — a SOFT DELETE (the same model as archive\_dashboard): the widget is hidden everywhere and its data pipeline is PARKED, but nothing is destroyed and restore\_widget brings both back intact. Nothing here hard-deletes a widget. Confirm with the user only when their request does NOT identify the widget unambiguously ("drop the chart" on a dashboard holding three charts); when the request names the widget, or you resolved the id from list\_widgets / search\_widgets and it matches what was asked for, that request IS the confirmation — verify the id, then remove it. dashboardId must be the widget's own dashboard: a mismatch refuses instead of removing, so a stale or mistyped widgetId can never disrupt a widget somewhere else. The response echoes the removed widget's title and kind for verification, plus restorable:true. What removal does to the agent-facing surfaces, automatically — no follow-up cleanup call exists or is needed: it disappears from list\_widgets (unless includeArchived:true), get\_dashboard, search\_widgets, the canvas, and any public share link, and its parked pipeline stops running — it is dropped from refresh\_dashboard's fan-out and from scheduled auto-refresh, and refresh\_pipeline / refresh\_stage refuse on it, so a removed widget never fetches or spends again. Reads by id still work (get\_widget reports archived:true and returns the full wiring; get\_widget\_data still returns its last published rows). Every other write refuses while it is archived. The dashboard's AI skill summary does NOT auto-update — run regenerate\_dashboard\_context afterwards when the removal changes what the dashboard shows. Requires edit access.

## restore\_widget

`Destructive write`

Bring back a widget that remove\_widget archived, with its data pipeline, its stage wiring, its transform, and its last published rows intact — the exit from the widget archive, exactly as archive\_dashboard's restore:true is the exit from the dashboard archive. (Not to be confused with restore\_dashboard, which rolls a whole dashboard back to a recorded VERSION; this only un-hides one widget and changes nothing about its content.) Find the target with list\_widgets includeArchived:true, which marks archived rows archived:true. The widget returns to its STORED grid slot — archiving never moved the other widgets' saved geometry, so it normally reappears exactly where it was; if a widget added while it was archived now occupies that space, the grid's vertical compaction pushes one of them down at render (nothing is lost, but the arrangement may not be what you want), so the response echoes its position — reposition deliberately with set\_widget\_layout. The data is as stale as the moment it was removed: refresh\_pipeline to bring it current. Refuses on a widget that is not archived. Run regenerate\_dashboard\_context afterwards so the dashboard summary describes it again. Requires edit access.
