@graphit/cli 0.1.18 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { readFile } from "node:fs/promises";
2
2
  import { apiClient } from "../api/client.js";
3
3
  import { getFrontendUrl } from "../config.js";
4
4
  import { output, errorOutput, getOutputFormat } from "../output/format.js";
5
- const REQUIRED_ATTRS = ["data-graphit-id", "data-graphit-label", "data-graphit-kb", "data-graphit-sql", "data-graphit-ds"];
5
+ const REQUIRED_ATTRS = ["data-graphit-id", "data-graphit-label", "data-graphit-sql", "data-graphit-ds"];
6
6
  const KNOWN_ATTRS = new Set([...REQUIRED_ATTRS, "data-graphit-highlight"]);
7
7
  const TYPO_MAP = {
8
8
  "data-graphit-entity": "data-graphit-id",
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/commands/dashboard.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphit/cli",
3
- "version": "0.1.18",
3
+ "version": "0.1.21",
4
4
  "description": "Graphit CLI - Build custom dashboards from any AI coding assistant",
5
5
  "type": "module",
6
6
  "bin": {
@@ -43,7 +43,7 @@ Your HTML must NEVER contain:
43
43
  - `<img src="https://...">` - no external images
44
44
 
45
45
  If you use ANY `src=` or `href=` pointing to a URL, the dashboard will be blank.
46
- All CSS in `<style>`, all JS in `<script>`, all fonts from system stack. The iframe has a built-in runtime (`graphit.chart`, `graphit.table`, `graphit.kpi`) for standard visualizations - use it instead of importing libraries.
46
+ All CSS in `<style>`, all JS in `<script>`, all fonts from system stack. The iframe has a built-in runtime (`graphit.chart`, `graphit.table`, `graphit.kpi`, `graphit.presentation`) for standard visualizations - use it instead of importing libraries.
47
47
 
48
48
  ### 2. ALWAYS query through data sources
49
49
  NEVER query the warehouse directly when a cached data source covers the table. Data sources return in ~100ms. Warehouse queries take ~10s and cost Snowflake credits.
@@ -59,13 +59,12 @@ NEVER query the warehouse directly when a cached data source covers the table. D
59
59
  **Use the data source name in SQL** (e.g. `FROM MARKETING_UA_DS`), not the raw source table. The DS is a KB table - governance rules target it directly, and users recognize DS names from the platform.
60
60
 
61
61
  ### 3. EVERY element must have entity wrapping
62
- Without `data-graphit-*` attributes, elements are invisible to the platform - no click info, no mentions, no KB provenance. Every chart, KPI card, table, and text section needs ALL FIVE attributes:
62
+ Without `data-graphit-*` attributes, elements are invisible to the platform - no click info, no mentions, no KB provenance. Every chart, KPI card, table, and text section needs ALL FOUR attributes:
63
63
 
64
64
  ```html
65
65
  <div data-graphit-id="revenue-trend"
66
66
  data-graphit-label="Revenue Trend"
67
- data-graphit-kb="metric:REVENUE,dimension:REGION,table:ORDERS"
68
- data-graphit-sql="SELECT region, SUM(revenue) FROM orders GROUP BY region"
67
+ data-graphit-sql="SELECT {{dim:REGION}} AS region, {{metric:REVENUE}} AS revenue FROM orders GROUP BY region"
69
68
  data-graphit-ds="ds_abc123">
70
69
  <!-- chart/KPI/table content here -->
71
70
  </div>
@@ -75,11 +74,10 @@ Without `data-graphit-*` attributes, elements are invisible to the platform - no
75
74
  |-----------|--------|---------|
76
75
  | `data-graphit-id` | Unique kebab-case | `"spend-by-source"` |
77
76
  | `data-graphit-label` | Human-readable name | `"Ad Spend by Source"` |
78
- | `data-graphit-kb` | `type:NAME` comma-separated | `"metric:CPI,dimension:MEDIA_SOURCE,table:MARKETING_UA_DS"` |
79
77
  | `data-graphit-sql` | Executable SQL (HTML-encode `<>&"`) | `"SELECT ..."` |
80
78
  | `data-graphit-ds` | Data source ID from `graphit ds list` | `"ds_abc123"` |
81
79
 
82
- KB types: `metric`, `dimension`, `table`, `rule`. Names are UPPER_SNAKE_CASE matching the KB exactly. **Names are unique per type per org** - creating a duplicate name will fail. Check `graphit kb list <type>` first; update the existing asset instead of creating a new one.
80
+ KB asset references are derived automatically from `{{metric:X}}` / `{{dim:X}}` templates in your SQL. The platform's governance compiler resolves these and displays KB asset chips in the entity details panel.
83
81
  Missing any attribute = broken entity. Missing wrapping entirely = invisible to the platform.
84
82
 
85
83
  **SQL must be complete and executable.** The platform runs `data-graphit-sql` against the data source when a user opens the entity's details panel. Write the full query from the `graphit.resolve()` call - never abbreviate, truncate, or use placeholders (`FROM ...`, `SELECT ...`, ellipsis). It MUST use the real DS table name and only columns that exist in the DS - never invented summary columns, CTE aliases, JS variable names, or prose. If the chart's resolve call uses a CTE, put the full WITH query. If JS builds SQL dynamically, store one representative executable variant (e.g. the default date range).
@@ -108,19 +106,32 @@ NEVER embed query results as static JS variables. The dashboard iframe provides
108
106
 
109
107
  ---
110
108
 
109
+ ## How to Work (governs both workflows below)
110
+
111
+ You are a colleague building WITH the user, not a batch job that explores in silence and returns a finished product. Two habits make the difference: **short iterations** and **narration**.
112
+
113
+ **Short iterations.** Do one thing, show it, let the user react, then do the next: explore the KB and report what you found; validate one query and show the rows; build one section and show it. Each small step is a cheap chance for the user to redirect before you have built in the wrong direction. The opposite - exploring silently, deciding by yourself whether the data will work, then dropping a finished 600-line dashboard (or a bulk KB write) on the user - forces them to either accept a wrong result or send you back to the start.
114
+
115
+ **Always narrate.** The user cannot see your command output: the KB you listed, the SQL you ran, the rows that came back are invisible unless you surface them. So after each step, say what you found, what it means, and what you are about to do next. The one exception: if the user says "just build it" or "go", drop the running commentary and work straight through. Match the user's mode.
116
+
117
+ The difference in practice:
118
+ - **Weak (solo):** silently list the KB, silently run several queries, then save a complete dashboard and announce "Done - here's your dashboard."
119
+ - **Strong (collaborative):** "Found a **Marketing UA** data source with `{{metric:CPI}}` and `{{metric:ROAS}}` already defined. Starting with a spend-vs-installs trend - querying now." Then, after showing the rows: "Spend tracks installs except in March. Want that as the first graph, or should I look at ROAS first?"
120
+
121
+ The numbered steps in each workflow run *inside* this loop, not instead of it.
122
+
111
123
  ## Workflow: Dashboard Build
112
124
 
113
- 1. **Ask the user** what dashboard they want. Don't start querying until you know what they need.
114
- 2. **Explore KB** - use `graphit kb list domains` then `graphit kb explore domain <NAME>` to traverse existing assets. Search by concept with `graphit kb search "revenue"`. See `kb-exploration.md` for KB-first discovery, `kb-traversal.md` for tool selection.
115
- 3. **Find a data source** (`graphit ds list`) - prefer cached data sources (~100ms) over live warehouse (~10s).
116
- 4. **Query data to validate** - run queries via the CLI to verify SQL and preview results. Show the user what you found.
117
- 5. **Build HTML** - write `graphit.resolve()` calls for live data + `graphit.chart/table/kpi` for rendering. All CSS in `<style>`, all JS in `<script>`. Write to a local `.html` file.
118
- 6. **Save** with `graphit dashboard update-html <id> --file <path>`. If the response contains `entity_sql_warnings`, an entity's `data-graphit-sql` is missing, matches no data source, or fails against the DS schema - fix the flagged entities and save again before finishing.
119
- 7. Give the user the dashboard URL so they can open it.
125
+ 1. **Understand.** Ask what the dashboard should answer. Don't query until you know the goal - one clarifying question beats a wrong dashboard.
126
+ 2. **Scope to the domain, then work down: domain -> data source -> assets.** Start narrow, not broad. Ask the user which business domain this dashboard is about (or infer it and confirm) - that scopes everything that follows. Then `graphit kb explore domain <NAME>` to see that domain's data sources and the metrics and dimensions defined on them. Reach for broad `graphit kb search` only as a fallback - when the domain is unclear or a concept spans domains. See `kb-discovery.md` and `kb-traversal.md`. Then tell the user what you found - the data source, the metrics and dimensions you'll use (by name), and the graphs you plan - before building.
127
+ 3. **Pick the data source, and handle gaps.** Use the cached data source in that domain (~100ms, preferred over live warehouse at ~10s); use its name in SQL (`FROM MARKETING_UA_DS`). If that data source is missing something you need, first look for a connection to another data source you can join (`graphit kb list relationships`); only if the data genuinely does not exist yet, propose building a new data source rather than forcing a bad query.
128
+ 4. **Validate each query, and show the result.** Write SQL with `{{metric:NAME}}` / `{{dim:NAME}}` reference syntax for KB assets, run it with `--verbose`, and for EVERY query show the user a compact result: the reference-syntax query, a small markdown table of rows, the row count, and the trust tier. If a query returns zero rows or nulls, say so and diagnose (wrong table? filter too narrow?).
129
+ 5. **Get approval, then build.** Once the user is happy with the data and plan, assemble the HTML: `graphit.resolve()` for live data, `graphit.chart/table/kpi` for rendering, every entity wrapped (see HARD CONSTRAINTS), all CSS in `<style>`, all JS in `<script>`. For a large dashboard, add entities incrementally - build one, show it, add the next - rather than generating everything at once. Write to a local `.html` file.
130
+ 6. **Save - prefer entity updates - then hand off.** New dashboard: `graphit dashboard update-html <id> --file <path>`. Changing an existing one: prefer `graphit dashboard update-entity <id> <entity_id>`, which updates a single entity without regenerating (and destroying) the rest. If the response contains `entity_sql_warnings`, an entity's `data-graphit-sql` is missing, matches no data source, or fails the DS schema - fix the flagged entities and save again before reporting done. Confirm the save succeeded, then give the user the dashboard URL.
120
131
 
121
132
  ## Workflow: KB Build / Onboarding
122
133
 
123
- When the user wants to build or populate their KB (from files, schema descriptions, or scratch). Consult `kb-graph-structure.md` for the full graph model, `kb-traversal.md` for tool selection, `kb-actions.md` for the CLI command matrix, `kb-awareness.md` for when to propose asset creation, and `parameterized-metrics.md` for template metrics.
134
+ When the user wants to build or populate their KB (from files, schema descriptions, or scratch). Consult `kb-structure.md` for the full graph model and structural Q&A, `kb-traversal.md` for tool selection, `kb-actions.md` for the CLI command matrix, `kb-discovery.md` for when to propose asset creation, and `parameterized-metrics.md` for template metrics.
124
135
 
125
136
  **Step 1: Audit current KB state.** Before proposing anything, traverse the existing KB:
126
137
 
@@ -128,9 +139,9 @@ When the user wants to build or populate their KB (from files, schema descriptio
128
139
  2. For each domain: `graphit kb explore domain <NAME>` - returns all tables and assets in that domain in one traversal (see `kb-traversal.md` depth guidelines)
129
140
  3. `graphit kb list synonyms` and `graphit kb list relationships` - global assets not scoped to domains
130
141
 
131
- Present a tree summary of what already exists, following the Domain > Table > Topic > Asset hierarchy from `kb-graph-structure.md`.
142
+ Present a tree summary of what already exists, following the Domain > Table > Topic > Asset hierarchy from `kb-structure.md`.
132
143
 
133
- **Step 2: Analyze input.** Read the user's files, schema, or description. Classify every concept by asset type. Use `kb-explanation.md` for asset type definitions (what is a metric vs dimension vs rule). Use `kb-awareness.md` for signals (aggregation = metric, derived grouping = dimension, business constraint = rule, colloquial term = synonym).
144
+ **Step 2: Analyze input.** Read the user's files, schema, or description. Classify every concept by asset type. Use `kb-structure.md` for asset type definitions (what is a metric vs dimension vs rule). Use `kb-discovery.md` for signals (aggregation = metric, derived grouping = dimension, business constraint = rule, colloquial term = synonym).
134
145
 
135
146
  **Step 3: Present a tree-structured plan.** Show what will be created, organized by the KB hierarchy. Mark existing assets with (exists) so the user sees what's new vs what's already there:
136
147
 
@@ -288,6 +299,8 @@ The `dataSourceId` is the ID from `graphit ds list`. The `target` parameter (CSS
288
299
 
289
300
  **Error handling:** `graphit.resolve()` rejects on timeout (120s), bad SQL, or invalid data source ID. Wrap calls in try/catch and show a user-visible error message in the target element on failure. Verify SQL returns data via the CLI before embedding it in HTML.
290
301
 
302
+ **Rate limit:** 120 requests per minute per user per dashboard. Each `graphit.resolve()` call counts as one request. A dashboard with 6 KPIs/charts that refreshes on every filter change uses 6 requests per interaction - budget for ~20 filter changes per minute. If you hit the limit, the API returns a "Too many requests" error with a retry-after hint. Design dashboards to batch all queries in a single `Promise.all` so they count against the same time window rather than spreading across multiple refresh calls.
303
+
291
304
  ### First-paint loading state
292
305
 
293
306
  The dashboard HTML paints before the SDK connects (iframe load + handshake), so the SDK's own spinner cannot cover the first moments. Bake this pure-CSS overlay into the HTML so every chart shows a spinner from the first frame; the SDK adopts it and removes it when that element's `graphit.resolve()` settles (success or error).
@@ -322,6 +335,7 @@ The iframe also provides optional convenience helpers if you want quick standard
322
335
  | `graphit.chart(el, {type, data, x, y, ...})` | Bar, line, area, donut, scatter, stacked-bar, heatmap, funnel, gauge, sparkline |
323
336
  | `graphit.table(el, {data, columns?, maxRows?})` | Styled HTML table. `columns` is a `string[]` of data keys (NOT objects), defaults to `Object.keys(data[0])` |
324
337
  | `graphit.kpi(el, {value, label?, format?})` | KPI card with optional delta |
338
+ | `graphit.presentation(el)` | Full-screen slide deck. Returns builder: `.slide({bg, layout, html})` then `.start()`. See `presentations.md` |
325
339
 
326
340
  These are shortcuts, not requirements. Use them when a standard chart is all you need. Hand-roll when you want full control over the visualization.
327
341
 
@@ -334,8 +348,7 @@ These are shortcuts, not requirements. Use them when a standard chart is all you
334
348
  ```html
335
349
  <div data-graphit-id="spend-by-source"
336
350
  data-graphit-label="Ad Spend by Source"
337
- data-graphit-kb="metric:CPI,dimension:MEDIA_SOURCE,table:MARKETING_UA_DS"
338
- data-graphit-sql="SELECT MEDIA_SOURCE, SUM(APPSFLYER_COST) as spend FROM MARKETING_UA_DS GROUP BY MEDIA_SOURCE ORDER BY spend DESC"
351
+ data-graphit-sql="SELECT {{dim:MEDIA_SOURCE_DIMENSION}} AS source, {{metric:CPI}} AS cpi FROM MARKETING_UA_DS GROUP BY source ORDER BY cpi DESC"
339
352
  data-graphit-ds="ds_abc123">
340
353
  <div id="spend-chart" class="gh-loading">
341
354
  <div class="gh-loading-overlay"><svg class="gh-loading-spin" width="24" height="24" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="var(--graphit-border,#e5e5e5)" stroke-width="2.5"/><path d="M12 2a10 10 0 0 1 10 10" stroke="var(--graphit-accent,#4DB6AC)" stroke-width="2.5" stroke-linecap="round"/></svg></div>
@@ -366,10 +379,8 @@ Detailed knowledge lives in `references/`. Consult the relevant file when you ne
366
379
  |------|-------------|
367
380
  | `dashboard-planning.md` | Building a multi-chart dashboard. Covers framing the question, picking archetype, mandatory rules, metric contracts, anti-patterns. |
368
381
  | `chart-selection.md` | Choosing chart types. Full dimension/measure defaults, perception ranking, cardinality guards, hard caps. |
369
- | `kb-exploration.md` | Starting a build. KB-first discovery, metric vs dimension, naming conventions, formula syntax. |
370
- | `kb-awareness.md` | KB-first planning. When to propose KB asset creation, reuse over reinvention, cross-table referencing, topic assignment. |
371
- | `kb-graph-structure.md` | KB graph model. 9 node types, 5 edge types, multi-membership semantics, domain cascade, tree rendering order. |
372
- | `kb-explanation.md` | Structural Q&A. What are domains, topics, tables, relationships, memory. Why assets appear where they do. |
382
+ | `kb-discovery.md` | Starting a build (domain-first). Domain -> DS -> assets discovery, metric vs dimension, naming, formula syntax, when to propose asset creation, reuse over reinvention, cross-table referencing. |
383
+ | `kb-structure.md` | KB graph model + structural Q&A. Node types, edge types, the vertical home (domain -> DS -> assets) vs horizontal topics, tree order, and how to answer "what is a domain" / "why is X under Y". |
373
384
  | `kb-traversal.md` | Graph queries. Tool selection guide (search vs explore vs read), common query patterns, depth guidelines. |
374
385
  | `kb-actions.md` | Full CRUD matrix. Asset create/edit/delete, topic management, domain assignment cascade, navigation and discovery. |
375
386
  | `parameterized-metrics.md` | Metric templates. ${PARAM:NAME} tokens, child variant auto-generation, editing templates, using variants in queries. |
@@ -378,3 +389,5 @@ Detailed knowledge lives in `references/`. Consult the relevant file when you ne
378
389
  | `graphit-style.md` | Building the HTML. Design principles, typography scale, color system with usage rules, layout patterns (page structure, KPI cards, data tables). |
379
390
  | `chart-patterns.md` | Custom chart implementations. Inline SVG/CSS code for: scatter/bubble, heatmap, funnel, gauge, sparkline, stacked bar, and the shared tooltip pattern. |
380
391
  | `governance.md` | Query governance. Reference syntax, trust tiers, enforceable rules, override flow, governance commands. |
392
+ | `presentations.md` | Slide deck presentations. Builder API, layouts (center/split/full), backgrounds, navigation, live data inside slides. |
393
+ | `data-sources.md` | Building performant, cache-friendly data sources. Why source shape decides dashboard speed; pre-aggregate to query grain, narrow columns, keep high-cardinality dimensions out of the base. |
@@ -0,0 +1,31 @@
1
+ ---
2
+ alwaysApply: false
3
+ description: "Graphit: Consult when creating or shaping a data source. A source's shape (set by its source SQL) decides dashboard speed and whether filter changes are cacheable: pre-aggregate to the query grain, narrow columns, keep high-cardinality dimensions out of the base."
4
+ globs: []
5
+ ---
6
+
7
+ # Data Sources: Building for Speed
8
+
9
+ A data source's shape - set by its source SQL at creation - decides how fast every dashboard built on it will be, and whether filter changes feel instant. Get this right when you create the source; it can't be fixed later in the dashboard SQL.
10
+
11
+ ## Why source shape decides dashboard speed
12
+
13
+ When you change a dashboard filter (e.g. switch country), Graphit answers from a cached, pre-aggregated result instead of re-scanning the whole source - but only when the source is small and already aggregated to the grain you query. Build the source as one row per the grain you'll chart (e.g. month x country x channel) with only the columns you use, and filter changes return in milliseconds. Pull in raw ungrouped rows, hundreds of columns, or thousands-of-values dimensions and the result is too big to cache - every filter change re-scans the entire source and is slow.
14
+
15
+ ## Build it right (in the source SQL)
16
+
17
+ 1. **Pre-aggregate to your query grain.** Use `GROUP BY` so the source has one row per the grain you'll chart (month x country x channel), not one row per raw event. The single biggest speed lever.
18
+ 2. **Select only the columns you'll use.** Every column is downloaded and cached on each query; hundreds of columns slow every dashboard, even ones that touch a few.
19
+ 3. **Keep high-cardinality dimensions out of the base.** Individual ad / campaign / adset names (thousands of values) explode aggregation cost and block filter-caching. If you need them, build a separate filtered drill-down source.
20
+ 4. **Aim small.** A source whose typical query aggregates a few thousand rows is fast and cacheable; a 50M-row, 400-column raw source is slow no matter how the dashboard is written. The size guardrails (>100M rows / >5GB) are the ceiling, not the target.
21
+
22
+ ## Quick check
23
+
24
+ | Lever | Build it right | Anti-pattern |
25
+ |---|---|---|
26
+ | Grain | `GROUP BY` to the grain you chart | One row per raw event |
27
+ | Columns | Only the columns dashboards use | 400+ columns "just in case" |
28
+ | Cardinality | Low-card dimensions in the base; ad/campaign names in a separate drill-down | Thousands-of-values dimensions in the base grain |
29
+ | Size | A few-thousand-row typical aggregation | Sitting at the 100M-row / 5GB ceiling |
30
+
31
+ Build the source small and pre-aggregated, and dashboards on it stay fast and filterable.
@@ -0,0 +1,56 @@
1
+ ---
2
+ alwaysApply: false
3
+ description: "Graphit: Build full-screen slide deck presentations inside canvas dashboards using graphit.presentation(). Builder pattern with layouts, backgrounds, and keyboard navigation."
4
+ globs: []
5
+ ---
6
+
7
+ # Presentations
8
+
9
+ Build slide deck presentations inside Graphit canvas dashboards using `graphit.presentation()`.
10
+
11
+ ## API
12
+
13
+ ```js
14
+ var deck = graphit.presentation('#my-deck');
15
+ deck.slide({ bg: 'dark', layout: 'center', html: '<h1>Title</h1>' });
16
+ deck.slide({ bg: 'white', layout: 'split', html: '<div>Left</div><div>Right</div>' });
17
+ deck.slide({ bg: 'paper', layout: 'full', html: '<div id="charts">...</div>' });
18
+ var ctrl = deck.start();
19
+ ```
20
+
21
+ ## Slide Config
22
+
23
+ | Field | Type | Default | Description |
24
+ |-------|------|---------|-------------|
25
+ | `layout` | `'center'` / `'split'` / `'full'` | `'center'` | Content arrangement |
26
+ | `bg` | `'paper'` / `'white'` / `'dark'` / `'teal'` / hex | `'paper'` | Fixed background |
27
+ | `html` | `string` | `''` | Raw HTML content |
28
+
29
+ ## Layouts
30
+
31
+ - **center**: Centered horizontally/vertically. Title slides, CTAs.
32
+ - **split**: First two child elements become left/right panels. Text + image.
33
+ - **full**: Top-to-bottom flow. Tables, grids, live data.
34
+
35
+ ## Backgrounds (fixed, not theme-aware)
36
+
37
+ | Name | Background | Text |
38
+ |------|-----------|------|
39
+ | `paper` | `#F7F6F2` | `#222224` |
40
+ | `white` | `#FFFFFF` | `#222224` |
41
+ | `dark` | `#222224` | `#F7F6F2` |
42
+ | `teal` | `#4DB6AC` | `#FFFFFF` |
43
+
44
+ ## Navigation
45
+
46
+ Arrow keys, spacebar, Home/End. Prev/Next buttons bottom-right with slide counter.
47
+
48
+ ## Live data works inside slides
49
+
50
+ `graphit.resolve()` + `graphit.chart/table/kpi` work inside slides. Entity wrapping (`data-graphit-*`) works normally.
51
+
52
+ ## Anti-Patterns
53
+
54
+ - Don't use external fonts/images (CSP blocks). Embed as base64 or use system fonts.
55
+ - Don't put scrollable content on slides. Split into multiple slides.
56
+ - One `graphit.presentation()` per dashboard.
@@ -128,12 +128,14 @@ Canvas `graphit.resolve()` queries that follow these shapes serve from a semanti
128
128
  - Literal dates (`>= '2026-01-01'`), never `CURRENT_DATE` expressions
129
129
  - GROUP BY column names or ordinals; ORDER BY / LIMIT allowed (outer only)
130
130
  - CTEs are fine when the CTE body follows the same rules
131
+ - Top-N rank queries: project the sort metric in SELECT (`SELECT dim, SUM(metric) AS rv ... ORDER BY rv DESC LIMIT N`), not only in ORDER BY
131
132
 
132
133
  **Shapes that skip the cache** (fall back to normal execution, still correct):
133
134
  - `COUNT(DISTINCT x)`, window functions, HAVING, QUALIFY
134
135
  - OR / NOT in WHERE
135
136
  - Ratio metrics (`SUM(a)/NULLIF(SUM(b),0)`) - compute client-side or use two resolves
136
137
  - `CURRENT_DATE`-relative predicates
138
+ - Top-N with aggregate only in ORDER BY (`SELECT dim FROM t GROUP BY dim ORDER BY SUM(metric) DESC LIMIT N` - no decomposable aggregate in SELECT)
137
139
 
138
140
  ## Data Source Routing
139
141
 
@@ -28,13 +28,12 @@ Run `graphit ds list` FIRST. If a DS covers your table, use `graphit query "SQL"
28
28
  **Use the DS name in SQL, not the source table name.** Write `FROM MARKETING_UA_DS`, not `FROM MARKETING_UA`. The DS name is what users see in the platform. DuckDB resolves both, but the DS name keeps SQL consistent with the UI.
29
29
 
30
30
  ### 3. EVERY element must have entity wrapping
31
- Without `data-graphit-*` attributes, elements are invisible to the platform. Every chart, KPI card, table, and text section needs ALL FIVE attributes:
31
+ Without `data-graphit-*` attributes, elements are invisible to the platform. Every chart, KPI card, table, and text section needs ALL FOUR attributes:
32
32
 
33
33
  ```html
34
34
  <div data-graphit-id="revenue-trend"
35
35
  data-graphit-label="Revenue Trend"
36
- data-graphit-kb="metric:REVENUE,dimension:REGION,table:ORDERS"
37
- data-graphit-sql="SELECT region, SUM(revenue) FROM orders GROUP BY region"
36
+ data-graphit-sql="SELECT {{dim:REGION}} AS region, {{metric:REVENUE}} AS revenue FROM orders GROUP BY region"
38
37
  data-graphit-ds="ds_abc123">
39
38
  <!-- chart/KPI/table content here -->
40
39
  </div>
@@ -44,11 +43,10 @@ Without `data-graphit-*` attributes, elements are invisible to the platform. Eve
44
43
  |-----------|--------|---------|
45
44
  | `data-graphit-id` | Unique kebab-case | `"spend-by-source"` |
46
45
  | `data-graphit-label` | Human-readable name | `"Ad Spend by Source"` |
47
- | `data-graphit-kb` | `type:NAME` comma-separated | `"metric:CPI,dimension:MEDIA_SOURCE,table:MARKETING_UA_DS"` |
48
46
  | `data-graphit-sql` | Executable SQL (HTML-encode `<>&"`) | `"SELECT ..."` |
49
47
  | `data-graphit-ds` | Data source ID from `graphit ds list` | `"ds_abc123"` |
50
48
 
51
- KB types: `metric`, `dimension`, `table`, `rule`. Names are UPPER_SNAKE_CASE matching the KB exactly. **Names are unique per type per org** - creating a duplicate name will fail. Check `graphit kb list <type>` first; update the existing asset instead of creating a new one.
49
+ KB asset references are derived automatically from `{{metric:X}}` / `{{dim:X}}` templates in your SQL.
52
50
 
53
51
  **SQL must be complete and executable.** The platform runs `data-graphit-sql` against the data source when a user opens the entity's details panel. Write the full query from the `graphit.resolve()` call - never abbreviate, truncate, or use placeholders (`FROM ...`, `SELECT ...`, ellipsis). It MUST use the real DS table name and only columns that exist in the DS - never invented summary columns, CTE aliases, JS variable names, or prose. If the chart's resolve call uses a CTE, put the full WITH query. If JS builds SQL dynamically, store one representative executable variant (e.g. the default date range).
54
52
 
@@ -109,7 +107,7 @@ You are the rendering layer - format and present every CLI result using markdown
109
107
 
110
108
  ## Workflow: KB Build / Onboarding
111
109
 
112
- When the user wants to build or populate their KB from files, schemas, or scratch. Consult companion rules: graphit-kb-graph-structure (graph model), graphit-kb-traversal (tool selection), graphit-kb-actions (CLI commands), graphit-kb-awareness (when to propose assets), graphit-parameterized-metrics (template metrics).
110
+ When the user wants to build or populate their KB from files, schemas, or scratch. Consult companion rules: graphit-kb-graph-structure (graph model), graphit-kb-traversal (tool selection), graphit-kb-actions (CLI commands), graphit-kb-awareness (when to propose assets), graphit-parameterized-metrics (template metrics), graphit-data-sources (shaping sources for speed: pre-aggregate to grain, narrow columns, keep high-cardinality dimensions out of the base).
113
111
 
114
112
  1. **Audit current KB state FIRST.** Traverse, don't just list: `graphit kb list domains`, then `graphit kb explore domain <NAME>` for each (returns full tree in one call). Add `graphit kb list synonyms` and `graphit kb list relationships` for globals. Present tree summary.
115
113
  2. **Analyze input.** Read the user's files/schema. Classify every concept by asset type (see graphit-kb-explanation for definitions, graphit-kb-awareness for signals).
@@ -153,6 +151,8 @@ const result = await graphit.resolve({
153
151
 
154
152
  **Error handling:** Rejects on timeout (120s), bad SQL, or invalid data source ID. Wrap in try/catch.
155
153
 
154
+ **Rate limit:** 120 requests/min per user per dashboard. A 6-chart dashboard uses 6 requests per filter change (~20 changes/min budget). Batch all queries in a single `Promise.all`.
155
+
156
156
  ### First-paint loading state
157
157
 
158
158
  The HTML paints before the SDK connects, so bake a pure-CSS spinner overlay into the page; the SDK adopts it and removes it when that element's `graphit.resolve()` settles (success or error). Add once to the page `<style>`:
@@ -181,8 +181,7 @@ Add the overlay inside EVERY element you pass as `target:` - and ONLY those elem
181
181
  ```html
182
182
  <div data-graphit-id="spend-by-source"
183
183
  data-graphit-label="Ad Spend by Source"
184
- data-graphit-kb="metric:CPI,dimension:MEDIA_SOURCE,table:MARKETING_UA_DS"
185
- data-graphit-sql="SELECT MEDIA_SOURCE, SUM(APPSFLYER_COST) as spend FROM MARKETING_UA_DS GROUP BY MEDIA_SOURCE ORDER BY spend DESC"
184
+ data-graphit-sql="SELECT {{dim:MEDIA_SOURCE_DIMENSION}} AS source, {{metric:CPI}} AS cpi FROM MARKETING_UA_DS GROUP BY source ORDER BY cpi DESC"
186
185
  data-graphit-ds="ds_abc123">
187
186
  <div id="spend-chart" class="gh-loading">
188
187
  <div class="gh-loading-overlay"><svg class="gh-loading-spin" width="24" height="24" viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="10" stroke="var(--graphit-border,#e5e5e5)" stroke-width="2.5"/><path d="M12 2a10 10 0 0 1 10 10" stroke="var(--graphit-accent,#4DB6AC)" stroke-width="2.5" stroke-linecap="round"/></svg></div>
@@ -1,6 +1,6 @@
1
1
  # Chart Patterns
2
2
 
3
- All chart types are available via `graphit.chart()`. All data comes from `graphit.resolve()` - never embed static data.
3
+ The chart types documented below are the native `graphit.chart()` types. Anything not listed here (treemap, sankey, maps, box) is hand-rolled SVG - see `chart-selection.md` for the native-vs-hand-rolled split. All data comes from `graphit.resolve()` - never embed static data.
4
4
 
5
5
  **NEVER use `<canvas>`.** Canvas produces blurry charts inside the sandboxed iframe due to DPI scaling issues.
6
6
 
@@ -54,18 +54,7 @@ Templates are org-specific - they exist only when users have saved them. The age
54
54
 
55
55
  ## Color tokens
56
56
 
57
- | Token | Usage |
58
- |---|---|
59
- | `var(--graphit-accent)` | Primary brand teal |
60
- | `var(--graphit-success)` | Positive/good |
61
- | `var(--graphit-warning)` | Caution |
62
- | `var(--graphit-error)` | Negative/bad |
63
- | `var(--graphit-fg)` | Primary text |
64
- | `var(--graphit-fg-muted)` | Secondary text |
65
- | `var(--graphit-fg-subtle)` | Labels, placeholders |
66
- | `var(--graphit-border)` | Borders, grid lines |
67
- | `var(--graphit-surface-raised)` | Card backgrounds |
68
- | `var(--graphit-surface-sunken)` | Inset areas |
57
+ Use theme CSS variables for all structural colors so charts adapt to light and dark mode. The full token table and usage rules live in `graphit-style.md` - that is the single source; do not re-list tokens here. Chart series colors come from the runtime palette automatically.
69
58
 
70
59
  ## Tooltip pattern (for hand-rolled charts)
71
60
 
@@ -17,23 +17,26 @@ When ambiguous, propose 2-3 options and ask the user. Do not guess.
17
17
 
18
18
  ## Full Chart Type Table
19
19
 
20
- | Data shape | Chart type | Required columns |
21
- |---|---|---|
22
- | Time series | line | 1 temporal + 1 numeric |
23
- | Categories | bar | 1 categorical + 1 numeric |
24
- | Stacked areas | area | 1 temporal/categorical + 1 numeric |
25
- | Part-whole (max 5 slices) | pie | 1 categorical + 1 numeric |
26
- | Single metric | KPI card | 1 numeric |
27
- | Stages | funnel | 1 categorical + 1 numeric |
28
- | Target/progress | gauge | 1 numeric |
29
- | Matrix (unpivoted) | heatmap | 2 categorical + 1 numeric |
30
- | Hierarchy | treemap | 1 categorical + 1 numeric |
31
- | Flows | sankey | 2 categorical + 1 numeric |
32
- | Correlation | scatter | 2 numeric |
33
- | 3 variables | bubble | 3 numeric |
34
- | Countries | choropleth map | 1 categorical + 1 numeric |
35
- | Lat/lng | scatter map | 2 numeric (lat + lng) |
36
- | Detail/raw data | table | any columns |
20
+ `graphit.chart()` renders only the **native** types below and throws `Unsupported graphit.chart type` on anything else. The iframe still lets you draw anything with inline SVG/CSS, so the **hand-rolled** shapes are fully buildable - just not through `graphit.chart()` (see `chart-patterns.md`). Never pass a hand-rolled type name to `graphit.chart()`.
21
+
22
+ | Data shape | Chart type | Render with | Columns |
23
+ |---|---|---|---|
24
+ | Time series | line / area | `graphit.chart` (native) | 1 temporal + 1 numeric |
25
+ | Categories | bar | `graphit.chart` (native) | 1 categorical + 1 numeric |
26
+ | Long category labels | horizontal-bar | `graphit.chart` (native) | 1 categorical + 1 numeric |
27
+ | Part-whole (max 5 slices) | donut / pie | `graphit.chart` (native) | 1 categorical + 1 numeric |
28
+ | Single metric | KPI card | `graphit.kpi` (native) | 1 numeric |
29
+ | Stages | funnel | `graphit.chart` (native) | 1 categorical + 1 numeric |
30
+ | Target / progress | gauge | `graphit.chart` (native) | 1 numeric |
31
+ | Matrix (unpivoted) | heatmap | `graphit.chart` (native) | 2 categorical + 1 numeric |
32
+ | Correlation | scatter | `graphit.chart` (native) | 2 numeric |
33
+ | 3 variables | bubble | `graphit.chart` (native) | 3 numeric |
34
+ | Inline trend | sparkline | `graphit.chart` (native) | 1 numeric series |
35
+ | Detail / raw data | table | `graphit.table` (native) | any columns |
36
+ | Hierarchy | treemap | hand-rolled SVG | 1 categorical + 1 numeric |
37
+ | Flows | sankey | hand-rolled SVG | 2 categorical + 1 numeric |
38
+ | Geographic | map | hand-rolled SVG | region or lat/lng + 1 numeric |
39
+ | Distribution | histogram / box | hand-rolled SVG | 1 numeric |
37
40
 
38
41
  ## Perception Ranking (Cleveland-McGill)
39
42
 
@@ -53,6 +56,8 @@ Position > length > angle > area > color.
53
56
  | KPI vs target | big-number + sparkline | gauge (unbounded) |
54
57
  | 2D matrix / cohort | heatmap | bar with 100+ |
55
58
 
59
+ The native `graphit.chart` first choices here are line, bar, stacked-bar, scatter, bubble, funnel, heatmap, gauge, and sparkline. Treemap, histogram, and box are hand-rolled SVG (see the table above) - draw them, don't pass them to `graphit.chart()`.
60
+
56
61
  ## Cardinality Guards
57
62
 
58
63
  | Cardinality of categorical dim | Action |
@@ -82,6 +82,16 @@ Purpose before data. The first response should mirror the user's intent and ask
82
82
  - User says "active users" - ask: what defines active? (logged in? performed action? within what window?)
83
83
  - User mentions MQL/SQL - ask: how does your org define the handoff? (Same column can mean 13% or 40%)
84
84
 
85
+ ## Performance
86
+
87
+ `graphit.resolve()` is rate-limited to 120 requests/min per user per dashboard. Each call counts as one request. Design for efficiency:
88
+
89
+ - **Single refresh function.** All queries in ONE `Promise.all` inside one `refresh()` function. Never scatter `graphit.resolve()` across independent event handlers or timeouts - that turns one user action into multiple bursts.
90
+ - **Count your queries per interaction.** 6 charts = 6 requests per filter change = 20 changes/min budget. 12 charts = 10 changes/min. If you have 10+ charts with 3+ filters, consider debouncing filter changes (300ms) so rapid clicks don't each trigger a full refresh.
91
+ - **Reuse trend data for KPIs.** If you already fetch a weekly time series (`SELECT week, SUM(spend) ...`), derive the KPI total and sparkline from that result set in JS instead of running a separate aggregate query. One query serves both the chart and the KPI card.
92
+ - **Avoid redundant refreshes.** If a filter only affects some charts, split into targeted refresh functions (`refreshKPIs()`, `refreshCharts()`) so unchanged sections don't re-query.
93
+ - **No polling.** Never `setInterval(refresh, ...)`. Data sources update on their own schedule - a dashboard that polls wastes the entire rate budget.
94
+
85
95
  ## Pre-Build Checklist
86
96
 
87
97
  Before generating the HTML:
@@ -0,0 +1,25 @@
1
+ # Data Sources: Building for Speed
2
+
3
+ A data source's shape - set by its source SQL at creation - decides how fast every dashboard built on it will be, and whether filter changes feel instant. Get this right when you create the source; it can't be fixed later in the dashboard SQL.
4
+
5
+ ## Why source shape decides dashboard speed
6
+
7
+ When you change a dashboard filter (e.g. switch country), Graphit answers from a cached, pre-aggregated result instead of re-scanning the whole source - but only when the source is small and already aggregated to the grain you query. Build the source as one row per the grain you'll chart (e.g. month x country x channel) with only the columns you use, and filter changes return in milliseconds. Pull in raw ungrouped rows, hundreds of columns, or thousands-of-values dimensions and the result is too big to cache - every filter change re-scans the entire source and is slow.
8
+
9
+ ## Build it right (in the source SQL)
10
+
11
+ 1. **Pre-aggregate to your query grain.** Use `GROUP BY` so the source has one row per the grain you'll chart (month x country x channel), not one row per raw event. The single biggest speed lever.
12
+ 2. **Select only the columns you'll use.** Every column is downloaded and cached on each query; hundreds of columns slow every dashboard, even ones that touch a few.
13
+ 3. **Keep high-cardinality dimensions out of the base.** Individual ad / campaign / adset names (thousands of values) explode aggregation cost and block filter-caching. If you need them, build a separate filtered drill-down source.
14
+ 4. **Aim small.** A source whose typical query aggregates a few thousand rows is fast and cacheable; a 50M-row, 400-column raw source is slow no matter how the dashboard is written. The size guardrails (>100M rows / >5GB) are the ceiling, not the target.
15
+
16
+ ## Quick check
17
+
18
+ | Lever | Build it right | Anti-pattern |
19
+ |---|---|---|
20
+ | Grain | `GROUP BY` to the grain you chart | One row per raw event |
21
+ | Columns | Only the columns dashboards use | 400+ columns "just in case" |
22
+ | Cardinality | Low-card dimensions in the base; ad/campaign names in a separate drill-down | Thousands-of-values dimensions in the base grain |
23
+ | Size | A few-thousand-row typical aggregation | Sitting at the 100M-row / 5GB ceiling |
24
+
25
+ Build the source small and pre-aggregated, and dashboards on it stay fast and filterable.
@@ -4,6 +4,8 @@ Consult when the user's data signals match a specific business domain. Each lens
4
4
 
5
5
  Detect the domain from column names and user intent. Apply universal planning rules first (see dashboard-planning.md), then layer domain-specific patterns.
6
6
 
7
+ Several high-value lens charts - **waterfall** (P&L / ARR bridges), **bullet** (KPI vs target), **Lorenz** (revenue concentration), and **histogram** (attainment distribution) - are NOT native `graphit.chart()` types, so `graphit.chart()` throws on those names. Build them as hand-rolled SVG (see `chart-selection.md` for the native-vs-hand-rolled split). The native lens charts (line, bar, stacked-bar, heatmap, funnel, KPI, sparkline) render through `graphit.chart` / `graphit.kpi`.
8
+
7
9
  ---
8
10
 
9
11
  ## Marketing & Attribution
@@ -37,6 +37,17 @@ NEVER use hardcoded hex colors. Use CSS custom properties that automatically ada
37
37
  - **Warning:** `var(--graphit-warning)`
38
38
  - **Danger / bad:** `var(--graphit-error)`
39
39
 
40
+ ### Custom Colors
41
+
42
+ When the user explicitly requests specific colors or a custom color theme, ask for both light and dark mode variants. Write explicit CSS with `.dark` class overrides so the dashboard adapts to both modes:
43
+
44
+ ```css
45
+ .revenue-card { background: #001f3f; color: #ffffff; }
46
+ .dark .revenue-card { background: #0a3d6b; color: #e0e0e0; }
47
+ ```
48
+
49
+ NEVER hardcode a structural color (background, color, border-color) without a `.dark` counterpart. Data/chart series colors (bar fills, line strokes) are exempt - they work in both modes.
50
+
40
51
  ### Multi-Series
41
52
  Use `var(--graphit-accent)` as the primary series. For additional series, choose muted complementary colors that work on both light and dark backgrounds.
42
53