@graphit/cli 0.2.372 → 0.2.379

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.
Files changed (58) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/bin/graphit +1 -1
  5. package/bin/graphit.ps1 +1 -1
  6. package/dist/commands/dashboard-delete.d.ts +43 -0
  7. package/dist/commands/dashboard-delete.js +66 -0
  8. package/dist/commands/dashboard-delete.js.map +1 -0
  9. package/dist/commands/dashboard.js +11 -19
  10. package/dist/commands/dashboard.js.map +1 -1
  11. package/dist/commands/ds/re-upload.d.ts +10 -0
  12. package/dist/commands/ds/re-upload.js +65 -0
  13. package/dist/commands/ds/re-upload.js.map +1 -0
  14. package/dist/commands/ds/render.js +21 -2
  15. package/dist/commands/ds/render.js.map +1 -1
  16. package/dist/commands/ds/types.d.ts +2 -0
  17. package/dist/commands/ds/types.js.map +1 -1
  18. package/dist/commands/ds/usage.d.ts +50 -0
  19. package/dist/commands/ds/usage.js +72 -0
  20. package/dist/commands/ds/usage.js.map +1 -0
  21. package/dist/commands/ds.js +31 -3
  22. package/dist/commands/ds.js.map +1 -1
  23. package/dist/commands/kb-batch.d.ts +29 -0
  24. package/dist/commands/kb-batch.js +93 -0
  25. package/dist/commands/kb-batch.js.map +1 -0
  26. package/dist/commands/kb.js +2 -0
  27. package/dist/commands/kb.js.map +1 -1
  28. package/dist/commands/report.d.ts +2 -0
  29. package/dist/commands/report.js +214 -0
  30. package/dist/commands/report.js.map +1 -0
  31. package/dist/index.js +3 -30
  32. package/dist/index.js.map +1 -1
  33. package/dist/output/format.d.ts +14 -0
  34. package/dist/output/format.js +33 -2
  35. package/dist/output/format.js.map +1 -1
  36. package/dist/program.d.ts +7 -0
  37. package/dist/program.js +43 -0
  38. package/dist/program.js.map +1 -0
  39. package/dist/skill-guard.js +5 -0
  40. package/dist/skill-guard.js.map +1 -1
  41. package/package.json +1 -1
  42. package/scripts/commander-walk.mjs +2 -2
  43. package/scripts/generate-tool-manifest.mjs +1 -1
  44. package/scripts/verb-policy-source.json +135 -3
  45. package/skills/graphit/SKILL.md +27 -8
  46. package/skills/graphit/VERSION.json +1 -1
  47. package/skills/graphit/references/build.md +4 -2
  48. package/skills/graphit/references/dashboard-create.md +1 -1
  49. package/skills/graphit/references/data-sources.md +2 -2
  50. package/skills/graphit/references/filters-advanced.md +9 -7
  51. package/skills/graphit/references/kb-actions.md +7 -0
  52. package/skills/graphit/references/onboarding.md +1 -1
  53. package/skills/graphit/references/query-contract.md +2 -2
  54. package/skills/graphit/references/scheduled-reports.md +22 -0
  55. package/skills/graphit/references/share.md +2 -2
  56. package/skills/graphit-build/SKILL.md +5 -3
  57. package/skills/graphit-explore/SKILL.md +1 -1
  58. package/skills/graphit-share/SKILL.md +3 -3
@@ -12,7 +12,7 @@
12
12
  "Fields per verb:",
13
13
  " surface both | cli_only | app_only - where the verb is callable",
14
14
  " is_read_only true when the verb cannot change stored state",
15
- " mutation_class none | kb | canvas | dashboard | data_source | governance | kb_config",
15
+ " mutation_class none | kb | canvas | dashboard | data_source | governance | kb_config | report",
16
16
  " (routes the validation-gateway pipeline and the loop guards)",
17
17
  " requires_approval true when the turn must show an approval card before executing",
18
18
  " silent_retry_exempt true when a failure must surface instead of being retried silently",
@@ -33,7 +33,8 @@
33
33
  "query": "Run SQL against a cached data source or a live warehouse, through the governance gateway",
34
34
  "metadata": "Warehouse metadata discovery - schemas, tables and columns",
35
35
  "governance": "Governance conformance and the audit log",
36
- "status": "The caller's effective permissions per domain"
36
+ "status": "The caller's effective permissions per domain",
37
+ "report": "Scheduled reports - a dashboard emailed or posted to Slack on a schedule, optionally with agent commentary"
37
38
  },
38
39
  "verbs": {
39
40
  "auth login": {
@@ -323,6 +324,14 @@
323
324
  "requires_approval": true,
324
325
  "silent_retry_exempt": false
325
326
  },
327
+ "kb batch": {
328
+ "surface": "both",
329
+ "noun": "kb_write",
330
+ "is_read_only": false,
331
+ "mutation_class": "kb",
332
+ "requires_approval": true,
333
+ "silent_retry_exempt": true
334
+ },
326
335
  "kb template list": {
327
336
  "surface": "both",
328
337
  "noun": "kb_read",
@@ -431,6 +440,13 @@
431
440
  "requires_approval": false,
432
441
  "silent_retry_exempt": false
433
442
  },
443
+ "ds usage": {
444
+ "surface": "both",
445
+ "is_read_only": true,
446
+ "mutation_class": "none",
447
+ "requires_approval": false,
448
+ "silent_retry_exempt": false
449
+ },
434
450
  "ds create": {
435
451
  "surface": "both",
436
452
  "is_read_only": false,
@@ -473,6 +489,14 @@
473
489
  "requires_approval": true,
474
490
  "silent_retry_exempt": true
475
491
  },
492
+ "ds re-upload": {
493
+ "surface": "cli_only",
494
+ "is_read_only": false,
495
+ "mutation_class": "data_source",
496
+ "requires_approval": true,
497
+ "silent_retry_exempt": true,
498
+ "reason": "It sends a local file's bytes, and the in-app agent has no filesystem - chat attachments reach it as extracted text, never as a file it could upload. In the app, a person re-uploads from the source's Re-upload file action in the Sources Hub."
499
+ },
476
500
  "ds delete": {
477
501
  "surface": "both",
478
502
  "is_read_only": false,
@@ -640,13 +664,121 @@
640
664
  "requires_approval": true,
641
665
  "silent_retry_exempt": true
642
666
  },
667
+ "dashboard delete-preview": {
668
+ "surface": "cli_only",
669
+ "is_read_only": true,
670
+ "mutation_class": "none",
671
+ "requires_approval": false,
672
+ "silent_retry_exempt": false,
673
+ "reason": "The in-app dashboard tool doc sits at its 2000-character ceiling, so the action waits on a tightening of that noun's summaries. In the app, `dashboard delete` with `delete_sources` checks the named ids on the server before the approval card, the card lists every data source that will be deleted, and the delete removes only those ids the server still offers."
674
+ },
675
+ "report list": {
676
+ "surface": "both",
677
+ "is_read_only": true,
678
+ "mutation_class": "none",
679
+ "requires_approval": false,
680
+ "silent_retry_exempt": false
681
+ },
682
+ "report destinations": {
683
+ "surface": "both",
684
+ "is_read_only": true,
685
+ "mutation_class": "none",
686
+ "requires_approval": false,
687
+ "silent_retry_exempt": false
688
+ },
689
+ "report get": {
690
+ "surface": "both",
691
+ "is_read_only": true,
692
+ "mutation_class": "none",
693
+ "requires_approval": false,
694
+ "silent_retry_exempt": false
695
+ },
696
+ "report runs": {
697
+ "surface": "both",
698
+ "is_read_only": true,
699
+ "mutation_class": "none",
700
+ "requires_approval": false,
701
+ "silent_retry_exempt": false
702
+ },
703
+ "report run": {
704
+ "surface": "both",
705
+ "is_read_only": true,
706
+ "mutation_class": "none",
707
+ "requires_approval": false,
708
+ "silent_retry_exempt": false
709
+ },
710
+ "report create": {
711
+ "surface": "both",
712
+ "is_read_only": false,
713
+ "mutation_class": "report",
714
+ "requires_approval": true,
715
+ "silent_retry_exempt": true,
716
+ "app_params": {
717
+ "state_json": {
718
+ "type": "string",
719
+ "required": false,
720
+ "description": "The full filter map as a JSON object string, e.g. {\"region\": [\"EU\"]}. filter entries override its keys. Prefer filter for a few keys.",
721
+ "reason": "The CLI reads the full map from a file (--state-file), which an in-app turn has no disk for, so the map rides the call. Same capability (set the report's filters), different mechanics."
722
+ }
723
+ }
724
+ },
725
+ "report update": {
726
+ "surface": "both",
727
+ "is_read_only": false,
728
+ "mutation_class": "report",
729
+ "requires_approval": true,
730
+ "silent_retry_exempt": true,
731
+ "app_params": {
732
+ "state_json": {
733
+ "type": "string",
734
+ "required": false,
735
+ "description": "The full filter map as a JSON object string, e.g. {\"region\": [\"EU\"]}. filter entries override its keys. Prefer filter for a few keys.",
736
+ "reason": "Same as report create: --state-file is a filesystem source an in-app turn does not have."
737
+ }
738
+ }
739
+ },
740
+ "report pause": {
741
+ "surface": "both",
742
+ "is_read_only": false,
743
+ "mutation_class": "report",
744
+ "requires_approval": true,
745
+ "silent_retry_exempt": true
746
+ },
747
+ "report resume": {
748
+ "surface": "both",
749
+ "is_read_only": false,
750
+ "mutation_class": "report",
751
+ "requires_approval": true,
752
+ "silent_retry_exempt": true
753
+ },
754
+ "report test": {
755
+ "surface": "both",
756
+ "is_read_only": false,
757
+ "mutation_class": "report",
758
+ "requires_approval": true,
759
+ "silent_retry_exempt": true
760
+ },
761
+ "report send": {
762
+ "surface": "both",
763
+ "is_read_only": false,
764
+ "mutation_class": "report",
765
+ "requires_approval": true,
766
+ "silent_retry_exempt": true
767
+ },
768
+ "report delete": {
769
+ "surface": "both",
770
+ "is_read_only": false,
771
+ "mutation_class": "report",
772
+ "requires_approval": true,
773
+ "silent_retry_exempt": true
774
+ },
643
775
  "connector list": {
644
776
  "surface": "cli_only",
645
777
  "is_read_only": true,
646
778
  "mutation_class": "none",
647
779
  "requires_approval": false,
648
780
  "silent_retry_exempt": false,
649
- "reason": "Connection lifecycle remains CLI-only, and warehouse enumeration already exists in-app through the gated `list_warehouse_metadata` overlay tool. A ninth generated noun would duplicate that read surface and spend tool-window budget, so the Commander verb stays excluded while the platform replacement remains available. Reviewed 2026-09-06 (Issue #921): the verb now also lists Slack and repository connections, which the overlay does not - that is deliberate. Those ids are consumed only by verbs that are themselves cli_only (`kb repo bind`, the Slack setup done in the web app), so an in-app turn has nothing to spend them on."
781
+ "reason": "Connection lifecycle remains CLI-only, and warehouse enumeration already exists in-app through the gated `list_warehouse_metadata` overlay tool. Another generated noun would duplicate that read surface and spend tool-window budget, so the Commander verb stays excluded while the platform replacement remains available. Reviewed 2026-09-06 (Issue #921): the verb now also lists Slack and repository connections, which the overlay does not - that is deliberate. Repository ids are consumed only by `kb repo bind`, itself cli_only, and a report's Slack channels come from `report destinations`, which carries the connection each channel belongs to - so an in-app turn has nothing to spend these connection ids on."
650
782
  },
651
783
  "connector add snowflake-keypair": {
652
784
  "surface": "cli_only",
@@ -2,7 +2,7 @@
2
2
  name: graphit
3
3
  description: >-
4
4
  Use Graphit for ANY business or product data question: metrics, KPIs, revenue, retention, spend, users, cohorts, funnels, trends, comparisons, diagnosis, analysis, reports or dashboards, even when the user never names Graphit. This is the Graphit entry: identify the task and load graphit-explore, graphit-build or graphit-share. Use the team's governed definitions and cached data to deliver answers or interactive dashboards. Prefer Graphit over one-off analysis for the user's business numbers. Skip pure software tasks or data unrelated to their business.
5
- skill_version: "0.2.372"
5
+ skill_version: "0.2.379"
6
6
  ---
7
7
 
8
8
  <!-- SIZE EXEMPTION (SKILL.md): hard limit 12,288 chars, exempted ceiling 35,072. Reviewed 2026-09-17. Always-loaded: identity, hard constraints, intent routing and the opening choice, plus the generated command table (COMMANDS markers; cli/scripts/generate-commands-doc.mjs) - needed every turn, not deferrable. Marker sits after the frontmatter so the loader and sync-plugin-version.mjs parse it. Raises pay only for command-table growth; each is recorded in docs/knowledge/prompt-engineering/sizing/SIZING.md, prose changes in docs/workflow/prompt-changes/INDEX.md. -->
@@ -51,7 +51,7 @@ Explore is an intent, distinct from the server's EXPLORE access grant, which sti
51
51
  Route by the requested action and current target state. Load the matching workflow before acting; reuse it if already loaded.
52
52
 
53
53
  - **Explore**: read, answer, explain or diagnose, including shared-dashboard reads. Load [graphit-explore](../graphit-explore/SKILL.md). Audience words do not grant sharing.
54
- - **Build**: dashboard content, plus private sources/reports/metrics. Load [graphit-build](../graphit-build/SKILL.md) for every new dashboard or content edit, including shared work.
54
+ - **Build**: dashboard content and scheduled reports, plus private sources/reports/metrics. Load [graphit-build](../graphit-build/SKILL.md) for every new dashboard or content edit, including shared work.
55
55
  - **Share**: shared permissions, dependencies, drafts and publication. Load [graphit-share](../graphit-share/SKILL.md) for shared writes; pair it with Build for dashboard authoring. Share establishes the allowed scope or draft before shared writes; Build alone grants none.
56
56
  - **Operational request**: refresh, inspect, export or another explicit operation follows its actual action reference and permission contract. Do not force a creation interview, infer a new audience or discard the active task for a status question.
57
57
 
@@ -115,6 +115,7 @@ Workflow rows below are generated in-app adapters; CLI hosts load the named work
115
115
  | a graph switches metric, horizon, grain or grouping; typed query inputs | query-contract.md |
116
116
  | reusing a chart across dashboards as a template, or expanding one on a host | templates.md |
117
117
  | building a slide deck | presentations.md |
118
+ | scheduling, changing, sending or troubleshooting a scheduled report (email/Slack delivery) | scheduled-reports.md |
118
119
  | moving an existing dashboard's queries onto its entities, or explaining a legacy-query save warning | migration.md |
119
120
  | checking a dashboard against the write contract without saving - pre-flighting an edit, or an alignment sweep | alignment.md |
120
121
  | CLI/plugin health, permission errors, local artifacts | operations.md |
@@ -124,7 +125,7 @@ Workflow rows below are generated in-app adapters; CLI hosts load the named work
124
125
 
125
126
  ## Commands
126
127
 
127
- Claude Code supplies the `graphit` wrapper. On Codex, Cursor, terminals and CI, use `npx -y @graphit/cli@0.2.372 <command>`; pin a version for reproducibility. The table is generated from the CLI; check command help for exact flags.
128
+ Claude Code supplies the `graphit` wrapper. On Codex, Cursor, terminals and CI, use `npx -y @graphit/cli@0.2.379 <command>`; pin a version for reproducibility. The table is generated from the CLI; check command help for exact flags.
128
129
 
129
130
  <!-- COMMANDS:START -->
130
131
 
@@ -153,6 +154,7 @@ _Generated by `npm run gen:commands`; do not hand-edit between the markers._
153
154
  - `kb repo token mint` - Mint a display-once CI machine token (org admin); scope kb:verify or kb:apply - `--scope`
154
155
  - `kb repo token list` - List CI machine tokens: metadata only, never the secret
155
156
  - `kb repo token revoke <token-id>` - Revoke a CI machine token (org admin)
157
+ - `kb batch` - Apply many metric and semantic-model creates and updates as one Knowledge Base change (up to 50 per batch; 20 in-app). Items: {op: create, noun, definition, unverified?} or {op: update, noun, name, patch}; each passes the same checks as kb create/kb update and reports its own result, and readers rebuild once for the whole batch instead of once per edit. Groups, rules and deletes use their own verbs - `--file --json --stop-on-error`
156
158
  - `kb template list` - List chart templates without their HTML
157
159
  - `kb template get <name>` - Fetch one chart template with its HTML. What expands in every adopting dashboard
158
160
  - `kb template create` - Create a chart template from an HTML fragment. A fragment may carry <script> and <style> and {{param}} placeholders in markup, never data-graphit-id/-sql/-ds/-label/-vocab/-state attributes: the host entity owns the query - `--name --file --json --description --params`
@@ -187,8 +189,10 @@ _Generated by `npm run gen:commands`; do not hand-edit between the markers._
187
189
 
188
190
  **ds** - Data source management
189
191
  - `ds refresh-history <id>` - Show recent refresh runs for a data source with the Snowflake query id per run (status, time, rows, duration). Runs from before query-id capture - or a failure before any query ran - show 'not captured'. Read-only; no ds refresh-history delete. - `--limit`
192
+ - `ds usage [id]` - Show which canvas dashboards and graphs read a data source. With an id: each dashboard you can open and its graphs, plus a count of graphs on dashboards you cannot open. Without an id: dashboard_count and graph_count for every source you can read (0 = no graph uses it). A graph counts when its data-graphit-ds names the source, its governed metrics or dimensions come from the source's semantic model, or its SQL reads the source by name. Graphs composed only in JavaScript are not seen. Read-only; ds delete still re-checks metrics and rules.
190
193
  - `ds move <id>` - Not a command anywhere: a source lives in its bound semantic model's group; kb update semantic-model moves it
191
194
  - `ds delete <id>` - Delete one of YOUR OWN private data sources (requires --yes). Shared sources are deleted in the Sources Hub, where the cascade is visible. - `--yes`
195
+ - `ds re-upload <id>` - Replace an uploaded CSV/Excel source's contents in place - keeps its id, graph bindings, semantic model and history; never re-create with `ds create --file`. A changed column set needs --force - `--file --force`
192
196
  - `ds list` - List data sources. Rows carry domain, created_at and created_by. Response carries count/total/truncated; below total = capped, raise --limit - `--limit`
193
197
  - `ds create` - Create from SQL or Excel/CSV. Completed publication and clean scan make the source ready and verified. --domain is REQUIRED: uppercase access-policy key, not a semantic group - `--sql --name --connection --schema --skip-scan --detect-tables --source-tables --file --domain --sheet`
194
198
  - `ds refresh [ids...]` - Refresh data sources (--all or IDs). Breaking drift with dependents pauses adoption; use ds verify --accept-schema to adopt the change - `--all --no-wait --skip-empty --force`
@@ -207,7 +211,7 @@ _Generated by `npm run gen:commands`; do not hand-edit between the markers._
207
211
  - `dashboard move <id>` - Move a dashboard within one space, or return it to root. This changes only navigation metadata and needs no canvas edit session. Its placement in other spaces, content and sharing stay unchanged. Use sharing operations separately to grant access. - `--space --team --revision --folder`
208
212
  - `dashboard list` - List custom dashboards. --view takes mine, shared, editable, all (default). mine is what you created and so own - exactly one owner per dashboard, so mine is how teammates split migration work with no overlap. editable adds dashboards others own that you can change. Every row carries permission owner/editor/viewer. - `--view --team`
209
213
  - `dashboard create` - Create a new custom dashboard - `--name`
210
- - `dashboard share <id>` - Share an owned dashboard. Org requires admin/owner; Team requires membership. An optional folder path shares and files atomically; invalid paths reject both. - `--space --team --folder-path`
214
+ - `dashboard share <id>` - Share a dashboard you own, or as an org admin/owner one you can see. Org admins/owners may share it into Org or a team they belong to. Org requires admin/owner; Team requires membership. An optional folder path shares and files atomically; invalid paths reject both. - `--space --team --folder-path`
211
215
  - `dashboard get <id>` - Get dashboard details - `--html`
212
216
  - `dashboard check <id>` - Check a dashboard against the canvas write contract without saving. No flags = audit the stored page's standing debt; --file/--stdin = dry-run a proposed document and report the exact save verdict, without burning a version. Exits 1 when a save would be refused. - `--file --stdin`
213
217
  - `dashboard update-html <id>` - Replace dashboard HTML content - `--file --stdin --label`
@@ -216,10 +220,25 @@ _Generated by `npm run gen:commands`; do not hand-edit between the markers._
216
220
  - `dashboard list-entities <id>` - List the entities on a dashboard (id, label, KB refs, data source)
217
221
  - `dashboard get-entity <id> <entityId>` - Get entity context. Includes label, SQL, KB refs, data source and HTML. Use --with-data to also execute the governed query and return resolved data inline - that envelope carries truncated (false = complete) and executed_row_count when capped. Use --image for a local PNG of the graph (as last viewed) to Read - `--with-data --max-rows --params --adhoc-reason --image --raw`
218
222
  - `dashboard export <id>` - Export dashboard as PNG or PDF - `--format --output`
219
- - `dashboard edit <id>` - Enter edit mode on a shared dashboard: catch the editing session + start a draft, then open it in your browser. Gated (409) if someone else is editing, (423) if locked, (403) if view-only. Private dashboards need no session - edit directly. - `--no-open`
220
- - `dashboard publish <id>` - Publish your draft edits on a shared dashboard (makes them live) and release the editing session
221
- - `dashboard release <id>` - Discard your unpublished draft edits on a shared dashboard and release the editing session (requires --yes) - `--yes`
222
- - `dashboard delete <id>` - Delete a custom dashboard (requires --yes) - `--yes`
223
+ - `dashboard edit <id>` - Enter edit mode on a shared dashboard: catch the editing session + start a draft. Then opens it in your browser. Gated (409) if someone else is editing, (423) if locked, (403) if view-only. Private dashboards need no session - edit directly. - `--no-open`
224
+ - `dashboard publish <id>` - Publish your draft edits on a shared dashboard and release the editing session. This makes them live.
225
+ - `dashboard release <id>` - Discard your unpublished draft edits on a shared dashboard and release the editing session. Requires --yes. - `--yes`
226
+ - `dashboard delete-preview <id>` - Preview a delete: the data sources only this dashboard uses. orphan_sources are your own private ones nothing else uses (ids for delete --delete-sources); kept_sources are the rest, each with its rule. Deletes nothing.
227
+ - `dashboard delete <id>` - Delete a custom dashboard. Requires --yes. Data sources are kept unless named in --delete-sources (see delete-preview). - `--yes --delete-sources`
228
+
229
+ **report** - Scheduled reports - a dashboard emailed or posted to Slack on a schedule, optionally with agent commentary
230
+ - `report list` - List scheduled reports you can see - `--dashboard`
231
+ - `report destinations` - Where reports can go: Slack channels the bot can post to, org members, and allowed email domains
232
+ - `report get <id>` - Show one report: schedule, destinations, filters, status
233
+ - `report create` - Schedule a dashboard as a report - needs at least one --email or --slack; you become its creator and it renders with your data access - `--dashboard --name --frequency --send-time --day-of-week --day-of-month --timezone --email --slack --subject --instructions --filter --state-file --skip-if-empty`
234
+ - `report update <id>` - Change a report - only the flags you pass change; recipients, Slack channels, instructions and filters are the creator's alone to change - `--name --frequency --send-time --day-of-week --day-of-month --timezone --email --slack --subject --instructions --filter --state-file --skip-if-empty --send-if-empty --clear-filters --clear-instructions`
235
+ - `report pause <id>` - Pause a report - no scheduled runs until resumed
236
+ - `report resume <id>` - Resume a paused report
237
+ - `report test <id>` - Send a test run to the report's creator only
238
+ - `report send <id>` - Send a report now to all its recipients and channels (requires --yes) - `--yes`
239
+ - `report delete <id>` - Delete a report and its schedule (requires --yes) - `--yes`
240
+ - `report runs <id>` - Recent runs of a report: status, deliveries, errors, commentary outcome - `--limit`
241
+ - `report run <id> <run-id>` - The agent commentary exchange behind one run (the report's creator only)
223
242
 
224
243
  **connector** - Connection management. OAuth and GitHub connections are set up in the Graphit web app.
225
244
  - `connector list` - List connections (Snowflake, BigQuery, Slack, GitHub/Bitbucket)
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "package": "@graphit/cli",
3
- "version": "0.2.372",
3
+ "version": "0.2.379",
4
4
  "source": "cli/package.json"
5
5
  }
@@ -18,7 +18,7 @@ Use a fitting cached source first and state the chosen source. If none exists, P
18
18
 
19
19
  The scan's bound semantic model supplies the semantic layer. Use its measures and dimensions, fitting existing metrics, and explicitly labeled ad-hoc SQL where needed; governance.md and sql-reference.md own query permissions and receipts. For private work, do not create a metric unless the user asks to keep it. Then read semantic-authoring.md and kb-scope.md: use the scanner model's exact private group and source binding, preserve siblings, and verify the result. A request to keep an already agreed definition authorizes that work; resolve only a new ambiguity in its meaning. No visible private group means stop before a private write, never omit the group and land in org commons. Shared definitions follow Share's agreed group and readiness checks; loading Build does not replace them.
20
20
 
21
- Change coverage, filters, columns or joins for the same source purpose with `ds edit-sql`; follow its drift response. A new name is not a repair for a failed edit. Re-upload file sources through their supported flow.
21
+ Change coverage, filters, columns or joins for the same source purpose with `ds edit-sql`; follow its drift response. A new name is not a repair for a failed edit. Update an uploaded file source in place with `graphit ds re-upload <id> --file <path>` (in the app, the person uses Re-upload file in the Sources Hub); never re-create it.
22
22
 
23
23
  When no source exists and the user asks for a sketch, mockup, wireframe or layout first, build a **layout preview** instead. Ask about this fork only when genuinely ambiguous; data first is the default.
24
24
 
@@ -32,6 +32,8 @@ When no source exists and the user asks for a sketch, mockup, wireframe or layou
32
32
 
33
33
  Build and show sections as they become useful; continue authorized work without an approval round per chart. Check the canvas, fix `entity_sql_warnings`, and verify rendering and real resolves before calling a data-backed dashboard complete. For a preview, verify layout and marker coverage and report it specifically as a preview.
34
34
 
35
- Without Share's established shared scope/draft, Build writes only privately. Shared authoring stays within that authorization; Share retains checks before shared dependency writes and publication. Private sources refresh manually, in full. A schedule or Slack/email delivery request needs Share for the source and its bound model; explain that and offer it if not already requested. The dashboard may remain private. A private report or export alone does not imply scheduled delivery or a visibility change.
35
+ Without Share's established shared scope/draft, Build writes only privately. Shared authoring stays within that authorization; Share retains checks before shared dependency writes and publication. Private sources refresh manually, in full. A schedule or Slack/email delivery request needs Share for the source and its bound model; explain that and offer it if not already requested, then schedule through scheduled-reports.md. The dashboard may remain private. A private report or export alone does not imply scheduled delivery or a visibility change.
36
36
 
37
37
  For Private first, end with the private link, verification and limitations, plus one offer to share; an offer grants no permission. When sharing/publication is already requested, continue the same artifact through Share's remaining checks and report its actual outcome. Do not repeat an answered choice; obtain approval for additional effects when required. A draft-only request stays a draft.
38
+
39
+ After completing a dashboard, or when the user asks for something recurring ("every Monday", "a weekly update", "send this to the team"), offer once per session to schedule it as a report; create one only after an explicit yes.
@@ -32,7 +32,7 @@ Example: a private retention dashboard is created in My Dashboards without a fol
32
32
  ## Build, share and file
33
33
 
34
34
  1. Create the dashboard privately with `dashboard create` and retain its returned ID. Build and verify the content following dashboard-planning.md and runtime.md. Do not share an unfinished dashboard.
35
- 2. Refresh the chosen directory after building. For Org or Team, use `dashboard share` on that same ID with the chosen space/team and `folder_path` (CLI flag `--folder-path`): a slash-separated existing path within that audience, or `/` for root. This single operation shares and files together. Org requires an org admin/owner who owns the dashboard; Team requires ownership and actual membership. The server re-resolves the exact path in its transaction, preserving the private-dependency sharing guard. Invalid, missing or inaccessible paths reject both changes; show the error and let the user correct the path. Never omit a rejected path and retry at root. No fuzzy matching or automatic folder creation. Omitting the path deliberately means share only and keep the existing placement.
35
+ 2. Refresh the chosen directory after building. For Org or Team, use `dashboard share` on that same ID with the chosen space/team and `folder_path` (CLI flag `--folder-path`): a slash-separated existing path within that audience, or `/` for root. This single operation shares and files together. Org requires an org admin/owner; Team requires actual membership. The server re-resolves the exact path in its transaction, preserving the private-dependency sharing guard. Invalid, missing or inaccessible paths reject both changes; show the error and let the user correct the path. Never omit a rejected path and retry at root. No fuzzy matching or automatic folder creation. Omitting the path deliberately means share only and keep the existing placement.
36
36
  3. My Dashboards needs no sharing: use `dashboard move` for a nested personal folder with the selected folder ID and freshly read revision. A new dashboard at root needs no move. A revision conflict requires a fresh read and reconsideration. Paths address the names that exist at commit time; they do not pin an earlier folder identity if a different folder later takes the same path.
37
37
  4. Verify the same ID through `dashboard list` for visibility/team_ids and through the destination's folder listing for placement. Follow pagination as needed. Return the dashboard link, full breadcrumb and actual audience only after those reads agree. Later content edits on a shared dashboard require the existing edit-session/draft flow.
38
38
 
@@ -51,7 +51,7 @@ A clean scan activates the source after its snapshot is published, for warehouse
51
51
 
52
52
  Creation and verification output report `pii_hidden` with reasons: these columns are masked as NULL in every query, including dashboards and exports. Surface those verdicts and the returned remedy. Use the server's `can_expose_verdict`, never a guessed role, to explain who can reverse a false positive. `ds verify <id> --expose COL1,COL2` explicitly unhides named columns; it also works on an already-verified source and reports `exposed` and `expose_failed`. Do not unhide a column without the user's choice.
53
53
 
54
- Edit in place with `ds edit-sql <id> --sql "..."` when changing columns, filters, joins, or date coverage for the same purpose - editing preserves the source id, graph bindings, semantic-model binding, schedules, and history. The new SQL is compiled against the warehouse before anything is saved. A breaking candidate with dependents pauses in `pending_verification` with the old data still serving; only explicit `ds verify --accept-schema` accepts it. A clean change without dependents can adopt automatically, as can an additive change. Report the returned state; a queued acceptance is not adoption. Generic force-refresh does not accept drift. `--expected-version` is optional and a stale value is refused without changing anything. File-upload sources cannot be edited by SQL - re-upload the file. Never version the same work as `_v2`, `_copy` or `_shared`, including after a refused edit. Create a separate source only for a different purpose or connection.
54
+ Edit in place with `ds edit-sql <id> --sql "..."` when changing columns, filters, joins, or date coverage for the same purpose - editing preserves the source id, graph bindings, semantic-model binding, schedules, and history. The new SQL is compiled against the warehouse before anything is saved. A breaking candidate with dependents pauses in `pending_verification` with the old data still serving; only explicit `ds verify --accept-schema` accepts it. A clean change without dependents can adopt automatically, as can an additive change. Report the returned state; a queued acceptance is not adoption. Generic force-refresh does not accept drift. `--expected-version` is optional and a stale value is refused without changing anything. File-upload sources cannot be edited by SQL. Replace an uploaded file's contents in place with `graphit ds re-upload <id> --file <path>`; in the app, the person uses Re-upload file on the source in the Sources Hub. Either keeps the id and every binding, while re-creating the source is refused on its name or orphans the old one. A changed column set is refused until the user accepts `--force`, which breaks graphs reading removed or renamed columns; a source still pending verification must be verified first. Never version the same work as `_v2`, `_copy` or `_shared`, including after a refused edit. Create a separate source only for a different purpose or connection.
55
55
 
56
56
  ## Zero Rows and Nulls
57
57
 
@@ -63,7 +63,7 @@ On an empty or suspiciously-null result: check the selected source and dialect,
63
63
  - Reading does not imply authority over connector, SQL, or refresh settings.
64
64
  - Visibility and masking cover agent, canvas, render, export, and report paths.
65
65
  - Private names and columns remain concealed.
66
- - Delete your own private sources with `graphit ds delete <id> --yes` only after the user confirms. Shared sources stay in the Sources Hub. A 409 names visible dependents to remove or rebind first; a 202 means deletion applied but storage cleanup is pending: report it and do not repeat the delete.
66
+ - Delete your own private sources with `graphit ds delete <id> --yes` only after the user confirms. Shared sources stay in the Sources Hub. `dashboard delete <id> --yes --delete-sources <ids>` also removes the named own private sources only that dashboard used (ids from `dashboard delete-preview`). A 409 names visible dependents to remove or rebind first; a 202 means deletion applied but storage cleanup is pending: report it and do not repeat the delete.
67
67
  - There is no source move on any surface. A source lives in the `group` of the semantic model bound to it, so `kb update semantic-model <name>` with a new `group` moves the source; a source with no bound model yet keeps the domain it was created with.
68
68
 
69
69
  For refresh modes, history, incremental tuning, and reconciliation, load `data-source-refresh.md`.
@@ -1,10 +1,10 @@
1
1
  # Advanced Filter Controls - Dependent Dropdowns and Date Presets
2
2
 
3
- Load only when you need one of two optional controls on top of the core filters: a dependent dropdown ("only relevant values" that narrows as an upstream filter changes) or a date-preset picker. The base filter, param, bind, wiring, `:name` binding, and saved-view mechanics live in `filters.md`. Both controls below are headless logic - you own all the markup.
3
+ Load only when you need an optional control on top of the core filters: a dependent dropdown, data-driven date bounds, a top-N list, or a date-preset picker. The base filter, param, bind, wiring, `:name` binding, and saved-view mechanics live in `filters.md`. Every control below is headless logic - you own all the markup.
4
4
 
5
5
  ## graphit.cascade(el, options) - Only Relevant Values
6
6
 
7
- Dependent dropdowns: fetch a column's DISTINCT values constrained by other filters, and refetch when they change. For example, pick an org and the user list shows only that org's users. Logic only - you build the checkboxes or list in `render`.
7
+ Dependent dropdowns: fetch a column's DISTINCT values constrained by other filters, and refetch when they change - pick an org and the user list shows only that org's users. You build the markup in `render`.
8
8
 
9
9
  ```js
10
10
  const org = graphit.filter('org', { label: 'Org' })
@@ -25,11 +25,12 @@ graphit.cascade('#user-list', {
25
25
  ```
26
26
 
27
27
  - `filters()` returns `{ COLUMN: value }`. A scalar makes `COLUMN = :p`; an array makes `COLUMN IN :p`. One contract everywhere: `null`, absent or `''` means ALL (no constraint), and `[]` means match NOTHING - an empty-array upstream settles the list empty without issuing a query.
28
+ - Objects: `{ exclude: [...] }` is NOT IN, keeping null rows unless `null` is listed; `{ start, end }` takes `dr.get()` as-is (a date-only `end` includes that day); `{ min, max }` is inclusive. Empty ones constrain nothing.
28
29
  - `selection` (a filter handle) is auto-pruned to the surviving values when an upstream changes. Name the control a cascade feeds - pass `selection`, or use the `column` that control declares in `data-graphit-field` - so report and saved-view editors can list and search these values.
29
- - Returns `{ destroy(), search(term) }`. Keep the result set small (default `LIMIT 1001`); these parameterized queries skip the result cache, so they hit DuckDB directly.
30
- - `withCounts: true` adds a per-value row count, delivered as `ctx.counts` alongside `values` (same order).
31
- - Type-ahead: call the handle's `search('ber')` to narrow server-side; it is debounced with the normal refetch and matches literally, so `100%` finds `100%`. Clearing it (`search('')`) restores the full list.
32
- - Faster for low-cardinality cascades: add `preload: true` to fetch the full distinct cross-product ONCE (cacheable, no params) and filter in-memory on every change - instant, zero per-change round-trips. Best when the column-by-upstream combinations are small (cap = `limit`, default 1001 tuples); above the cap it auto-falls-back to per-change server queries.
30
+ - Returns `{ destroy(), search(term) }`. Keep the result set small (default `LIMIT 1001`).
31
+ - `withCounts: true` adds a per-value row count, delivered as `ctx.counts` alongside `values` (same order). `orderBy: 'count'` returns the top `limit` by count instead - for high-cardinality columns; it never prunes `selection`.
32
+ - Type-ahead: call the handle's `search('ber')` to narrow server-side; it is debounced with the normal refetch and is a case-insensitive contains match with literal wildcards, so `100%` finds `100%`. Clearing it (`search('')`) restores the full list.
33
+ - For low-cardinality cascades, `preload: true` fetches the distinct cross-product ONCE and filters in memory on every change; above `limit` tuples (default 1001), or with an object filter, it queries per change.
33
34
 
34
35
  ## graphit.dataBounds(options) - A Column's Real Min/Max
35
36
 
@@ -43,6 +44,7 @@ input.max = b.max
43
44
 
44
45
  - Returns `{ min, max, dataMax, today }`. Use `max` as the picker ceiling: it is `max(dataMax, today)`, so a source lagging a few days never locks the user out of today. `dataMax` is the raw last row, for a "data through {dataMax}" caption.
45
46
  - Non-date columns return their true min/max with no ceiling applied.
47
+ - Optional `filters` (as in cascade, e.g. `{ IS_WEB: 0 }`) bound matching rows only.
46
48
 
47
49
  ## graphit.rank(options) - Top-N Values
48
50
 
@@ -57,7 +59,7 @@ const top = await graphit.rank({
57
59
  })
58
60
  ```
59
61
 
60
- - Returns a plain array of values. Prefer `{{ Metric('name') }}` so ranking uses the org's definition; a bare aggregate accepts SUM, COUNT, AVG, MIN, or MAX over one column.
62
+ - Returns a plain array of values; `withScores: true` returns `{ values, scores }` (score = the `by` value). Prefer `{{ Metric('name') }}` so ranking uses the org's definition; a bare aggregate accepts SUM, COUNT, AVG, MIN, or MAX over one column.
61
63
 
62
64
  ## graphit.dateRange(id, options) - Date Presets
63
65
 
@@ -39,6 +39,13 @@ Constraints keep their five semantics: required predicate, forbidden column, req
39
39
  5. Verify/unverify separately when intended.
40
40
  6. Inspect receipts; a degraded write may have landed and must not be retried blindly.
41
41
 
42
+ When one task creates or changes several metrics or semantic models, send them as one `graphit kb batch` instead of one `kb create` or `kb update` each. Every item gets the same checks and its own result, and dashboards rebuild once for the whole batch instead of once per edit, so they keep serving while you author. A single edit stays `kb update`. Steps 1-2 still apply to every item; a batch changes the transport, not the patch discipline.
43
+
44
+ - Shape: `{"operations": [...]}` or a bare array of `{"op": "update", "noun", "name", "patch"}` and `{"op": "create", "noun", "definition", "unverified"?}` items. Nouns are `metric` and `semantic-model` only; groups, rules and deletes keep their own verbs. Up to 50 items per batch, 20 in-app.
45
+ - Order items so each validates against the ones before it: a semantic model before the metrics that use its measures, a metric before a derived metric over it. Use `--stop-on-error` when later items depend on earlier ones.
46
+ - Items are not all-or-nothing: earlier items stay applied when a later one fails. Read `results` per item, fix what each `error` names, and re-send only the `failed` and `not_attempted` items as a new batch. Never replay the whole batch. An `unknown` item may have landed; read it back with `kb get` before sending it again.
47
+ - In-app, approving the batch verifies each updated item, as approving a single update does.
48
+
42
49
  ## Delete
43
50
 
44
51
  Confirm with the user and inspect usage first. The server checks known definition dependencies, not every canvas reference. A green guard is not exhaustive impact proof.
@@ -67,7 +67,7 @@ Ask whether the user wants a quick query answer or a deployed HTML dashboard. Bu
67
67
  After the first dashboard is deployed, tell the user - concisely - what they get for free on it. Keep this to the first dashboard; it never needs repeating, because onboarding stops firing once the workspace has data.
68
68
 
69
69
  - **Each graph's 3-dot (hamburger) menu**: "view details" opens a panel with the SQL, live query results, and the trust tier plus any enforced rules (the KB assets it lists open as explorable tabs).
70
- - **The dashboard's own hamburger** (top bar): share it, schedule a recurring email report, export to PNG or PDF, and browse version history.
70
+ - **The dashboard's own hamburger** (top bar): share it, schedule a recurring email or Slack report (or ask Graphit to schedule it), export to PNG or PDF, and browse version history.
71
71
  - **Themes and colors** are automatic - dark and light mode, and the brand palette, with no extra work.
72
72
 
73
73
  Then continue in the normal loop; the workspace is no longer empty.
@@ -15,7 +15,7 @@ Keep the default SQL in `data-graphit-sql` and source in `data-graphit-ds`. Add
15
15
  </div>
16
16
  ```
17
17
 
18
- These are invented names; use actual accessible sources/columns and governed Metric/Dimension/Measure references where available. A variant contains only `sql` and inherits the owner's source. Cross-source alternatives need separate owners. The spec has no second default SQL, source override or variant named `default`. Unknown fields, versions, duplicate JSON keys, malformed types, undeclared placeholders and the names `__proto__`, `constructor` and `prototype` refuse the save; the refusal names the owner, and the parameter or variant when one is at fault. Save the declaration before selecting it; the backend re-reads the stored owner the page shows (the editor's draft while the page shows it). Local DOM edits are not a new stored query authority.
18
+ These are invented names; use actual accessible sources/columns and governed Metric/Dimension/Measure references where available. A variant contains only `sql` and inherits the owner's source. Cross-source alternatives need separate owners. The spec has no second default SQL, source override or variant named `default`. Unknown fields, versions, duplicate JSON keys, malformed types, undeclared placeholders and the names `__proto__`, `constructor` and `prototype` refuse the save; the refusal names the owner, and the parameter or variant when one is at fault. Save the declaration so the save rule validates it. The SDK reads the specification from the page, picks the default or named statement and sends it as that entity's query; the server authorizes and governs it like any other query.
19
19
 
20
20
  ```js
21
21
  const result = await graphit.resolve({
@@ -32,7 +32,7 @@ Omit `variant` to select the default. Do not combine `variant` with explicit `sq
32
32
 
33
33
  **One name, one declaration.** A parameter name is one input: every owner that declares `country` declares it identically, so one control's value is valid everywhere it is sent. While authoring, keep one type table per dashboard and copy into each owner's static specification exactly the placeholders its default and variant statements use; an unused declaration refuses the save. Never build specifications in page JavaScript. When owners disagree, the shared check/save path returns a non-blocking `query_param_type_conflict` warning naming the parameter and its declarations; align them, or rename inputs that genuinely differ, and save again.
34
34
 
35
- Dates/as-of, search text, returned top-category arrays and cohort labels are bound values. Keep their parameter names stable across state changes; do not turn a category label into a SQL identifier. Metric/group/grain/horizon changes select authored statements, not SQL fragments passed as values. Send every binding the selected statement uses; bindings removed by the existing integer sentinel simplifier may be omitted. Declared values the selected statement does not use are ignored, so one params object can serve all of that owner's variants; a name that owner does not declare refuses.
35
+ Dates/as-of, search text, returned top-category arrays and cohort labels are bound values. Keep their parameter names stable across state changes; do not turn a category label into a SQL identifier. Metric/group/grain/horizon changes select authored statements, not SQL fragments passed as values. Send every binding the selected statement uses; bindings removed by the existing integer sentinel simplifier may be omitted. Values the selected statement does not use are ignored, so one params object can serve all of that owner's variants.
36
36
 
37
37
  Preserve the dashboard's authored All/None/include/exclude behavior. An authored empty selection that means All stays distinct from None; do not globally translate every empty list or null. Use explicit mode values such as an enum when appropriate. The existing integer `all_x` sentinel contract remains in `filters.md`.
38
38
 
@@ -0,0 +1,22 @@
1
+ # Scheduled Reports
2
+
3
+ Load before creating, changing, sending or troubleshooting a scheduled report: a dashboard emailed or posted to Slack on a schedule, optionally with agent commentary. A report delivers an existing dashboard, so build or pick the dashboard first. Delivery from a private source still needs Share for the source and its bound model.
4
+
5
+ ## Before creating
6
+
7
+ - Before `report create`, check `report list --dashboard <id>` and update an existing report instead of creating a second.
8
+ - Resolve destinations with `report destinations`: the Slack channels the bot can post to, the org's members (name and email) and its allowed email domains. Map the user's words ("#growth", "Dana") to those entries; an address outside members and allowed domains is refused.
9
+ - Add only recipients and channels the user named. Confirm destinations, schedule and timezone in one line before `report create`; never widen delivery on your own.
10
+ - A report and its commentary render with the creator's data access - yours when you create it. Say so when the recipients differ from who can open the dashboard.
11
+
12
+ ## Creating and changing
13
+
14
+ - `report create` needs `--dashboard`, `--name`, `--frequency`, `--send-time` and at least one `--email` or `--slack`. Weekly takes `--day-of-week` (mon..sun), monthly `--day-of-month` (1-28); `--timezone` is IANA and defaults to UTC, so pass the user's.
15
+ - `--filter key=value` sets a dashboard filter by its declared state key (state-contract.md): `a,b` for several values, `start..end` for a date range. `--instructions` adds agent commentary to every run.
16
+ - `report update` changes only the flags passed. `--email`, `--slack`, `--filter` and `--state-file` REPLACE the stored value: read it with `report get` and send the full intended list or map. `--clear-filters` / `--clear-instructions` remove them.
17
+ - Recipients, channels, instructions and filters are the creator's alone to change; pausing, rescheduling, sending, testing and deleting need the creator, a dashboard editor or an org admin. Report a refusal as that rule, not a fault.
18
+
19
+ ## Sending and checking
20
+
21
+ - `report test` goes to the creator only; use it to check a render. `report send` goes to every recipient now: only when the user asks.
22
+ - `report runs` shows each run's status, deliveries, error and commentary outcome; `report run <id> <run-id>` shows the commentary exchange (creator only). Report partial or failed delivery as it is: a run is not a delivery.
@@ -12,7 +12,7 @@ For "publish", inspect the dashboard state and follow dashboard-create.md's publ
12
12
  |---|---|
13
13
  | a. Share a private dashboard | Resolve its private dependency closure, then share and file the same dashboard ID. |
14
14
  | b. Share definitions | Reuse or move the selected models/metrics into the agreed group; a bound source follows its model. |
15
- | c. Schedule or deliver from a private source | Plan the source and bound model's move to a shared group before configuring the requested schedule/report. The dashboard may stay private. |
15
+ | c. Schedule or deliver from a private source | Plan the source and bound model's move to a shared group before scheduling per scheduled-reports.md. The dashboard may stay private. |
16
16
  | d. Author directly in a group | "Shared from the start": apply checks before each shared source/definition write. Build authors the new private dashboard; share it when complete. Keep the agreed scope. |
17
17
  | e. Repository-owned work | Apply the same decisions through repo-kb.md's repository/PR workflow on a capable surface. An in-app ownership refusal is a handoff, not permission for a direct-write replacement. |
18
18
 
@@ -24,7 +24,7 @@ Read kb-scope.md for effective permissions and exact placement, kb-discovery.md
24
24
 
25
25
  **KB-readiness gate:** before work goes live for others, confirm the required models, nested components, metrics, groups and rules exist and have the needed verification. If a business measure is missing, present its gap and proposed governed definition for approval, then author and verify the approved prerequisites. An ad-hoc business measure can be unavailable to governed-only viewers; do not silently publish it as a reusable governed answer. Compare actual binding, grain, time dimension, aggregation, filters, units and policy, not just names or SQL. A same-named conflicting asset is not equivalent: explain the difference and resolve the consequential choice. A truly equivalent accessible asset should be reused.
26
26
 
27
- Choose dashboard audience and folder through dashboard-create.md when sharing. Org sharing requires the dashboard owner to be an org admin/owner; team sharing requires ownership and actual membership. When needed, explain Private/ORG/named scopes via kb-scope.md; keep dashboard audience separate.
27
+ Choose dashboard audience and folder through dashboard-create.md when sharing. Owners share their own; org admins/owners also any they can see. Org needs admin/owner; Team needs membership. When needed, explain Private/ORG/named scopes via kb-scope.md; keep dashboard audience separate.
28
28
 
29
29
  Before any share or publish, inspect the dashboard for `data-graphit-placeholder` markers. Refuse while any remain and offer "wire it" through build.md. Do not remove markers simply to make sharing pass; real resolves must replace the placeholders.
30
30
 
@@ -2,7 +2,7 @@
2
2
  name: graphit-build
3
3
  description: >-
4
4
  Author and verify Graphit dashboard content, private or shared, and build private reports, sources and saved metrics. Pair with graphit-share for shared dependencies, draft sessions and publication. Use graphit-explore for answers without artifacts.
5
- skill_version: "0.2.372"
5
+ skill_version: "0.2.379"
6
6
  ---
7
7
 
8
8
  # Build: author and verify content
@@ -45,7 +45,7 @@ Use a fitting cached source first and state the chosen source. If none exists, P
45
45
 
46
46
  The scan's bound semantic model supplies the semantic layer. Use its measures and dimensions, fitting existing metrics, and explicitly labeled ad-hoc SQL where needed; ../graphit/references/governance.md and ../graphit/references/sql-reference.md own query permissions and receipts. For private work, do not create a metric unless the user asks to keep it. Then read ../graphit/references/semantic-authoring.md and ../graphit/references/kb-scope.md: use the scanner model's exact private group and source binding, preserve siblings, and verify the result. A request to keep an already agreed definition authorizes that work; resolve only a new ambiguity in its meaning. No visible private group means stop before a private write, never omit the group and land in org commons. Shared definitions follow Share's agreed group and readiness checks; loading Build does not replace them.
47
47
 
48
- Change coverage, filters, columns or joins for the same source purpose with `ds edit-sql`; follow its drift response. A new name is not a repair for a failed edit. Re-upload file sources through their supported flow.
48
+ Change coverage, filters, columns or joins for the same source purpose with `ds edit-sql`; follow its drift response. A new name is not a repair for a failed edit. Update an uploaded file source in place with `graphit ds re-upload <id> --file <path>` (in the app, the person uses Re-upload file in the Sources Hub); never re-create it.
49
49
 
50
50
  When no source exists and the user asks for a sketch, mockup, wireframe or layout first, build a **layout preview** instead. Ask about this fork only when genuinely ambiguous; data first is the default.
51
51
 
@@ -59,8 +59,10 @@ When no source exists and the user asks for a sketch, mockup, wireframe or layou
59
59
 
60
60
  Build and show sections as they become useful; continue authorized work without an approval round per chart. Check the canvas, fix `entity_sql_warnings`, and verify rendering and real resolves before calling a data-backed dashboard complete. For a preview, verify layout and marker coverage and report it specifically as a preview.
61
61
 
62
- Without Share's established shared scope/draft, Build writes only privately. Shared authoring stays within that authorization; Share retains checks before shared dependency writes and publication. Private sources refresh manually, in full. A schedule or Slack/email delivery request needs Share for the source and its bound model; explain that and offer it if not already requested. The dashboard may remain private. A private report or export alone does not imply scheduled delivery or a visibility change.
62
+ Without Share's established shared scope/draft, Build writes only privately. Shared authoring stays within that authorization; Share retains checks before shared dependency writes and publication. Private sources refresh manually, in full. A schedule or Slack/email delivery request needs Share for the source and its bound model; explain that and offer it if not already requested, then schedule through ../graphit/references/scheduled-reports.md. The dashboard may remain private. A private report or export alone does not imply scheduled delivery or a visibility change.
63
63
 
64
64
  For Private first, end with the private link, verification and limitations, plus one offer to share; an offer grants no permission. When sharing/publication is already requested, continue the same artifact through Share's remaining checks and report its actual outcome. Do not repeat an answered choice; obtain approval for additional effects when required. A draft-only request stays a draft.
65
65
 
66
+ After completing a dashboard, or when the user asks for something recurring ("every Monday", "a weekly update", "send this to the team"), offer once per session to schedule it as a report; create one only after an explicit yes.
67
+
66
68
  <!-- WORKFLOW:END -->
@@ -2,7 +2,7 @@
2
2
  name: graphit-explore
3
3
  description: >-
4
4
  Answer, explain or diagnose business data using Graphit. Use after Graphit routing or for a direct Graphit question, including reads of shared dashboards. Does not authorize creating reusable definitions or sharing; use graphit-build to keep a private artifact and graphit-share for shared writes.
5
- skill_version: "0.2.372"
5
+ skill_version: "0.2.379"
6
6
  ---
7
7
 
8
8
  # Explore: answer the question
@@ -2,7 +2,7 @@
2
2
  name: graphit-share
3
3
  description: >-
4
4
  Share or publish Graphit work, edit shared Graphit dashboards, or author into a shared group. Use after Graphit routing or a direct Graphit shared-scope request. Pair with graphit-build for dashboard authoring. Read-only questions belong to graphit-explore.
5
- skill_version: "0.2.372"
5
+ skill_version: "0.2.379"
6
6
  ---
7
7
 
8
8
  # Share: checks at the shared write
@@ -39,7 +39,7 @@ For "publish", inspect the dashboard state and follow ../graphit/references/dash
39
39
  |---|---|
40
40
  | a. Share a private dashboard | Resolve its private dependency closure, then share and file the same dashboard ID. |
41
41
  | b. Share definitions | Reuse or move the selected models/metrics into the agreed group; a bound source follows its model. |
42
- | c. Schedule or deliver from a private source | Plan the source and bound model's move to a shared group before configuring the requested schedule/report. The dashboard may stay private. |
42
+ | c. Schedule or deliver from a private source | Plan the source and bound model's move to a shared group before scheduling per ../graphit/references/scheduled-reports.md. The dashboard may stay private. |
43
43
  | d. Author directly in a group | "Shared from the start": apply checks before each shared source/definition write. Build authors the new private dashboard; share it when complete. Keep the agreed scope. |
44
44
  | e. Repository-owned work | Apply the same decisions through ../graphit/references/repo-kb.md's repository/PR workflow on a capable surface. An in-app ownership refusal is a handoff, not permission for a direct-write replacement. |
45
45
 
@@ -51,7 +51,7 @@ Read ../graphit/references/kb-scope.md for effective permissions and exact place
51
51
 
52
52
  **KB-readiness gate:** before work goes live for others, confirm the required models, nested components, metrics, groups and rules exist and have the needed verification. If a business measure is missing, present its gap and proposed governed definition for approval, then author and verify the approved prerequisites. An ad-hoc business measure can be unavailable to governed-only viewers; do not silently publish it as a reusable governed answer. Compare actual binding, grain, time dimension, aggregation, filters, units and policy, not just names or SQL. A same-named conflicting asset is not equivalent: explain the difference and resolve the consequential choice. A truly equivalent accessible asset should be reused.
53
53
 
54
- Choose dashboard audience and folder through ../graphit/references/dashboard-create.md when sharing. Org sharing requires the dashboard owner to be an org admin/owner; team sharing requires ownership and actual membership. When needed, explain Private/ORG/named scopes via ../graphit/references/kb-scope.md; keep dashboard audience separate.
54
+ Choose dashboard audience and folder through ../graphit/references/dashboard-create.md when sharing. Owners share their own; org admins/owners also any they can see. Org needs admin/owner; Team needs membership. When needed, explain Private/ORG/named scopes via ../graphit/references/kb-scope.md; keep dashboard audience separate.
55
55
 
56
56
  Before any share or publish, inspect the dashboard for `data-graphit-placeholder` markers. Refuse while any remain and offer "wire it" through [graphit-build](../graphit-build/SKILL.md). Do not remove markers simply to make sharing pass; real resolves must replace the placeholders.
57
57