| name | modify-dashboard |
| description | Modify an existing monitoring dashboard on Nightingale (n9e). Use when the user asks to change a dashboard's variables, check and fix variables, modify charts/series (change PromQL, legend, unit, add/remove series), rename a chart, or change the chart type (e.g., turn a stat chart into a timeseries chart). Distinct from "creating a dashboard from scratch" (that is create-dashboard). |
| max_iterations | 16 |
| examples | ["Change the default value of the ident variable on this dashboard to web01","Check whether this dashboard's variables have any issues, and fix them while you're at it","Change the query of the CPU usage chart to only look at total cores","Add a swap usage series to the memory chart","Change this panel's unit to percent","Change the chart in the first row from a stat to a timeseries chart"] |
| builtin_tools | ["list_dashboards","get_dashboard_detail","update_dashboard","list_busi_groups","list_datasources","list_metrics","get_metric_labels","query_prometheus"] |
Skill: Nightingale (N9E) Modify an Existing Dashboard
Help users modify an existing dashboard using natural language — not create a new one. Three typical kinds of requests:
| Request | What you change |
|---|
| Change variables | A template variable's value expression (definition), default value, whether it is multi-select (multi), display label (label) |
| Check and fix variables | Scan variable definitions and the references to variables inside charts, detect smells (a chart references an undefined variable, a variable returns no value, datasource references are inconsistent, etc.) and fix them |
| Change chart series | The series of a chart (panel): query expression (PromQL), legend, unit, adding/removing series, changing the title, changing the chart type (e.g., stat→timeseries) |
Editing series queries (queries) is only supported for Prometheus/VictoriaMetrics panels; SQL/log panels (mysql, ck, es, etc.) can only have their unit, title, description changed or be deleted — passing queries will be rejected by the tool.
Iron rule: a single proposal call wraps it up; confirmation is done by the system
update_dashboard is a proposal-style write: after you call it (passing only the part you want to change), the tool computes the diff, directly shows the user the list of changes and pauses the conversation; once the user confirms, the system automatically persists it to the database — the confirmation step neither needs nor goes through you. Therefore:
- First call
get_dashboard_detail(id, include_config=true) to read the current variables, chart summaries, and variable health check.
- After working out the part you want to change, call
update_dashboard once, passing only the variables/panels/fix_datasource you want to change. This call is the last step of this turn; the system takes over the display and confirmation.
- Do not render the change table yourself (the system will show the list generated by the tool), and do not pass
proposal_id/confirmed (those are parameters for the system's confirmation channel).
- When the user rejects or raises a new requirement, you will receive feedback in a new turn: just recompute the changes per the feedback and call
update_dashboard again (the old proposal is automatically voided).
Step 1: Locate the dashboard
- If the context already carries
dashboard_id (injected by the frontend from /dashboards/<id>, or already determined in a previous turn) → use it directly, don't call list_dashboards again.
- The user pasted a
/dashboards/<id> link → take the id from it.
- Only a name was given → call
list_dashboards(query="...") to match by name; if there are multiple candidates or no match, list them and ask the user — do not guess.
Read the business group and the datasources from the dashboard itself; do not ask the user for them.
Step 2: Read the current state (always pass include_config=true)
get_dashboard_detail(id=<id>, include_config=true)
In the response:
variables: for each variable, name / type / label / definition / multi / default_value / datasource_value
panels: for each chart, id / name / type / unit / queries (each series contains ref / promql / legend / instant / step / hide; fields that are not set are omitted); charts inside collapsed rows (row) have been flattened in
variable_lint: the list of smells caught by the variable health check (e.g., "the query expression of chart X references an undefined variable $foo")
Prefer id when locating a chart (e.g., panel-3); names may be duplicated.
Step 3: Validate that the query can return a value (optional but recommended)
When changing PromQL or fixing a variable's definition, you can first use query_prometheus / list_metrics / get_metric_labels to verify that the new expression really has data before proposing, to avoid the chart still being empty after the change.
For variable-fix tasks: for each item caught in variable_lint, decide on a fix action (change the definition / rename the reference / fix the datasource reference) and put them all into the same proposal.
Step 4: Submit the proposal (call update_dashboard, just once)
Call update_dashboard, passing only the part you want to change (everything else is preserved as-is; the tool won't touch it). The tool will show the user the list of changes and wait for confirmation; this turn ends here:
- Change/add/delete variables →
variables (a JSON array, matched by name):
[{"name":"ident","default_value":"web01","multi":false}]
- Write only the fields you want to change; if
name does not exist it is treated as adding a new query variable, and an addition must carry definition (omitting it raises an error — a misspelled name falls into the addition branch, and this guard catches it); delete:true deletes it.
- Change chart series →
panels (a JSON array, located by id first, otherwise by name):
[{"id":"panel-2","unit":"percent","queries":[{"promql":"avg(cpu_usage_active{cpu=\"cpu-total\",ident=~\"$ident\"})","legend":"{{ident}}"}]}]
- When
queries is passed in it is with the existing series: matched by (the original series' refId), only the fields you write are overwritten; the rest (step/hide/, the refId-associated overrides, etc.) are preserved as-is; . — so when changing only one series, pass just that one (with its ); you don't need to list all the series of the whole chart.
Step 5: Responding to special cases
- After reading the current state, if you find no change is needed, the query validation returns no data, or the target chart/variable cannot be located: do not call
update_dashboard; just state the reason in a single sentence and give a suggestion.
- When the user gives feedback in a new turn that "the proposal is stale/invalid" (the dashboard was changed by someone else in the meantime): just re-read the current state and re-propose.
The changes list returned by the tool is the set of changes actually persisted to the database; restate to the user based on it.
Notes
- For multi-select variables, use
=~ instead of = in PromQL, e.g., ident=~"$ident".
- When changing/adding a series, use the
{{label}} form for the legend template, e.g., {{ident}}.
- When unsure of a metric name/label, probe with
list_metrics / get_metric_labels first; don't make it up.
- When the user raises multiple changes in a row within one conversation, you can merge them into a single
update_dashboard call (pass variables and panels together); the change list and confirmation are gated by the system and won't be skipped.