@graphit/cli 0.1.30 → 0.1.38
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.
- package/.claude-plugin/marketplace.json +12 -5
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/commands/kb.js +76 -7
- package/dist/commands/kb.js.map +1 -1
- package/dist/commands/plugin.d.ts +2 -0
- package/dist/commands/plugin.js +39 -0
- package/dist/commands/plugin.js.map +1 -0
- package/dist/commands/setup.js +94 -5
- package/dist/commands/setup.js.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/skill-version.d.ts +20 -0
- package/dist/skill-version.js +139 -0
- package/dist/skill-version.js.map +1 -0
- package/dist/update-check.js +10 -6
- package/dist/update-check.js.map +1 -1
- package/hooks/hooks.json +30 -0
- package/package.json +8 -3
- package/scripts/plugin-status.mjs +285 -0
- package/scripts/sync-plugin-version.mjs +123 -0
- package/skills/graphit/SKILL.md +63 -13
- package/skills/graphit/VERSION.json +5 -0
- package/skills/graphit/cursor/graphit-filters.mdc +56 -0
- package/skills/graphit/cursor/graphit-kb-actions.mdc +12 -3
- package/skills/graphit/graphit.mdc +164 -44
- package/skills/graphit/references/filters.md +127 -0
- package/skills/graphit/references/kb-actions.md +41 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
+
skill_version: "0.1.38"
|
|
2
3
|
alwaysApply: false
|
|
3
4
|
description: "Build Graphit HTML dashboards with KB-aware queries, entity wrapping, and cached data sources"
|
|
4
5
|
globs: []
|
|
@@ -8,6 +9,23 @@ globs: []
|
|
|
8
9
|
|
|
9
10
|
Build custom HTML dashboards from real data using the Graphit CLI.
|
|
10
11
|
|
|
12
|
+
## Session Start
|
|
13
|
+
|
|
14
|
+
Run `graphit plugin status` at the start of every Graphit session and whenever the user asks about Graphit updates, plugin health, or stale instructions. This command is the source of truth for CLI, plugin-bundle, skill, ref, hook, and legacy copied-file version health; do not invent a manual version check.
|
|
15
|
+
If it reports action needed, tell the user the exact remediation it prints before proceeding.
|
|
16
|
+
|
|
17
|
+
## Install / Update Model
|
|
18
|
+
|
|
19
|
+
The Graphit plugin bundle is the default and source of truth for Claude Code and Codex. It contains the CLI, skills, refs, hooks, status script, and manifests. Claude Code/Codex users should update Graphit through their assistant plugin manager, not by running copied-skill setup.
|
|
20
|
+
|
|
21
|
+
`graphit setup` is only for legacy/fallback copied-file installs, mainly Cursor or environments without plugin support. If `graphit plugin status` reports Claude Code/Codex copied snapshots, tell the user to remove them with `graphit setup --remove-legacy-copies` after confirming the plugin is installed. Use `graphit setup --legacy-copy` only when the plugin path is unavailable.
|
|
22
|
+
|
|
23
|
+
## CLI Health Gate
|
|
24
|
+
|
|
25
|
+
ALWAYS run `graphit plugin status` before diagnosing, retrying, or inventing a workaround when Graphit CLI behavior looks wrong. This includes unknown commands, unrecognized flags, missing commands described in this rule, stale-looking output, copied-skill warnings, non-zero exits with unclear messages, or the user saying Graphit/CLI/plugin/skill is not working.
|
|
26
|
+
If `graphit plugin status` reports action needed, stop and tell the user the exact remediation first. Do not continue with stale instructions unless the user explicitly asks you to proceed anyway.
|
|
27
|
+
Do NOT suggest updating for normal operational failures (expired auth, bad SQL, entity not found).
|
|
28
|
+
|
|
11
29
|
## HARD CONSTRAINTS (violating these produces a broken dashboard)
|
|
12
30
|
|
|
13
31
|
### 1. ZERO external resources
|
|
@@ -18,14 +36,17 @@ Your HTML must NEVER contain:
|
|
|
18
36
|
- `<img src="https://...">` - no external images
|
|
19
37
|
|
|
20
38
|
If you use ANY `src=` or `href=` pointing to a URL, the dashboard will be blank.
|
|
21
|
-
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.
|
|
39
|
+
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.
|
|
22
40
|
|
|
23
41
|
### 2. ALWAYS query through data sources
|
|
24
42
|
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.
|
|
25
43
|
|
|
26
|
-
|
|
44
|
+
**Before writing ANY query:**
|
|
45
|
+
1. Run `graphit ds list` to see what data sources exist
|
|
46
|
+
2. If a DS covers your table, use `graphit query "SQL" --ds <id>` (DuckDB syntax)
|
|
47
|
+
3. Only use `graphit query "SQL" --warehouse --connection <id>` if NO data source exists and the user approves
|
|
27
48
|
|
|
28
|
-
**Use the
|
|
49
|
+
**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.
|
|
29
50
|
|
|
30
51
|
### 3. EVERY element must have entity wrapping
|
|
31
52
|
Without `data-graphit-*` attributes, elements are invisible to the platform. Every chart, KPI card, table, and text section needs ALL FOUR attributes:
|
|
@@ -48,7 +69,7 @@ Without `data-graphit-*` attributes, elements are invisible to the platform. Eve
|
|
|
48
69
|
|
|
49
70
|
KB asset references are derived automatically from `{{metric:X}}` / `{{dim:X}}` templates in your SQL.
|
|
50
71
|
|
|
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
|
|
72
|
+
**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. It MUST use the real DS table name and only columns that exist in the DS.
|
|
52
73
|
|
|
53
74
|
**Label = visible title.** The `data-graphit-label` MUST match the card's visible heading exactly.
|
|
54
75
|
|
|
@@ -65,13 +86,63 @@ NEVER embed query results as static JS variables. The dashboard iframe provides
|
|
|
65
86
|
**Wrong:** Embedding results as `const data = [{...}, ...]` in the HTML.
|
|
66
87
|
**Right:** Using `graphit.resolve({sql, dataSourceId})` in a `<script>` block so data refreshes automatically.
|
|
67
88
|
|
|
89
|
+
### 6. NEVER build a dashboard on ad-hoc SQL when KB assets are missing
|
|
90
|
+
The KB-readiness gate in Workflow Step 4 is BLOCKING. When you check the KB and find it is missing metrics or dimensions the dashboard needs, you MUST create them before writing any HTML. Do not offer to skip. Do not ask "should I use ad-hoc SQL instead?" Do not frame it as the user's choice. The gate exists because ad-hoc SQL bypasses governance, breaks provenance, and produces untrustworthy graphs. The only question to ask is "here's my KB plan - approve?" not "should I follow my own instructions?"
|
|
91
|
+
|
|
92
|
+
**Wrong:** "The KB has no metrics defined for caching performance. Should I build the dashboard with ad-hoc SQL or create KB assets first? Your call."
|
|
93
|
+
**Right:** "The KB is missing 3 metrics this dashboard needs: RESULT_CACHE_HIT_RATE, DS_QUERY_LATENCY, QUERY_FAILURE_RATE. Creating them now - here's the plan: [tree]. Approve?"
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## How to Work (governs both workflows below)
|
|
98
|
+
|
|
99
|
+
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**.
|
|
100
|
+
|
|
101
|
+
**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.
|
|
102
|
+
|
|
103
|
+
**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. After each step, say what you found, what it means, and what you are about to do next. Exception: if the user says "just build it" or "go", drop the commentary and work straight through.
|
|
104
|
+
|
|
105
|
+
**Workflow gates are not optional.** When a step says BLOCKING or STOP, execute it. Do not offer to skip, do not say "your call", do not reframe it as optional. The KB-readiness gate (Step 4) is the most common one: if the KB is missing metrics or dimensions the dashboard needs, create them before writing HTML. The only question to ask is "here's my KB plan - approve?" not "should I follow the plan?"
|
|
106
|
+
|
|
107
|
+
- **Wrong:** "The KB is empty. Should I skip KB creation and use ad-hoc SQL, or build assets first?"
|
|
108
|
+
- **Right:** "The KB is empty. Here are the 7 metrics and 4 dimensions this dashboard needs: [tree]. Approve so I can create them?"
|
|
109
|
+
|
|
110
|
+
The difference in practice:
|
|
111
|
+
- **Weak (solo):** silently list the KB, silently run several queries, then save a complete dashboard and announce "Done."
|
|
112
|
+
- **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 rows: "Spend tracks installs except in March. Want that as the first graph, or should I look at ROAS first?"
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Workflow: Dashboard Build
|
|
117
|
+
|
|
118
|
+
1. **Understand.** Ask what the dashboard should answer. Don't query until you know the goal - one clarifying question beats a wrong dashboard.
|
|
119
|
+
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). 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. Tell the user what you found - the data source, the metrics and dimensions you'll use, and the graphs you plan - before building.
|
|
120
|
+
3. **Understand the business question.** Before touching SQL, apply the domain lenses to classify the user's goal. Match column names and user intent against the five lens detection signals (Marketing, Finance, Product/Growth, Operational, Sales). Once the lens is identified: check its canonical metrics and clarification questions. Ask at most ONE clarifying question using collaborative phrasing - state your assumption and offer to redirect. Map the user's goal to specific metric and dimension concepts the dashboard needs - name them. Show the user the concept list, then check it against the KB.
|
|
121
|
+
4. **KB-readiness gate (BLOCKING).** Check the KB against the specific concepts from step 3 - not a vague "does the KB have stuff?" but "does the KB have the ROAS, CPI, and LTV:CAC that this marketing dashboard needs?" Show a compact gap table: which concepts exist (with formula) and which are missing. If covered, proceed to step 5. If missing key assets, STOP - do not build on raw ad-hoc SQL. Propose creating the assets, route to KB Build workflow first, return here after.
|
|
122
|
+
5. **Pick the data source, and handle gaps.** Use the cached data source in that domain (~100ms); use its name in SQL (`FROM MARKETING_UA_DS`). If something is missing, look for relationships (`graphit kb list relationships`) before proposing a new data source.
|
|
123
|
+
6. **Validate each query, and show the result.** Write SQL with `{{metric:NAME}}` / `{{dim:NAME}}` reference syntax, run with `--verbose`, and for EVERY query show the user: the reference-syntax query, a small markdown table of rows, the row count, and the trust tier. If zero rows or nulls, diagnose.
|
|
124
|
+
7. **Get approval, then build.** Once the user is happy with data and plan, assemble the HTML: `graphit.resolve()` for live data, `graphit.chart/table/kpi` for rendering, every entity wrapped, all CSS in `<style>`, all JS in `<script>`. For large dashboards, add entities incrementally.
|
|
125
|
+
8. **Save - prefer entity updates - then hand off.** New dashboard: `graphit dashboard update-html <id> --file <path>`. Existing: prefer `graphit dashboard update-entity <id> <entity_id>`. If `entity_sql_warnings` appear, fix and re-save. Give the user the dashboard URL.
|
|
126
|
+
|
|
127
|
+
## Workflow: KB Build / Onboarding
|
|
128
|
+
|
|
129
|
+
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).
|
|
130
|
+
|
|
131
|
+
1. **Audit current KB state FIRST.** `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.
|
|
132
|
+
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).
|
|
133
|
+
3. **Present a tree plan** showing Domain > Table > Topic > Asset hierarchy. Mark existing assets with (exists), new ones with **NEW**. Include global items (synonyms, relationships) at the bottom. Propose parameterized templates for variant metrics (D7/D30/D90).
|
|
134
|
+
4. **Wait for approval.** Do not create anything until confirmed.
|
|
135
|
+
5. **Execute top-down.** Create in order: domains, topics, metrics (with --topics), dimensions, rules, synonyms, relationships, then attachments (domain->table, secondary_tables). Each create validates against real data and returns sample results; if validation fails (422), fix the formula before retrying. Use `--skip-validate` for batch speed.
|
|
136
|
+
6. **After each metric/dimension/rule create**, present the `validation` section: show the sample query, render sample data as a table, surface warnings. If validation was skipped, say why. If it failed (422), show the error and fix.
|
|
137
|
+
7. **Verify.** Re-traverse with `graphit kb explore domain <NAME>`, confirm counts match plan.
|
|
138
|
+
|
|
68
139
|
---
|
|
69
140
|
|
|
70
141
|
## Presenting Results to the User
|
|
71
142
|
|
|
72
143
|
You are the rendering layer - format and present every CLI result using markdown. Never silently consume output.
|
|
73
144
|
|
|
74
|
-
**Formatting fundamentals:** Bold every KB asset/table/DS name (**CPI**, **MARKETING_UA_DS**). Markdown tables for tabular data. Code blocks (```sql) for every SQL query. Format numbers
|
|
145
|
+
**Formatting fundamentals:** Bold every KB asset/table/DS name (**CPI**, **MARKETING_UA_DS**). Markdown tables for tabular data. Code blocks (```sql) for every SQL query. Format numbers (commas, $, %). Narrate between steps.
|
|
75
146
|
|
|
76
147
|
**After `graphit query`** - ground in KB, show five sections:
|
|
77
148
|
1. **KB Assets:** bold names of all referenced metrics/dimensions/tables
|
|
@@ -81,48 +152,91 @@ You are the rendering layer - format and present every CLI result using markdown
|
|
|
81
152
|
5. **Governance:** tier, KB refs, rules enforced (**bold names**)
|
|
82
153
|
- For ad-hoc queries: show query + results + governance, suggest KB reference equivalent
|
|
83
154
|
|
|
84
|
-
**After `graphit kb list`** - count summary + table with bold names
|
|
85
|
-
|
|
86
|
-
- Footer summarizing parameterized vs pre-baked
|
|
87
|
-
|
|
88
|
-
**After `graphit kb get`** - entity heading + key-value table:
|
|
89
|
-
- `### **CPI** (metric, verified)` with description in italics
|
|
90
|
-
- Key-value table: Table, Calculation, Parameters, Topics, Dimensions
|
|
91
|
-
|
|
155
|
+
**After `graphit kb list`** - count summary + table with bold names
|
|
156
|
+
**After `graphit kb get`** - entity heading + key-value table
|
|
92
157
|
**After `graphit kb search`** - result count + table with type column
|
|
93
158
|
**After `graphit kb explore`** - tree structure: Asset > Tables > Dimensions > Rules
|
|
94
159
|
**After `graphit ds list`** - table with Name, ID, Rows, Status, Governed + recommend which DS to use
|
|
95
|
-
**After `graphit ds create`** - shows creation progress (materializing -> scanning schema -> verification link)
|
|
96
|
-
**After `graphit ds verify <id>`** - scans schema
|
|
97
|
-
**After `graphit ds refresh --all`** - live status table showing each DS name, status
|
|
98
|
-
**After `graphit governance status`** - mode + conformance table
|
|
160
|
+
**After `graphit ds create`** - shows creation progress (materializing -> scanning schema -> verification link)
|
|
161
|
+
**After `graphit ds verify <id>`** - scans schema and prints verification link
|
|
162
|
+
**After `graphit ds refresh --all`** - live status table showing each DS name, status, row count
|
|
163
|
+
**After `graphit governance status`** - mode + conformance table
|
|
99
164
|
**After errors** - bold error message + actionable fix suggestion
|
|
100
165
|
|
|
101
166
|
**Never:** run queries silently, present raw JSON, skip governance footer, omit SQL code blocks, show tables without bold asset names.
|
|
102
167
|
|
|
103
168
|
---
|
|
104
169
|
|
|
105
|
-
##
|
|
170
|
+
## Commands
|
|
171
|
+
|
|
172
|
+
| Command | Description |
|
|
173
|
+
|---------|-------------|
|
|
174
|
+
| `graphit auth login` | Authenticate with Graphit |
|
|
175
|
+
| `graphit auth status` | Show current auth status |
|
|
176
|
+
| `graphit auth logout` | Clear stored credentials |
|
|
177
|
+
| `graphit plugin status` | Check plugin bundle, CLI, skill, refs, hooks, copied legacy files, and update health |
|
|
178
|
+
| `graphit setup` | Legacy copied-file fallback for Cursor/non-plugin environments |
|
|
179
|
+
| `graphit setup --remove-legacy-copies` | Remove old Claude Code/Codex copied snapshots so the plugin bundle is source of truth |
|
|
180
|
+
| `graphit kb list <type>` | List entities: metric, dimension, table, rule, domain, synonym, template, relationship, topic |
|
|
181
|
+
| `graphit kb get <type> <name>` | Full entity details by name |
|
|
182
|
+
| `graphit kb search <query>` | Search across all KB types (optional `--type` filter) |
|
|
183
|
+
| `graphit kb explore metric <name>` | Metric -> tables -> dimensions graph |
|
|
184
|
+
| `graphit kb explore domain <name>` | Domain -> tables -> assets full tree (preferred starting point) |
|
|
185
|
+
| `graphit kb create metric --name X --sql "..." --table T` | Create a metric (optional `--default-dimensions "D1,D2"`). Validates against real data; blocks on failure (422). Use `--skip-validate` to bypass. |
|
|
186
|
+
| `graphit kb create dimension --name X --expr "..." --table T` | Create a dimension (type auto-inferred; override with `--type` / `--output-type`). Validates; shows cardinality + NULL rate. |
|
|
187
|
+
| `graphit kb create rule --name X --sql "..." --table T` | Create a rule. Validates as WHERE clause; warns if zero rows match. |
|
|
188
|
+
| `graphit kb create synonym --term X --canonical Y --type metric` | Create a synonym (type: metric, column, table) |
|
|
189
|
+
| `graphit kb create domain --name X` | Create a domain (optional `--color "#hex"`) |
|
|
190
|
+
| `graphit kb create relationship --name X --primary-table T --primary-column C --related-table T2 --related-column C2` | Create a JOIN relationship |
|
|
191
|
+
| `graphit kb create topic --name X` | Create a topic (business-concept tag) |
|
|
192
|
+
| `graphit kb create template --name X --file template.html` | Save a reusable chart template (--file or --render-code) |
|
|
193
|
+
| `graphit kb update metric NAME --topics "A,B"` | Attach topics to a metric (also works on dimension, rule) |
|
|
194
|
+
| `graphit kb update metric NAME --default-dimensions "D1,D2"` | Set default grouping dimensions for a metric |
|
|
195
|
+
| `graphit kb update metric NAME --secondary-tables "T1,T2"` | Reference metric onto additional tables (also dimension, rule) |
|
|
196
|
+
| `graphit kb update metric NAME --parameters '<json>'` | Set parameterized metric template (JSON array, or `--parameters-file`) |
|
|
197
|
+
| `graphit kb update table NAME --domain DOMAIN` | Assign domain to table (cascades to all assets on table) |
|
|
198
|
+
| `graphit kb update domain NAME --color "#hex"` | Update domain color |
|
|
199
|
+
| `graphit kb update synonym TERM --canonical Y` | Update synonym target |
|
|
200
|
+
| `graphit kb update relationship NAME --primary-column C` | Update relationship columns |
|
|
201
|
+
| `graphit kb update topic NAME --description "..."` | Update topic description |
|
|
202
|
+
| `graphit kb update template NAME --file template.html` | Update template render code |
|
|
203
|
+
| `graphit kb update <type> <name> --description "..."` | Update description (all types) |
|
|
204
|
+
| `graphit kb delete <type> <name> --yes` | Delete any entity (all types supported) |
|
|
205
|
+
| `graphit ds list` | List cached data sources (use these for fast queries) |
|
|
206
|
+
| `graphit ds create --name "..." --sql "..."` | Create DS, poll until ready, auto-scan schema, print verification link |
|
|
207
|
+
| `graphit ds create --name "..." --sql "..." --skip-scan` | Create DS without auto-scan |
|
|
208
|
+
| `graphit ds verify <id>` | Scan schema and print verification link for an unverified DS |
|
|
209
|
+
| `graphit ds refresh --all` | Refresh all data sources, wait for completion with live status |
|
|
210
|
+
| `graphit ds refresh --all --skip-empty` | Refresh non-empty data sources only |
|
|
211
|
+
| `graphit ds refresh --all --no-wait` | Trigger all refreshes without waiting |
|
|
212
|
+
| `graphit ds refresh <id> [id2...]` | Refresh one or more data sources by ID |
|
|
213
|
+
| `graphit ds update <id> --governed-mode on\|off` | Enable/disable governed mode on a data source |
|
|
214
|
+
| `graphit ds update <id> --max-rows N` | Set max rows cap on a data source |
|
|
215
|
+
| `graphit query "<sql>" --ds <id>` | Query cached data source (~100ms) |
|
|
216
|
+
| `graphit query "<sql>" --ds <id> --override-rules RULE1 RULE2` | Query with governance rule overrides |
|
|
217
|
+
| `graphit query "<sql>" --ds <id> --verbose` | Show expanded SQL and trust tier |
|
|
218
|
+
| `graphit query "<sql>" --warehouse --connection <id>` | Query live Snowflake (~10s) |
|
|
219
|
+
| `graphit governance status` | Show governance mode and conformance stats |
|
|
220
|
+
| `graphit governance set <mode>` | Set governance mode (observe/warn/strict) |
|
|
221
|
+
| `graphit governance audit` | View recent governance audit events |
|
|
222
|
+
| `graphit dashboard create --name "..."` | Create dashboard (returns ID) |
|
|
223
|
+
| `graphit dashboard get-html <id>` | Get current HTML content of a dashboard |
|
|
224
|
+
| `graphit dashboard update-html <id> --file <path>` | Upload HTML to dashboard (full page replace) |
|
|
225
|
+
| `graphit dashboard update-entity <id> <entity_id> --file <path>` | Update a single entity's inner HTML (optional `--title`, `--stdin`) |
|
|
226
|
+
| `graphit dashboard list` | List dashboards with sharing metadata (permission, visibility, teams, is_locked) |
|
|
227
|
+
| `graphit dashboard list --view mine` | Only dashboards you own |
|
|
228
|
+
| `graphit dashboard list --view shared` | Only dashboards shared with you |
|
|
229
|
+
| `graphit dashboard list --team <id>` | Only dashboards shared with a specific team |
|
|
230
|
+
| `graphit team list` | List teams you belong to (org admins see all) |
|
|
231
|
+
| `graphit dashboard export <id>` | Export as PNG (default) or PDF (`--format pdf`, `--output <path>`). Presentations auto-export as multi-page PDF. Custom multi-page: `data-graphit-page="N"` (0-indexed). |
|
|
232
|
+
| `graphit metadata schemas --connection <id>` | List Snowflake schemas |
|
|
233
|
+
| `graphit metadata tables --schema <name> --connection <id>` | List tables in a Snowflake schema |
|
|
234
|
+
| `graphit connector list` | List active connections |
|
|
235
|
+
| `graphit connector add snowflake-keypair --account X --user Y --key <path> --warehouse W` | Add Snowflake keypair connection (admin only). OAuth and GitHub connections are configured via the web app. |
|
|
236
|
+
| `graphit connector test <id>` | Test a connection |
|
|
237
|
+
| `graphit connector remove <id> --yes` | Remove a connection (admin only) |
|
|
106
238
|
|
|
107
|
-
|
|
108
|
-
2. **Explore KB** to understand available metrics, dimensions, tables, and rules.
|
|
109
|
-
3. **Find a data source** (`graphit ds list`) - prefer cached data sources over live warehouse.
|
|
110
|
-
4. **Query data to validate** - run queries via the CLI to verify SQL and preview results.
|
|
111
|
-
5. **Build HTML** - write `graphit.resolve()` calls for live data + `graphit.chart/table/kpi` for rendering. All CSS in `<style>`, all JS in `<script>`.
|
|
112
|
-
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.
|
|
113
|
-
7. Give the user the dashboard URL.
|
|
114
|
-
8. **Export** with `graphit dashboard export <id> --format pdf`. Presentations export as multi-page PDF automatically. For custom multi-page layouts, add `data-graphit-page="N"` (0-indexed) to each section.
|
|
115
|
-
|
|
116
|
-
## Workflow: KB Build / Onboarding
|
|
117
|
-
|
|
118
|
-
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).
|
|
119
|
-
|
|
120
|
-
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.
|
|
121
|
-
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).
|
|
122
|
-
3. **Present a tree plan** showing Domain > Table > Topic > Asset hierarchy. Mark existing assets with (exists), new ones with **NEW**. Include global items (synonyms, relationships) at the bottom. Propose parameterized templates for variant metrics (D7/D30/D90).
|
|
123
|
-
4. **Wait for approval.** Do not create anything until confirmed.
|
|
124
|
-
5. **Execute top-down.** Create in order: domains, topics, metrics (with --topics), dimensions, rules, synonyms, relationships, then attachments (domain->table, secondary_tables).
|
|
125
|
-
6. **Verify.** Re-traverse with `graphit kb explore domain <NAME>`, confirm counts match plan.
|
|
239
|
+
---
|
|
126
240
|
|
|
127
241
|
## Query Governance and Reference Syntax
|
|
128
242
|
|
|
@@ -145,6 +259,8 @@ graphit ds update <id> --governed-mode on # enable governance on DS
|
|
|
145
259
|
|
|
146
260
|
Reference syntax in `graphit.resolve()` calls works the same way - server expands at query time. Trust tiers: **governed** (KB refs), **verified** (matches KB), **ad-hoc** (inline). Strict mode blocks ad-hoc on governed DSes.
|
|
147
261
|
|
|
262
|
+
---
|
|
263
|
+
|
|
148
264
|
## graphit.resolve() - Live Data API
|
|
149
265
|
|
|
150
266
|
```js
|
|
@@ -163,7 +279,7 @@ const result = await graphit.resolve({
|
|
|
163
279
|
|
|
164
280
|
### First-paint loading state
|
|
165
281
|
|
|
166
|
-
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
|
|
282
|
+
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. Add once to the page `<style>`:
|
|
167
283
|
|
|
168
284
|
```css
|
|
169
285
|
@keyframes gh-spin{to{transform:rotate(360deg)}}
|
|
@@ -172,17 +288,21 @@ The HTML paints before the SDK connects, so bake a pure-CSS spinner overlay into
|
|
|
172
288
|
.gh-loading-spin{animation:gh-spin .7s linear infinite}
|
|
173
289
|
```
|
|
174
290
|
|
|
175
|
-
Add the overlay inside EVERY element you pass as `target:` - and ONLY those elements
|
|
291
|
+
Add the overlay inside EVERY element you pass as `target:` - and ONLY those elements. Keep the class names exactly as shown; they are the contract the SDK uses. NEVER write text placeholders ("Loading...") - they never animate and make slow loads look stuck. See the canonical pattern below for the overlay markup.
|
|
176
292
|
|
|
177
293
|
### Runtime chart helpers
|
|
178
294
|
|
|
179
295
|
| Helper | Usage |
|
|
180
296
|
|---|---|
|
|
181
|
-
| `graphit.chart(el, {type, data, x, y, ...})` | Bar, line, area, donut, scatter, stacked-bar, heatmap, funnel, gauge, sparkline |
|
|
182
|
-
| `graphit.table(el, {data, columns?, maxRows?})` | Styled HTML table. `columns` is a `string[]` of data keys (NOT objects)
|
|
183
|
-
| `graphit.kpi(el, {value, label?, format?})` | KPI card with optional delta |
|
|
297
|
+
| `graphit.chart(el, {type, data, x, y, ...})` | Bar, horizontal-bar, line, area, donut, scatter, stacked-bar, heatmap, funnel, gauge, sparkline |
|
|
298
|
+
| `graphit.table(el, {data, columns?, maxRows?})` | Styled HTML table. `columns` is a `string[]` of data keys (NOT objects) |
|
|
299
|
+
| `graphit.kpi(el, {value, label?, format?})` | KPI card with optional delta (`compareValue`, `compareLabel`) |
|
|
300
|
+
| `graphit.presentation(el)` | Full-screen slide deck. Returns builder: `.slide({bg, layout, html})` then `.start()`. See graphit-presentations rule. |
|
|
301
|
+
| `graphit.filter(id, {label, field?, default?})` | Headless filter (zero DOM). Returns `{get, set, subscribe}` handle. See graphit-filters rule. |
|
|
302
|
+
| `graphit.param(id, {label, default?, options?})` | Headless parameter (zero DOM). Same handle API. |
|
|
303
|
+
| `graphit.bind(el, {sql, dataSourceId, params, deps?, render})` | Auto re-resolve on filter/param change. See graphit-filters rule. |
|
|
184
304
|
|
|
185
|
-
`graphit.chart` types: `"bar"`, `"line"`, `"area"`, `"donut"` (alias `"pie"`), `"scatter"` (alias `"bubble"`), `"stacked-bar"` (alias `"stacked"`), `"heatmap"`, `"funnel"`, `"gauge"`, `"sparkline"`. Config: `x
|
|
305
|
+
`graphit.chart` types: `"bar"`, `"horizontal-bar"` (alias `"hbar"`), `"line"`, `"area"`, `"donut"` (alias `"pie"`), `"scatter"` (alias `"bubble"`), `"stacked-bar"` (alias `"stacked"`), `"heatmap"`, `"funnel"`, `"gauge"`, `"sparkline"`. Config: `x`, `y`, `series`, `title`, `height` (140-900px), `valueFormat` (`"currency"` | `"percent"` | `"number"`), `colors`. Dual axis (bar/line/area): `y2`, `y2Format`, `y2Label`; `y2` and `series` are mutually exclusive. Scatter adds: `size`, `label`. Gauge: `min`, `max`, `format`. Sparkline: `width`, `showValue`.
|
|
186
306
|
|
|
187
307
|
### Canonical pattern - entity with live data
|
|
188
308
|
|
|
@@ -210,4 +330,4 @@ Add the overlay inside EVERY element you pass as `target:` - and ONLY those elem
|
|
|
210
330
|
</script>
|
|
211
331
|
```
|
|
212
332
|
|
|
213
|
-
For detailed chart selection
|
|
333
|
+
For detailed chart selection, dashboard planning, SQL reference, domain lenses, visual style, KB structure, chart patterns, governance, presentations, filters, and data source shaping, see the companion rule files.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Headless Filters, Parameters, and Saved Views
|
|
2
|
+
|
|
3
|
+
## Core Concept
|
|
4
|
+
|
|
5
|
+
`graphit.filter()` and `graphit.param()` are headless JS registrations. They create NO DOM elements. You build 100% of the filter control's markup (any HTML, SVG, or CSS). The registration manages state so values can be snapshotted into saved views and survive page reloads.
|
|
6
|
+
|
|
7
|
+
## graphit.filter(id, options)
|
|
8
|
+
|
|
9
|
+
Register a named filter. Returns a handle for reading, writing, and subscribing to value changes.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const country = graphit.filter('country', {
|
|
13
|
+
label: 'Country', // display label (used in saved view UI)
|
|
14
|
+
field: 'COUNTRY', // metadata for the platform (optional)
|
|
15
|
+
default: 'US', // initial value if no saved view overrides it
|
|
16
|
+
})
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Handle API:
|
|
20
|
+
- `country.get()` - current value
|
|
21
|
+
- `country.set(value)` - update value (triggers subscribers + bound re-resolves)
|
|
22
|
+
- `country.subscribe(cb)` - called on change; returns unsubscribe fn
|
|
23
|
+
|
|
24
|
+
## graphit.param(id, options)
|
|
25
|
+
|
|
26
|
+
Same API as filter but semantically a parameter (not tied to a KB field). Use for user-controlled inputs like date range pickers, threshold sliders, or toggle switches.
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const topN = graphit.param('top_n', { label: 'Top N', default: 10, options: [5, 10, 20, 50] })
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Wiring a Control
|
|
33
|
+
|
|
34
|
+
The registration renders nothing. Wire any HTML element you build:
|
|
35
|
+
|
|
36
|
+
```html
|
|
37
|
+
<select id="country-picker">
|
|
38
|
+
<option value="US">US</option>
|
|
39
|
+
<option value="IL">Israel</option>
|
|
40
|
+
</select>
|
|
41
|
+
<script>
|
|
42
|
+
const country = graphit.filter('country', { label: 'Country', default: 'US' });
|
|
43
|
+
const picker = document.getElementById('country-picker');
|
|
44
|
+
picker.value = country.get();
|
|
45
|
+
picker.onchange = () => country.set(picker.value);
|
|
46
|
+
country.subscribe(v => { picker.value = v; }); // restores on view apply or page reload
|
|
47
|
+
</script>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## graphit.bind(el, options) - Reactive Data Binding
|
|
51
|
+
|
|
52
|
+
Connects a data entity to filter dependencies so it re-resolves automatically on change.
|
|
53
|
+
|
|
54
|
+
```js
|
|
55
|
+
graphit.bind(document.getElementById('revenue-chart'), {
|
|
56
|
+
sql: 'SELECT date, SUM(revenue) AS revenue FROM orders WHERE country = :country GROUP BY 1',
|
|
57
|
+
dataSourceId: 'ds_abc123',
|
|
58
|
+
params: () => ({ country: graphit.state.get('country') }),
|
|
59
|
+
deps: ['country'], // state keys that trigger re-resolve (inferred from params if omitted)
|
|
60
|
+
render: (result, el) => {
|
|
61
|
+
graphit.chart(el, { type: 'line', data: result.data, x: 'date', y: 'revenue' });
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- Runs once immediately, then re-runs on any dep change
|
|
67
|
+
- Multi-key changes (e.g. a saved view applying 3 filters) debounce into one re-resolve per element
|
|
68
|
+
- `render` is your code - call `graphit.chart`, `graphit.table`, or hand-roll SVG/CSS
|
|
69
|
+
|
|
70
|
+
## Safe Parameter Binding (`:name` syntax)
|
|
71
|
+
|
|
72
|
+
Use `:name` placeholders in SQL for safe server-side parameter binding. Never string-concatenate user values into SQL.
|
|
73
|
+
|
|
74
|
+
| Shape | SQL | Params |
|
|
75
|
+
|-------|-----|--------|
|
|
76
|
+
| Scalar | `WHERE country = :country` | `{country: 'US'}` |
|
|
77
|
+
| Multi-select | `WHERE country IN :countries` | `{countries: ['US', 'IL']}` (expands to safe `IN ($0, $1)`) |
|
|
78
|
+
| Date range | `WHERE date BETWEEN :from AND :to` | `{from: '2026-01-01', to: '2026-06-01'}` |
|
|
79
|
+
|
|
80
|
+
Array length capped at 200 elements, max 50 param keys per resolve call.
|
|
81
|
+
|
|
82
|
+
## Saved Views
|
|
83
|
+
|
|
84
|
+
Users can save the current filter/parameter state as a named view and restore it later. The platform snapshots all registered `graphit.filter` and `graphit.param` values automatically. Views survive page reloads (state is baked into the iframe on every render). A default view auto-applies on dashboard open with no flash.
|
|
85
|
+
|
|
86
|
+
The subscribe callback on each handle restores the control's visual state when a view is applied - this is why every control must include a `subscribe(v => ...)` that updates its appearance.
|
|
87
|
+
|
|
88
|
+
## Complete Example
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<div style="margin-bottom: 16px;">
|
|
92
|
+
<label style="font-size: 12px; color: var(--graphit-fg-muted);">Region</label>
|
|
93
|
+
<select id="region-select" style="padding: 6px 12px; border: 1px solid var(--graphit-border); border-radius: 6px; background: var(--graphit-surface-raised); color: var(--graphit-fg);">
|
|
94
|
+
<option value="ALL">All Regions</option>
|
|
95
|
+
<option value="NA">North America</option>
|
|
96
|
+
<option value="EU">Europe</option>
|
|
97
|
+
<option value="APAC">Asia Pacific</option>
|
|
98
|
+
</select>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div id="revenue-by-region" data-graphit-id="revenue-by-region"
|
|
102
|
+
data-graphit-label="Revenue by Region"
|
|
103
|
+
data-graphit-sql="SELECT month, SUM(revenue) AS revenue FROM sales WHERE region = :region GROUP BY 1 ORDER BY 1"
|
|
104
|
+
data-graphit-ds="ds_sales">
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<script>
|
|
108
|
+
const region = graphit.filter('region', { label: 'Region', field: 'REGION', default: 'ALL' });
|
|
109
|
+
|
|
110
|
+
const sel = document.getElementById('region-select');
|
|
111
|
+
sel.value = region.get();
|
|
112
|
+
sel.onchange = () => region.set(sel.value);
|
|
113
|
+
region.subscribe(v => { sel.value = v; });
|
|
114
|
+
|
|
115
|
+
graphit.bind(document.getElementById('revenue-by-region'), {
|
|
116
|
+
sql: `SELECT month, SUM(revenue) AS revenue FROM sales
|
|
117
|
+
${region.get() !== 'ALL' ? 'WHERE region = :region' : ''}
|
|
118
|
+
GROUP BY 1 ORDER BY 1`,
|
|
119
|
+
dataSourceId: 'ds_sales',
|
|
120
|
+
params: () => region.get() !== 'ALL' ? { region: region.get() } : {},
|
|
121
|
+
deps: ['region'],
|
|
122
|
+
render: (result, el) => {
|
|
123
|
+
graphit.chart(el, { type: 'area', data: result.data, x: 'month', y: 'revenue', valueFormat: 'currency' });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
</script>
|
|
127
|
+
```
|
|
@@ -6,14 +6,52 @@ Every KB asset has full create / update / delete through the `graphit kb` comman
|
|
|
6
6
|
|
|
7
7
|
| Asset | Command |
|
|
8
8
|
|---|---|
|
|
9
|
-
| Metric | `graphit kb create metric --name X --sql "<expr>" --table T` (optional `--topics "A,B"`, `--default-dimensions "D1,D2"`) |
|
|
10
|
-
| Dimension | `graphit kb create dimension --name X --expr "<expr>" --table T` (type auto-inferred; override with `--type` / `--output-type`) |
|
|
11
|
-
| Rule | `graphit kb create rule --name X --sql "<text>" --table T` (optional `--apply-on table:USERS metric:ARPU`) |
|
|
9
|
+
| Metric | `graphit kb create metric --name X --sql "<expr>" --table T` (optional `--topics "A,B"`, `--default-dimensions "D1,D2"`, `--skip-validate`) |
|
|
10
|
+
| Dimension | `graphit kb create dimension --name X --expr "<expr>" --table T` (type auto-inferred; override with `--type` / `--output-type`, `--skip-validate`) |
|
|
11
|
+
| Rule | `graphit kb create rule --name X --sql "<text>" --table T` (optional `--apply-on table:USERS metric:ARPU`, `--skip-validate`) |
|
|
12
12
|
| Synonym | `graphit kb create synonym --term X --canonical Y --type metric` |
|
|
13
13
|
| Domain | `graphit kb create domain --name X` (optional `--color "#4DB6AC"`) |
|
|
14
14
|
| Topic | `graphit kb create topic --name X` |
|
|
15
15
|
| Relationship | `graphit kb create relationship --name X --primary-table T --primary-column C --related-table T2 --related-column C2` |
|
|
16
16
|
|
|
17
|
+
## Pre-Creation Validation
|
|
18
|
+
|
|
19
|
+
Metric, dimension, and rule creates validate the formula against real data before writing to Firestore. On success, the response includes sample results. On failure, creation is blocked with a 422 error showing the failing query.
|
|
20
|
+
|
|
21
|
+
- **Metric**: runs `SELECT {formula} FROM {table} GROUP BY {default_dims} LIMIT 5`
|
|
22
|
+
- **Dimension**: runs `SELECT {expr} AS val, COUNT(*) AS cnt FROM {table} GROUP BY 1 ORDER BY cnt DESC LIMIT 10` (reports cardinality, NULL rate)
|
|
23
|
+
- **Rule**: runs `SELECT COUNT(*) FROM {table} WHERE {rule}` (warns if zero rows match)
|
|
24
|
+
|
|
25
|
+
Skip conditions (validation returns "skipped", asset still created):
|
|
26
|
+
- Template metrics with `${PARAM:X}` placeholders
|
|
27
|
+
- Constraint-based rules (non-empty `--constraint`)
|
|
28
|
+
- Table has no data source and no Snowflake connections
|
|
29
|
+
- Data source mid-refresh or unverified
|
|
30
|
+
|
|
31
|
+
Use `--skip-validate` on any create command to bypass validation entirely (useful for batch creation where speed matters more than per-asset checks).
|
|
32
|
+
|
|
33
|
+
### Presenting validation results to the user
|
|
34
|
+
|
|
35
|
+
The JSON response from every metric/dimension/rule create includes a `validation` object. You MUST present it to the user after each create:
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
validation: {
|
|
39
|
+
status: "pass" | "fail" | "skipped",
|
|
40
|
+
sample_query: "SELECT ...", // the SQL that ran
|
|
41
|
+
sample_data: [{...}, ...], // rows from real data
|
|
42
|
+
sample_columns: ["col1", "col2"], // column names
|
|
43
|
+
warnings: ["..."], // quality warnings
|
|
44
|
+
skip_reason: "...", // why validation was skipped
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
How to present each status:
|
|
49
|
+
- **pass**: render `sample_data` as a markdown table using `sample_columns` as headers. For metrics, this shows computed values. For dimensions, this shows top values with row counts. For rules, this shows the matching row count. Surface any `warnings` below the table.
|
|
50
|
+
- **skipped**: tell the user validation was skipped and quote the `skip_reason`.
|
|
51
|
+
- **fail** (HTTP 422, create was blocked): show the error message and `sample_query`. The asset was NOT created. Fix the formula and retry.
|
|
52
|
+
|
|
53
|
+
Never silently swallow validation results. The user needs to see that their formula actually works against real data.
|
|
54
|
+
|
|
17
55
|
## Update and Delete
|
|
18
56
|
|
|
19
57
|
- Update a field: `graphit kb update <type> NAME --<field> value` (e.g. `--sql`, `--expr`, `--description`, `--table`).
|