| name | manage-dashboard |
| description | This skill should be used when the user wants to perform CRUD operations on Langfuse dashboards. Trigger phrases include "create dashboard", "list dashboards", "manage dashboards", "delete dashboard", "add widget to dashboard", "remove widget from dashboard". It handles listing, creating, updating metadata, deleting dashboards, and managing widget placement entries within dashboard definitions.
|
Manage Langfuse Dashboards
Create, read, update, and delete Langfuse dashboards, including widget placement entries in each dashboard's
definition JSON column.
Prerequisites
- Langfuse Host URL and Project ID from the parent plugin context.
- Database connection via psycopg2 (preferred) or docker exec psql fallback.
- Python libraries
cuid2 and psycopg2-binary installed. If missing, install
via uv add cuid2 psycopg2-binary.
Operations
List Dashboards
Query all dashboards for the current project:
SELECT id, name, description, created_at, updated_at,
jsonb_array_length(definition->'widgets') AS widget_count
FROM dashboards
WHERE project_id = %(project_id)s
ORDER BY updated_at DESC;
Present the results as a table with columns: Name, Widget Count, Created,
Last Updated, ID. If no dashboards exist, inform the user and offer to create
one.
Create Dashboard
Generate a CUID for the new dashboard ID:
from cuid2 import cuid_wrapper
cuid_generator = cuid_wrapper()
dashboard_id = cuid_generator()
Ask for a name and optional description, then insert the dashboard with an
empty widget list:
INSERT INTO dashboards (
id, created_at, updated_at, created_by, updated_by,
project_id, name, description, definition, filters
) VALUES (
%(id)s, NOW(), NOW(), NULL, NULL,
%(project_id)s, %(name)s, %(description)s,
'{"widgets": []}'::jsonb, '[]'::jsonb
);
After creation, provide the dashboard URL:
{LANGFUSE_HOST}/project/{PROJECT_ID}/dashboards/{DASHBOARD_ID}
Update Dashboard Metadata
Update the name and/or description of an existing dashboard:
UPDATE dashboards
SET name = %(name)s,
description = %(description)s,
updated_at = NOW()
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
Only update the fields the user wants to change. For unchanged fields, use the
current values from the database.
Delete Dashboard
Before deleting, check whether the dashboard contains widgets:
SELECT name, definition
FROM dashboards
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
Parse the definition JSON and check the widgets array length.
If the dashboard has widgets:
Warn that deletion will orphan widget placement entries but will NOT delete the
underlying dashboard_widgets rows, then ask for explicit confirmation:
WARNING: Dashboard "<name>" contains <N> widget placements.
The widgets themselves will NOT be deleted, only their placement on this dashboard.
Proceed with deletion? (yes/no)
If the dashboard is empty or the user confirms:
DELETE FROM dashboards
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
Verify deletion:
SELECT COUNT(*) FROM dashboards
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
Add Widget to Dashboard
Add a widget placement entry to an existing dashboard's definition.widgets[]
array. Delegate grid position calculation to the layout-widgets skill.
- Verify the widget exists in
dashboard_widgets:
SELECT id, name FROM dashboard_widgets
WHERE id = %(widget_id)s AND project_id = %(project_id)s;
- Read the current dashboard definition:
SELECT definition FROM dashboards
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
-
Use layout-widgets to calculate placement (x, y, x_size, y_size) from
existing widget positions.
-
Generate a UUID v4 for the placement slot ID:
import uuid
placement_id = str(uuid.uuid4())
- Construct the placement entry:
{
"type": "widget",
"id": "<uuid4>",
"widgetId": "<cuid of dashboard_widget>",
"x": 0,
"y": 0,
"x_size": 6,
"y_size": 4
}
- Append to the
widgets array and update:
UPDATE dashboards
SET definition = %(updated_definition)s::jsonb,
updated_at = NOW()
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
Remove Widget from Dashboard
Remove a widget placement entry from a dashboard without deleting the
underlying dashboard_widgets row.
- Read the current dashboard definition:
SELECT definition FROM dashboards
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
-
Parse the definition JSON.
-
Find the placement entry where widgetId matches the target widget ID.
If not found, inform the user that the widget is not on this dashboard.
-
Remove the matching entry from the widgets array.
-
Optionally re-compact grid positions to remove visual gaps; skipping this
does not break functionality.
-
Update the dashboard definition:
UPDATE dashboards
SET definition = %(updated_definition)s::jsonb,
updated_at = NOW()
WHERE id = %(dashboard_id)s AND project_id = %(project_id)s;
Error Handling
- If a dashboard ID does not exist, report this and suggest listing dashboards.
- If a widget ID does not exist when adding to a dashboard, report this and
suggest using
list-widgets to find valid widget IDs.
- If the dashboard definition JSON is malformed, report the structure issue
and do not attempt partial updates.
- If the database connection fails, attempt the docker exec psql fallback
before reporting failure.
Related Skills
create-widget -- create new widgets to add to dashboards.
layout-widgets -- calculate grid positions for widget placement.
delete-widget -- delete widgets (also cleans up dashboard references).