$npx -y skills add girijashankarj/cursor-handbook --skill opensearch-dashboardGenerate OpenSearch Dashboards (Kibana) saved objects — index patterns, visualizations, and dashboards as JSON. Use when the user asks to create dashboards, charts, or visualizations for OpenSearch/Elasticsearch/Kibana.
| 1 | # Skill: OpenSearch Dashboard & Visualization Generator |
| 2 | |
| 3 | Generate exportable OpenSearch Dashboards / Kibana saved objects (index patterns, visualizations, dashboards) as NDJSON for import. |
| 4 | |
| 5 | ## Trigger |
| 6 | When the user asks to create, generate, or design OpenSearch/Kibana dashboards, visualizations, or index patterns. |
| 7 | |
| 8 | ## Prerequisites |
| 9 | - [ ] Index name or pattern known (e.g., `logs-*`, `orders-*`) |
| 10 | - [ ] Field names and types known (or mapping available) |
| 11 | - [ ] Visualization requirements identified (chart type, metrics, dimensions) |
| 12 | |
| 13 | ## Steps |
| 14 | |
| 15 | ### Step 1: Identify Index Pattern |
| 16 | - [ ] Get the index name or pattern from the user |
| 17 | - [ ] List key fields and their types (keyword, text, date, long, float, boolean, geo_point) |
| 18 | - [ ] Identify the time field (usually `@timestamp` or `created_at`) |
| 19 | - [ ] Note any nested or object fields |
| 20 | |
| 21 | ```json |
| 22 | { |
| 23 | "type": "index-pattern", |
| 24 | "attributes": { |
| 25 | "title": "logs-*", |
| 26 | "timeFieldName": "@timestamp", |
| 27 | "fields": "[]" |
| 28 | } |
| 29 | } |
| 30 | ``` |
| 31 | |
| 32 | ### Step 2: Determine Visualization Types |
| 33 | |
| 34 | | Chart Type | Best For | OpenSearch Vis Type | |
| 35 | |-----------|----------|-------------------| |
| 36 | | **Line chart** | Trends over time | `line` | |
| 37 | | **Bar chart** | Comparisons, distributions | `histogram` | |
| 38 | | **Pie chart** | Proportions | `pie` | |
| 39 | | **Area chart** | Cumulative trends | `area` | |
| 40 | | **Data table** | Detailed breakdowns | `table` | |
| 41 | | **Metric** | Single KPI value | `metric` | |
| 42 | | **Gauge** | Value against threshold | `gauge` | |
| 43 | | **Heat map** | Density / correlation | `heatmap` | |
| 44 | | **Markdown** | Text panels, notes | `markdown` | |
| 45 | | **TSVB** | Advanced time series | `metrics` | |
| 46 | | **Vega** | Custom visualizations | `vega` | |
| 47 | |
| 48 | ### Step 3: Design Each Visualization |
| 49 | |
| 50 | For each visualization: |
| 51 | - [ ] Choose chart type from the table above |
| 52 | - [ ] Define metric aggregation (count, sum, avg, min, max, cardinality, percentiles) |
| 53 | - [ ] Define bucket aggregation (date_histogram, terms, range, histogram, filters) |
| 54 | - [ ] Set appropriate time intervals |
| 55 | - [ ] Define split series or sub-aggregations if needed |
| 56 | - [ ] Choose colors and labels |
| 57 | |
| 58 | #### Metric Aggregations |
| 59 | ```json |
| 60 | { |
| 61 | "id": "1", |
| 62 | "enabled": true, |
| 63 | "type": "count", |
| 64 | "params": {}, |
| 65 | "schema": "metric" |
| 66 | } |
| 67 | ``` |
| 68 | |
| 69 | Common metrics: |
| 70 | - `count` — number of documents |
| 71 | - `avg` / `sum` / `min` / `max` — field statistics |
| 72 | - `cardinality` — unique count |
| 73 | - `percentiles` — p50, p95, p99 |
| 74 | - `top_hits` — sample documents |
| 75 | |
| 76 | #### Bucket Aggregations |
| 77 | ```json |
| 78 | { |
| 79 | "id": "2", |
| 80 | "enabled": true, |
| 81 | "type": "date_histogram", |
| 82 | "params": { |
| 83 | "field": "@timestamp", |
| 84 | "interval": "auto", |
| 85 | "min_doc_count": 1 |
| 86 | }, |
| 87 | "schema": "segment" |
| 88 | } |
| 89 | ``` |
| 90 | |
| 91 | Common buckets: |
| 92 | - `date_histogram` — time buckets (interval: 1m, 5m, 1h, 1d, auto) |
| 93 | - `terms` — top N values of a field |
| 94 | - `range` — custom numeric ranges |
| 95 | - `filters` — named query filters |
| 96 | - `histogram` — fixed-width numeric buckets |
| 97 | |
| 98 | ### Step 4: Generate Visualization JSON |
| 99 | |
| 100 | Template for a visualization saved object: |
| 101 | ```json |
| 102 | { |
| 103 | "type": "visualization", |
| 104 | "id": "[unique-id]", |
| 105 | "attributes": { |
| 106 | "title": "[Visualization Title]", |
| 107 | "visState": "{\"title\":\"[title]\",\"type\":\"[vis-type]\",\"aggs\":[...],\"params\":{...}}", |
| 108 | "uiStateJSON": "{}", |
| 109 | "description": "[what this shows]", |
| 110 | "kibanaSavedObjectMeta": { |
| 111 | "searchSourceJSON": "{\"index\":\"[index-pattern-id]\",\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" |
| 112 | } |
| 113 | } |
| 114 | } |
| 115 | ``` |
| 116 | |
| 117 | ### Step 5: Compose Dashboard Layout |
| 118 | - [ ] Arrange visualizations in a grid layout |
| 119 | - [ ] Group related metrics together |
| 120 | - [ ] Place summary/KPI panels at the top |
| 121 | - [ ] Place detailed breakdowns below |
| 122 | - [ ] Add markdown panels for section headers or notes |
| 123 | |
| 124 | Dashboard saved object: |
| 125 | ```json |
| 126 | { |
| 127 | "type": "dashboard", |
| 128 | "id": "[dashboard-id]", |
| 129 | "attributes": { |
| 130 | "title": "[Dashboard Title]", |
| 131 | "description": "[what this dashboard monitors]", |
| 132 | "panelsJSON": "[{\"gridData\":{\"x\":0,\"y\":0,\"w\":24,\"h\":15,\"i\":\"1\"},\"panelIndex\":\"1\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]", |
| 133 | "optionsJSON": "{\"hidePanelTitles\":false,\"useMargins\":true}", |
| 134 | "timeRestore": true, |
| 135 | "timeTo": "now", |
| 136 | "timeFrom": "now-24h", |
| 137 | "refreshInterval": { |
| 138 | "pause": false, |
| 139 | "value": 30000 |
| 140 | }, |
| 141 | "kibanaSavedObjectMeta": { |
| 142 | "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" |
| 143 | } |
| 144 | }, |
| 145 | "references": [ |
| 146 | {"name": "panel_0", "type": "visualization", "id": "[vis-id]"} |
| 147 | ] |
| 148 | } |
| 149 | ``` |
| 150 | |
| 151 | ### Step 6: Generate NDJSON Export |
| 152 | - [ ] Combine all saved objects (index pattern + visualizations + dashboard) |
| 153 | - [ ] Output as NDJSON (one JSON object per line) |
| 154 | - [ ] Include references between objects |
| 155 | |
| 156 | ``` |
| 157 | {"type":"index-pattern","id":"...","attributes":{...}} |
| 158 | {"type":"visualization","id":"...","attributes":{ |