xiaohongshu
xiaohongshu
aibi-dashboards
Create AI/BI dashboards. CRITICAL: You MUST test ALL SQL queries via execute_sql BEFORE deploying. Follow guidelines strictly.
Full skill instructions
Create Databricks AI/BI dashboards (formerly Lakeview dashboards). Follow these guidelines strictly.
You MUST follow this workflow exactly. Skipping validation causes broken dashboards.
┌─────────────────────────────────────────────────────────────────────┐
│ STEP 1: Get table schemas via get_table_details(catalog, schema) │
├─────────────────────────────────────────────────────────────────────┤
│ STEP 2: Write SQL queries for each dataset │
├─────────────────────────────────────────────────────────────────────┤
│ STEP 3: TEST EVERY QUERY via execute_sql() ← DO NOT SKIP! │
│ - If query fails, FIX IT before proceeding │
│ - Verify column names match what widgets will reference │
│ - Verify data types are correct (dates, numbers, strings) │
├─────────────────────────────────────────────────────────────────────┤
│ STEP 4: Build dashboard JSON using ONLY verified queries │
├─────────────────────────────────────────────────────────────────────┤
│ STEP 5: Deploy via create_or_update_dashboard() │
└─────────────────────────────────────────────────────────────────────┘
WARNING: If you deploy without testing queries, widgets WILL show "Invalid widget definition" errors!
| Tool | Description |
|---|---|
get_table_details | STEP 1: Get table schemas for designing queries |
execute_sql | STEP 3: Test SQL queries - MANDATORY before deployment! |
get_best_warehouse | Get available warehouse ID |
create_or_update_dashboard | STEP 5: Deploy dashboard JSON (only after validation!) |
get_dashboard | Get dashboard details by ID |
list_dashboards | List dashboards in workspace |
trash_dashboard | Move dashboard to trash |
publish_dashboard | Publish dashboard for viewers |
unpublish_dashboard | Unpublish a dashboard |
;)catalog.schema.table_nameAS aliasesfieldName must exactly match a dataset column or aliasAllowed expressions in widget queries (you CANNOT use CAST or other SQL in expressions):
For numbers:
{"fieldName": "sum(revenue)", "expression": "SUM(`revenue`)"}
{"fieldName": "avg(price)", "expression": "AVG(`price`)"}
{"fieldName": "count(orders)", "expression": "COUNT(`order_id`)"}
{"fieldName": "countdistinct(customers)", "expression": "COUNT(DISTINCT `customer_id`)"}
{"fieldName": "min(date)", "expression": "MIN(`order_date`)"}
{"fieldName": "max(date)", "expression": "MAX(`order_date`)"}
For dates (use daily for timeseries, weekly/monthly for grouped comparisons):
{"fieldName": "daily(date)", "expression": "DATE_TRUNC(\"DAY\", `date`)"}
{"fieldName": "weekly(date)", "expression": "DATE_TRUNC(\"WEEK\", `date`)"}
{"fieldName": "monthly(date)", "expression": "DATE_TRUNC(\"MONTH\", `date`)"}
Simple field reference (for pre-aggregated data):
{"fieldName": "category", "expression": "`category`"}
If you need conditional logic or multi-field formulas, compute a derived column in the dataset SQL first.
date_sub(current_date(), N) for days, add_months(current_date(), -N) for monthsDATE_TRUNC('DAY'|'WEEK'|'MONTH'|'QUARTER'|'YEAR', column)INTERVAL syntax - use functions insteadEach widget has a position: {"x": 0, "y": 0, "width": 2, "height": 4}
CRITICAL: Each row must fill width=6 exactly. No gaps allowed.
Recommended widget sizes:
| Widget Type | Width | Height | Notes |
|---|---|---|---|
| Text header | 6 | 1-2 | Full width; h=1 title only, h=2 with description |
| Counter/KPI | 2 | 3-4 | NEVER height=2 - too cramped! |
| Line/Bar chart | 3 | 5-6 | Pair side-by-side to fill row |
| Pie chart | 3 | 5-6 | Needs space for legend |
| Full-width chart | 6 | 5-7 | For detailed time series |
| Table | 6 | 5-8 | Full width for readability |
Standard dashboard structure:
y=0: Text header (w=6, h=2) - Dashboard title + description
y=2: KPIs (w=2 each, h=3) - 3 key metrics side-by-side
y=5: Section header (w=6, h=1) - "Trends" or similar
y=6: Charts (w=3 each, h=5) - Two charts side-by-side
y=11: Section header (w=6, h=1) - "Details"
y=12: Table (w=6, h=6) - Detailed data
Dashboard readability depends on limiting distinct values:
| Dimension Type | Max Values | Examples |
|---|---|---|
| Chart color/groups | 3-8 | 4 regions, 5 product lines, 3 tiers |
| Filters | 4-10 | 8 countries, 5 channels |
| High cardinality | Table only | customer_id, order_id, SKU |
Before creating any chart with color/grouping:
get_table_details to see distinct values)Widget Naming Convention (CRITICAL):
widget.name: alphanumeric + hyphens + underscores ONLY (no spaces, parentheses, colons)frame.title: human-readable name (any characters allowed)widget.queries[0].name: always use "main_query"Counter (KPI):
widgetType: "counter""disaggregated": true in widget query"number-currency", "number-percent", "number""format": {"type": "number-currency", "currencyCode": "USD", "abbreviation": "compact", "decimalPlaces": {"type": "max", "places": 2}}
"format": {"type": "number-percent", "decimalPlaces": {"type": "max", "places": 1}}
Line / Bar Charts:
widgetType: "line" or "bar"x, y, optional color encodingsscale.type: "temporal" (dates), "quantitative" (numbers), "categorical" (strings)"disaggregated": true with pre-aggregated dataset dataMultiple Lines - Two Approaches:
"y": {
"scale": {"type": "quantitative"},
"fields": [
{"fieldName": "sum(orders)", "displayName": "Orders"},
{"fieldName": "sum(returns)", "displayName": "Returns"}
]
}
"y": {"fieldName": "sum(revenue)", "scale": {"type": "quantitative"}},
"color": {"fieldName": "region", "scale": {"type": "categorical"}, "displayName": "Region"}
Bar Chart Modes:
mark field - bars stack on top of each other"mark": {"layout": "group"} - bars side-by-side for comparisonCombo Chart:
widgetType: "combo""y": {
"primary": {"fields": [{"fieldName": "sum(orders)", "displayName": "Orders"}]},
"secondary": {"fields": [{"fieldName": "avg(aov)", "displayName": "AOV"}]},
"scale": {"type": "quantitative"}
}
Pie Chart:
widgetType: "pie"angle: quantitative aggregatecolor: categorical dimensionTable:
widgetType: "table""disaggregated": true for raw rowstype: "string", "number", "datetime"numberFormat or dateTimeFormat as neededText:
# H1, ## H2, **bold**, *italic*\n at end of each line in the array"textboxSpec": {
"lines": ["# Dashboard Title\n", "Description of what this dashboard shows.\n"]
}
Create a second page with "pageType": "PAGE_TYPE_GLOBAL_FILTERS":
Filter widget types:
filter-date-range-picker: for DATE/TIMESTAMP fieldsfilter-single-select: categorical with single selectionfilter-multi-select: categorical with multiple selectionsFilter structure:
{
"widget": {
"name": "filter_region",
"queries": [
{"name": "ds_orders_region", "query": {"datasetName": "ds_orders", "fields": [{"name": "region", "expression": "`region`"}], "disaggregated": false}}
],
"spec": {
"version": 2,
"widgetType": "filter-multi-select",
"encodings": {
"fields": [{"fieldName": "region", "displayName": "Region", "queryName": "ds_orders_region"}]
}
}
},
"position": {"x": 0, "y": 0, "width": 2, "height": 2}
}
Important: All datasets must include filter fields for filtering to work across the dashboard.
Before deploying, verify:
execute_sql and return expected dataimport json
# Step 1: Check table schema
table_info = get_table_details(catalog="samples", schema="nyctaxi")
# Step 2: Test queries
execute_sql("SELECT COUNT(*) as trips, AVG(fare_amount) as avg_fare FROM samples.nyctaxi.trips")
execute_sql("""
SELECT pickup_zip, COUNT(*) as trip_count
FROM samples.nyctaxi.trips
GROUP BY pickup_zip
ORDER BY trip_count DESC
LIMIT 10
""")
# Step 3: Build dashboard JSON
dashboard = {
"pages": [{
"name": "overview",
"displayName": "NYC Taxi Overview",
"layout": [
{
"widget": {
"name": "total-trips",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "summary",
"fields": [{"name": "trips", "expression": "`trips`"}],
"disaggregated": True
}
}],
"spec": {
"version": 3,
"widgetType": "counter",
"encodings": {
"value": {"fieldName": "trips", "displayName": "Total Trips"}
},
"frame": {"title": "Total Trips", "showTitle": True}
}
},
"position": {"x": 0, "y": 0, "width": 3, "height": 3}
},
{
"widget": {
"name": "avg-fare",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "summary",
"fields": [{"name": "avg_fare", "expression": "`avg_fare`"}],
"disaggregated": True
}
}],
"spec": {
"version": 3,
"widgetType": "counter",
"encodings": {
"value": {"fieldName": "avg_fare", "displayName": "Avg Fare"}
},
"format": {
"type": "number-currency",
"currencyCode": "USD",
"decimalPlaces": {"type": "max", "places": 2}
},
"frame": {"title": "Average Fare", "showTitle": True}
}
},
"position": {"x": 3, "y": 0, "width": 3, "height": 3}
},
{
"widget": {
"name": "trips-by-zip",
"queries": [{
"name": "main_query",
"query": {
"datasetName": "by_zip",
"fields": [
{"name": "pickup_zip", "expression": "`pickup_zip`"},
{"name": "trip_count", "expression": "`trip_count`"}
],
"disaggregated": True
}
}],
"spec": {
"version": 3,
"widgetType": "bar",
"encodings": {
"x": {"fieldName": "pickup_zip", "scale": {"type": "categorical"}, "displayName": "ZIP"},
"y": {"fieldName": "trip_count", "scale": {"type": "quantitative"}, "displayName": "Trips"}
},
"frame": {"title": "Trips by Pickup ZIP", "showTitle": True}
}
},
"position": {"x": 0, "y": 3, "width": 6, "height": 5}
}
]
}],
"datasets": [
{
"name": "summary",
"displayName": "Summary Stats",
"queryLines": [
"SELECT COUNT(*) as trips, AVG(fare_amount) as avg_fare ",
"FROM samples.nyctaxi.trips "
]
},
{
"name": "by_zip",
"displayName": "Trips by ZIP",
"queryLines": [
"SELECT pickup_zip, COUNT(*) as trip_count ",
"FROM samples.nyctaxi.trips ",
"GROUP BY pickup_zip ",
"ORDER BY trip_count DESC ",
"LIMIT 10 "
]
}
]
}
# Step 4: Deploy
result = create_or_update_dashboard(
display_name="NYC Taxi Dashboard",
parent_path="/Workspace/Users/me/dashboards",
serialized_dashboard=json.dumps(dashboard),
warehouse_id=get_best_warehouse(),
)
print(result["url"])
execute_sqldisaggregated flag (should be true for pre-aggregated data)xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience