Back to Nightingale

Skill: Nightingale (N9E) Modify an Existing Dashboard

aiagent/skill/embedded/builtin/modify-dashboard/SKILL.md

9.1.18.4 KB
Original Source

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:

RequestWhat you change
Change variablesA template variable's value expression (definition), default value, whether it is multi-select (multi), display label (label)
Check and fix variablesScan 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 seriesThe 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:

  1. First call get_dashboard_detail(id, include_config=true) to read the current variables, chart summaries, and variable health check.
  2. 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.
  3. 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).
  4. 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.

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 variablesvariables (a JSON array, matched by name):
    json
    [{"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 seriespanels (a JSON array, located by id first, otherwise by name):
    json
    [{"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 incrementally merged with the existing series: matched by ref (the original series' refId), only the fields you write are overwritten; the rest (step/hide/mode, the refId-associated overrides, etc.) are preserved as-is; anything without a ref is always treated as a new series (no position match). Existing series that do not appear in queries will not be deleted and are preserved as-is — so when changing only one series, pass just that one (with its ref); you don't need to list all the series of the whole chart.
    • Changing an existing series must carry its ref (without ref it adds a series instead of changing the original one); to delete a series, put its ref on that series item and write delete:true.
    • new_name changes the title, unit changes the unit, description changes the description, type changes the chart type (only timeseries/stat/gauge/barGauge/pie/table; changing the type resets the chart's type-style options to the defaults of the new type, and changing to timeseries also clears the instant flag on series to restore range queries; a row layout row cannot be changed), delete:true (on the panel item) deletes the whole chart. Not passing queries leaves the series untouched.
    • Only the fields above are valid inside a panel item: colors, thresholds, layout coordinates, and other fields are not supported. A patch that only contains unsupported fields is directly rejected by the tool; if mixed in among supported fields, the unsupported parts are silently dropped — so you must restate to the user strictly based on the change list returned by the tool; changes outside that list did not happen. When the user wants to change something unsupported, just say it can't be done and suggest editing it manually on the page.
  • Fix datasource referencesfix_datasource: true: re-points dangling or hard-coded datasource references in charts/variables uniformly to the dashboard's datasource variable. Suitable for fixing smells like "chart returns no data / datasource references are inconsistent."

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.